Skip to content

Commit 2f8c680

Browse files
committed
Backport #579 and #589
1 parent 78927e1 commit 2f8c680

File tree

6 files changed

+137
-85
lines changed

6 files changed

+137
-85
lines changed

bin/webpack-dev-server.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ var optimist = require("optimist")
4545

4646
.boolean("history-api-fallback").describe("history-api-fallback", "Fallback to /index.html for Single Page Applications.")
4747

48+
.string("client-log-level").describe("client-log-level", "Log level in the browser (info, warning, error or none)").default("client-log-level", "info")
49+
4850
.boolean("compress").describe("compress", "enable gzip compression")
4951

5052
.boolean("open").describe("open", "Open default browser")
@@ -156,6 +158,9 @@ if(argv["inline"])
156158
if(argv["history-api-fallback"])
157159
options.historyApiFallback = true;
158160

161+
if(argv["client-log-level"])
162+
options.clientLogLevel = argv["client-log-level"];
163+
159164
if(argv["compress"])
160165
options.compress = true;
161166

client/index.js

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var url = require('url');
2-
var SockJS = require("sockjs-client");
32
var stripAnsi = require('strip-ansi');
3+
var socket = require('./socket');
44

55
function getCurrentScriptSource() {
66
// `document.currentScript` is the most accurate way to find the current script,
@@ -16,10 +16,9 @@ function getCurrentScriptSource() {
1616
throw new Error("[WDS] Failed to get current script source");
1717
}
1818

19-
// If this bundle is inlined, use the resource query to get the correct url.
20-
// Else, get the url from the <script> this file was called with.
2119
var urlParts;
22-
if (typeof __resourceQuery === "string" && __resourceQuery) {
20+
if(typeof __resourceQuery === "string" && __resourceQuery) {
21+
// If this bundle is inlined, use the resource query to get the correct url.
2322
urlParts = url.parse(__resourceQuery.substr(1));
2423
} else {
2524
// Else, get the url from the <script> this file was called with.
@@ -28,54 +27,70 @@ if (typeof __resourceQuery === "string" && __resourceQuery) {
2827
urlParts = url.parse((scriptHost ? scriptHost : "/"), false, true);
2928
}
3029

31-
var sock = null;
3230
var hot = false;
3331
var initial = true;
3432
var currentHash = "";
33+
var logLevel = "info";
34+
35+
function log(level, msg) {
36+
if(logLevel === "info" && level === "info")
37+
return console.log(msg);
38+
if(["info", "warning"].indexOf(logLevel) >= 0 && level === "warning")
39+
return console.warn(msg);
40+
if(["info", "warning", "error"].indexOf(logLevel) >= 0 && level === "error")
41+
return console.error(msg);
42+
}
3543

3644
var onSocketMsg = {
3745
hot: function() {
3846
hot = true;
39-
console.log("[WDS] Hot Module Replacement enabled.");
47+
log("info", "[WDS] Hot Module Replacement enabled.");
4048
},
4149
invalid: function() {
42-
console.log("[WDS] App updated. Recompiling...");
50+
log("info", "[WDS] App updated. Recompiling...");
4351
},
4452
hash: function(hash) {
4553
currentHash = hash;
4654
},
4755
"still-ok": function() {
48-
console.log("[WDS] Nothing changed.")
56+
log("info", "[WDS] Nothing changed.")
57+
},
58+
"log-level": function(level) {
59+
logLevel = level;
4960
},
5061
ok: function() {
5162
if(initial) return initial = false;
5263
reloadApp();
5364
},
5465
warnings: function(warnings) {
55-
console.log("[WDS] Warnings while compiling.");
66+
log("info", "[WDS] Warnings while compiling.");
5667
for(var i = 0; i < warnings.length; i++)
5768
console.warn(stripAnsi(warnings[i]));
5869
if(initial) return initial = false;
5970
reloadApp();
6071
},
6172
errors: function(errors) {
62-
console.log("[WDS] Errors while compiling.");
73+
log("info", "[WDS] Errors while compiling.");
6374
for(var i = 0; i < errors.length; i++)
6475
console.error(stripAnsi(errors[i]));
6576
if(initial) return initial = false;
6677
reloadApp();
6778
},
6879
"proxy-error": function(errors) {
69-
console.log("[WDS] Proxy error.");
80+
log("info", "[WDS] Proxy error.");
7081
for(var i = 0; i < errors.length; i++)
71-
console.error(stripAnsi(errors[i]));
82+
log("error", stripAnsi(errors[i]));
7283
if(initial) return initial = false;
84+
},
85+
close: function() {
86+
log("error", "[WDS] Disconnected!");
7387
}
7488
};
7589

76-
7790
var hostname = urlParts.hostname;
78-
if(!urlParts.hostname || urlParts.hostname === '0.0.0.0') {
91+
var protocol = urlParts.protocol;
92+
93+
if(urlParts.hostname === '0.0.0.0') {
7994
// why do we need this check?
8095
// hostname n/a for file protocol (example, when using electron, ionic)
8196
// see: https://github.com/webpack/webpack-dev-server/pull/384
@@ -84,44 +99,30 @@ if(!urlParts.hostname || urlParts.hostname === '0.0.0.0') {
8499
}
85100
}
86101

87-
var port = (!urlParts.port || urlParts.port === '0') ? window.location.port : urlParts.port;
88-
89-
var formattedUrl = url.format({
90-
protocol: (window.location.protocol === "https:" || urlParts.hostname === '0.0.0.0') ? window.location.protocol : urlParts.protocol,
91-
auth: urlParts.auth,
92-
hostname: hostname,
93-
port: port,
94-
pathname: urlParts.path == null || urlParts.path === '/' ? "/sockjs-node" : urlParts.path
95-
});
96-
97-
var newConnection = function() {
98-
sock = new SockJS(formattedUrl);
99-
100-
sock.onclose = function() {
101-
console.error("[WDS] Disconnected!");
102-
103-
// Try to reconnect.
104-
sock = null;
105-
setTimeout(function() {
106-
newConnection();
107-
}, 2000);
108-
};
102+
// `hostname` can be empty when the script path is relative. In that case, specifying
103+
// a protocol would result in an invalid URL.
104+
// When https is used in the app, secure websockets are always necessary
105+
// because the browser doesn't accept non-secure websockets.
106+
if(hostname && (window.location.protocol === "https:" || urlParts.hostname === '0.0.0.0')) {
107+
protocol = window.location.protocol;
108+
}
109109

110-
sock.onmessage = function(e) {
111-
// This assumes that all data sent via the websocket is JSON.
112-
var msg = JSON.parse(e.data);
113-
onSocketMsg[msg.type](msg.data);
114-
};
115-
};
110+
var socketUrl = url.format({
111+
protocol: protocol,
112+
auth: urlParts.auth,
113+
hostname: hostname,
114+
port: (urlParts.port === '0') ? window.location.port : urlParts.port,
115+
pathname: urlParts.path == null || urlParts.path === '/' ? "/sockjs-node" : urlParts.path
116+
});
116117

117-
newConnection();
118+
socket(socketUrl, onSocketMsg);
118119

119120
function reloadApp() {
120121
if(hot) {
121-
console.log("[WDS] App hot update...");
122+
log("info", "[WDS] App hot update...");
122123
window.postMessage("webpackHotUpdate" + currentHash, "*");
123124
} else {
124-
console.log("[WDS] App updated. Reloading...");
125+
log("info", "[WDS] App updated. Reloading...");
125126
window.location.reload();
126127
}
127128
}

client/live.js

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,13 @@
11
var $ = require("jquery");
2-
var SockJS = require("sockjs-client");
32
var stripAnsi = require('strip-ansi');
3+
var socket = require('./socket');
44
require("./style.css");
55

6-
var sock = null;
76
var hot = false;
87
var currentHash = "";
98

10-
var newConnection = function(handlers) {
11-
sock = new SockJS('/sockjs-node');
12-
13-
sock.onclose = function() {
14-
handlers.close();
15-
16-
// Try to reconnect.
17-
sock = null;
18-
setTimeout(function() {
19-
newConnection(handlers);
20-
}, 2000);
21-
};
22-
23-
sock.onmessage = function(e) {
24-
// This assumes that all data sent via the websocket is JSON.
25-
var msg = JSON.parse(e.data);
26-
handlers[msg.type](msg.data);
27-
};
28-
};
29-
309
$(function() {
31-
var body = $("body").html(require("./page.jade")());
10+
$("body").html(require("./page.jade")());
3211
var status = $("#status");
3312
var okness = $("#okness");
3413
var $errors = $("#errors");
@@ -38,8 +17,11 @@ $(function() {
3817
var contentPage = window.location.pathname.substr("/webpack-dev-server".length) + window.location.search;
3918

4019
status.text("Connecting to sockjs server...");
41-
$errors.hide(); iframe.hide();
42-
header.css({borderColor: "#96b5b4"});
20+
$errors.hide();
21+
iframe.hide();
22+
header.css({
23+
borderColor: "#96b5b4"
24+
});
4325

4426
var onSocketMsg = {
4527
hot: function() {
@@ -49,24 +31,30 @@ $(function() {
4931
invalid: function() {
5032
okness.text("");
5133
status.text("App updated. Recompiling...");
52-
header.css({borderColor: "#96b5b4"});
53-
$errors.hide(); if(!hot) iframe.hide();
34+
header.css({
35+
borderColor: "#96b5b4"
36+
});
37+
$errors.hide();
38+
if(!hot) iframe.hide();
5439
},
5540
hash: function(hash) {
5641
currentHash = hash;
5742
},
5843
"still-ok": function() {
5944
okness.text("");
6045
status.text("App ready.");
61-
header.css({borderColor: ""});
62-
$errors.hide(); if(!hot) iframe.show();
46+
header.css({
47+
borderColor: ""
48+
});
49+
$errors.hide();
50+
if(!hot) iframe.show();
6351
},
6452
ok: function() {
6553
okness.text("");
6654
$errors.hide();
6755
reloadApp();
6856
},
69-
warnings: function(warnings) {
57+
warnings: function() {
7058
okness.text("Warnings while compiling.");
7159
$errors.hide();
7260
reloadApp();
@@ -75,30 +63,41 @@ $(function() {
7563
status.text("App updated with errors. No reload!");
7664
okness.text("Errors while compiling.");
7765
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
78-
header.css({borderColor: "#ebcb8b"});
79-
$errors.show(); iframe.hide();
66+
header.css({
67+
borderColor: "#ebcb8b"
68+
});
69+
$errors.show();
70+
iframe.hide();
8071
},
8172
"proxy-error": function(errors) {
8273
status.text("Could not proxy to content base target!");
8374
okness.text("Proxy error.");
8475
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
85-
header.css({borderColor: "#ebcb8b"});
86-
$errors.show(); iframe.hide();
76+
header.css({
77+
borderColor: "#ebcb8b"
78+
});
79+
$errors.show();
80+
iframe.hide();
8781
},
8882
close: function() {
8983
status.text("");
9084
okness.text("Disconnected.");
9185
$errors.text("\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n");
92-
header.css({borderColor: "#ebcb8b"});
93-
$errors.show(); iframe.hide();
86+
header.css({
87+
borderColor: "#ebcb8b"
88+
});
89+
$errors.show();
90+
iframe.hide();
9491
}
9592
};
9693

97-
newConnection(onSocketMsg);
94+
socket("/sockjs-node", onSocketMsg);
9895

9996
iframe.load(function() {
10097
status.text("App ready.");
101-
header.css({borderColor: ""});
98+
header.css({
99+
borderColor: ""
100+
});
102101
iframe.show();
103102
});
104103

@@ -113,7 +112,9 @@ $(function() {
113112
iframe.show();
114113
} else {
115114
status.text("App updated. Reloading app...");
116-
header.css({borderColor: "#96b5b4"});
115+
header.css({
116+
borderColor: "#96b5b4"
117+
});
117118
try {
118119
var old = iframe[0].contentWindow.location + "";
119120
if(old.indexOf("about") == 0) old = null;

client/socket.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
var SockJS = require("sockjs-client");
2+
3+
var retries = 0;
4+
var sock = null;
5+
6+
function socket(url, handlers) {
7+
sock = new SockJS(url);
8+
9+
sock.onopen = function() {
10+
retries = 0;
11+
}
12+
13+
sock.onclose = function() {
14+
if(retries === 0)
15+
handlers.close();
16+
17+
// Try to reconnect.
18+
sock = null;
19+
20+
// After 10 retries stop trying, to prevent logspam.
21+
if(retries <= 10) {
22+
// Exponentially increase timeout to reconnect.
23+
// Respectfully copied from the package `got`.
24+
var retryInMs = 1000 * Math.pow(2, retries) + Math.random() * 100;
25+
retries += 1;
26+
27+
setTimeout(function() {
28+
socket(url, handlers);
29+
}, retryInMs);
30+
}
31+
};
32+
33+
sock.onmessage = function(e) {
34+
// This assumes that all data sent via the websocket is JSON.
35+
var msg = JSON.parse(e.data);
36+
if(handlers[msg.type])
37+
handlers[msg.type](msg.data);
38+
};
39+
}
40+
41+
module.exports = socket;

lib/Server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function Server(compiler, options) {
2121

2222
this.hot = options.hot;
2323
this.headers = options.headers;
24+
this.clientLogLevel = options.clientLogLevel;
2425
this.sockets = [];
2526

2627
// Listening for events
@@ -339,6 +340,9 @@ Server.prototype.listen = function() {
339340
}.bind(this));
340341

341342
if(this.hot) this.sockWrite([conn], "hot");
343+
344+
if(this.clientLogLevel)
345+
this.sockWrite([conn], "log-level", this.clientLogLevel);
342346
if(!this._stats) return;
343347
this._sendStats([conn], this._stats.toJson(), true);
344348
}.bind(this));

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
],
5353
"scripts": {
5454
"prepublish": "webpack ./client/live.js client/live.bundle.js --colors --config client/webpack.config.js -p && webpack ./client/index.js client/index.bundle.js --colors --config client/webpack.config.js -p",
55-
"lint": "eslint bin lib test client/{index,live,webpack.config}.js",
55+
"lint": "eslint bin lib test client/{index,live,socket,webpack.config}.js",
5656
"beautify-lint": "beautify-lint lib/**.js bin/**.js",
5757
"beautify": "beautify-rewrite lib/**.js bin/**.js",
5858
"travis": "npm run lint && npm run beautify-lint && node lib/Server.js"

0 commit comments

Comments
 (0)