UNPKG

3.97 kBJavaScriptView Raw
1var sysPath = require('path');
2var fs = require('fs');
3var https = require('https');
4var WebSocketServer = require('ws').Server;
5var isWorker = require('cluster').isWorker;
6var isCss = function(file) {
7 return sysPath.extname(file.path) === '.css';
8};
9var startingPort = 9485;
10
11function AutoReloader(config) {
12 if (config == null) config = {};
13 this.config = config;
14 if (config.autoReload) {
15 throw new Error('Warning: config.autoReload is no longer supported, please move it to config.plugins.autoReload');
16 }
17 var plugins = config.plugins || {};
18 var cfg = plugins.autoReload || {};
19 var ports = [];
20
21 if (cfg.port == null) {
22 for (var i = 0; i < 11; i++) ports.push(startingPort + i);
23 } else {
24 ports = Array.isArray(cfg.port) ? cfg.port.slice() : [cfg.port];
25 }
26
27 if (this.config.persistent) {
28 this.enabled = (cfg.enabled == null) ? true : cfg.enabled;
29 }
30 this.delay = cfg.delay;
31
32 var conns = this.connections = [];
33 var host = cfg.host || '0.0.0.0';
34 var port = this.port = ports.shift();
35
36 var key, cert;
37 if (cfg.keyPath && cfg.certPath) {
38 this.ssl = true;
39 key = fs.readFileSync(cfg.keyPath);
40 cert = fs.readFileSync(cfg.certPath);
41 if (key && cert) {
42 this.httpsServer = https.createServer({key: key, cert: cert}).listen(port, host);
43 }
44 }
45
46 var startServer = (function() {
47 this.port = port;
48 var args = this.httpsServer ? {server: this.httpsServer} : {host: host, port: port}
49 var server = this.server = new WebSocketServer(args);
50 server.on('connection', function(conn) {
51 conns.push(conn);
52 conn.on('close', function() {
53 conns.splice(conn, 1);
54 });
55 });
56 server.on('error', function(error) {
57 if (error.toString().match(/EADDRINUSE/)) {
58 if (ports.length) {
59 port = ports.shift();
60 startServer();
61 } else {
62 error = "cannot start because port " + port + " is in use";
63 }
64 }
65 // console.error("AutoReload " + error);
66 });
67 }).bind(this);
68
69 if (this.enabled && !isWorker) startServer();
70}
71
72AutoReloader.prototype.brunchPlugin = true;
73AutoReloader.prototype.type = 'javascript';
74AutoReloader.prototype.extension = 'js';
75
76AutoReloader.prototype.onCompile = function(changedFiles) {
77 var enabled = this.enabled;
78 var conns = this.connections;
79 if (!enabled) return;
80
81 var didCompile = changedFiles.length > 0;
82 var allCss = didCompile && changedFiles.every(isCss);
83
84 if (toString.call(enabled) === '[object Object]') {
85 if (!(didCompile || enabled.assets)) return;
86 if (allCss) {
87 if (!enabled.css) return;
88 } else if (didCompile) {
89 var changedExts = changedFiles.map(function(_) {
90 return sysPath.extname(_.path).slice(1);
91 });
92 var wasChanged = !Object.keys(enabled).some(function(_) {
93 return enabled[_] && changedExts.indexOf(_) !== -1;
94 });
95 if (wasChanged) return;
96 }
97 }
98
99 var message = allCss ? 'stylesheet' : 'page';
100 var sendMessage = function() {
101 conns
102 .filter(function(connection) {
103 return connection.readyState === 1;
104 })
105 .forEach(function(connection) {
106 return connection.send(message);
107 });
108 };
109
110 this.delay ? setTimeout(sendMessage, this.delay) : sendMessage();
111};
112
113var fileName = 'auto-reload.js';
114AutoReloader.prototype.include = function() {
115 return this.enabled ?
116 [sysPath.join(__dirname, 'vendor', fileName)] : [];
117};
118
119AutoReloader.prototype.teardown = function() {
120 if (this.server) this.server.close();
121 if (this.httpsServer) this.httpsServer.close();
122};
123
124AutoReloader.prototype.compile = function(params, callback) {
125 if (this.enabled &&
126 this.port !== startingPort &&
127 sysPath.basename(params.path) === fileName) {
128 params.data = params.data.replace(startingPort, this.port);
129 }
130 if (this.enabled && this.ssl) {
131 params.data = params.data.replace('ws://', 'wss://');
132 }
133 return callback(null, params);
134};
135
136module.exports = AutoReloader