Skip to content

Commit 7dcd41d

Browse files
committed
Replace socket.io with SockJS as discussed in #229
This removes the node-gyp dependency :). Fixes #229, #276, fixes #195, fixes #267, fixes #258 and fixes #242
1 parent 24b356e commit 7dcd41d

File tree

4 files changed

+152
-139
lines changed

4 files changed

+152
-139
lines changed

client/index.js

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var url = require('url');
2-
var io = require("socket.io-client");
2+
var SockJS = require("sockjs-client");
33
var stripAnsi = require('strip-ansi');
44
var scriptElements = document.getElementsByTagName("script");
55

@@ -8,70 +8,42 @@ var urlParts = url.parse(typeof __resourceQuery === "string" && __resourceQuery
88
scriptElements[scriptElements.length-1].getAttribute("src").replace(/\/[^\/]+$/, "")
99
);
1010

11-
io = io.connect(
12-
url.format({
11+
var recInterval = null;
12+
var sock = null;
13+
14+
var newConnection = function() {
15+
sock = new SockJS(url.format({
1316
protocol: urlParts.protocol,
1417
auth: urlParts.auth,
1518
hostname: (urlParts.hostname === '0.0.0.0') ? window.location.hostname : urlParts.hostname,
16-
port: urlParts.port
17-
}), {
18-
path: urlParts.path === '/' ? null : urlParts.path
19-
}
20-
);
21-
22-
var hot = false;
23-
var initial = true;
24-
var currentHash = "";
19+
port: urlParts.port,
20+
pathname: urlParts.path === '/' ? "/sockjs-node" : urlParts.path
21+
}));
2522

26-
io.on("hot", function() {
27-
hot = true;
28-
console.log("[WDS] Hot Module Replacement enabled.");
29-
});
23+
clearInterval(recInterval);
3024

31-
io.on("invalid", function() {
32-
console.log("[WDS] App updated. Recompiling...");
33-
});
25+
sock.onclose = function() {
26+
console.error("[WDS] Disconnected!");
3427

35-
io.on("hash", function(hash) {
36-
currentHash = hash;
37-
});
28+
// Try to reconnect.
29+
sock = null;
30+
recInterval = setInterval(function () {
31+
newConnection();
32+
}, 2000);
33+
};
3834

39-
io.on("still-ok", function() {
40-
console.log("[WDS] Nothing changed.")
41-
});
35+
sock.onmessage = function(e) {
36+
// This assumes that all data sent via the websocket is JSON.
37+
var msg = JSON.parse(e.data);
38+
onSocketMsg[msg.type](msg.data);
39+
};
40+
};
4241

43-
io.on("ok", function() {
44-
if(initial) return initial = false;
45-
reloadApp();
46-
});
42+
newConnection();
4743

48-
io.on("warnings", function(warnings) {
49-
console.log("[WDS] Warnings while compiling.");
50-
for(var i = 0; i < warnings.length; i++)
51-
console.warn(stripAnsi(warnings[i]));
52-
if(initial) return initial = false;
53-
reloadApp();
54-
});
55-
56-
io.on("errors", function(errors) {
57-
console.log("[WDS] Errors while compiling.");
58-
for(var i = 0; i < errors.length; i++)
59-
console.error(stripAnsi(errors[i]));
60-
if(initial) return initial = false;
61-
reloadApp();
62-
});
63-
64-
io.on("proxy-error", function(errors) {
65-
console.log("[WDS] Proxy error.");
66-
for(var i = 0; i < errors.length; i++)
67-
console.error(stripAnsi(errors[i]));
68-
if(initial) return initial = false;
69-
reloadApp();
70-
});
71-
72-
io.on("disconnect", function() {
73-
console.error("[WDS] Disconnected!");
74-
});
44+
var hot = false;
45+
var initial = true;
46+
var currentHash = "";
7547

7648
function reloadApp() {
7749
if(hot) {

client/live.js

Lines changed: 87 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,108 @@
11
var $ = require("jquery");
2-
var io = require("socket.io-client");
2+
var SockJS = require("sockjs-client");
33
var stripAnsi = require('strip-ansi');
44
require("./style.css");
55

6+
var recInterval = null;
7+
var sock = null;
8+
var hot = false;
9+
var currentHash = "";
10+
11+
var newConnection = function(handlers) {
12+
sock = new SockJS('/sockjs-node');
13+
14+
clearInterval(recInterval);
15+
16+
sock.onclose = function() {
17+
handlers.close();
18+
19+
// Try to reconnect.
20+
sock = null;
21+
recInterval = setInterval(function () {
22+
newConnection(handlers);
23+
}, 2000);
24+
};
25+
26+
sock.onopen = function() {
27+
// This callback also fires on a reconnect.
28+
handlers.ok();
29+
};
30+
31+
sock.onmessage = function(e) {
32+
// This assumes that all data sent via the websocket is JSON.
33+
var msg = JSON.parse(e.data);
34+
handlers[msg.type](msg.data);
35+
};
36+
};
37+
638
$(function() {
739
var body = $("body").html(require("./page.jade")());
840
var status = $("#status");
941
var okness = $("#okness");
1042
var $errors = $("#errors");
1143
var iframe = $("#iframe");
1244
var header = $(".header");
13-
var hot = false;
14-
var currentHash = "";
1545

1646
var contentPage = window.location.pathname.substr("/webpack-dev-server".length) + window.location.search;
1747

18-
status.text("Connecting to socket.io server...");
48+
status.text("Connecting to sockjs server...");
1949
$errors.hide(); iframe.hide();
2050
header.css({borderColor: "#96b5b4"});
21-
io = io.connect();
2251

23-
io.on("hot", function() {
24-
hot = true;
25-
iframe.attr("src", contentPage + window.location.hash);
26-
});
27-
28-
io.on("invalid", function() {
29-
okness.text("");
30-
status.text("App updated. Recompiling...");
31-
header.css({borderColor: "#96b5b4"});
32-
$errors.hide(); if(!hot) iframe.hide();
33-
});
34-
35-
io.on("hash", function(hash) {
36-
currentHash = hash;
37-
});
38-
39-
io.on("still-ok", function() {
40-
okness.text("");
41-
status.text("App ready.");
42-
header.css({borderColor: ""});
43-
$errors.hide(); if(!hot) iframe.show();
44-
});
45-
46-
io.on("ok", function() {
47-
okness.text("");
48-
$errors.hide();
49-
reloadApp();
50-
});
51-
52-
io.on("warnings", function(warnings) {
53-
okness.text("Warnings while compiling.");
54-
$errors.hide();
55-
reloadApp();
56-
});
57-
58-
io.on("errors", function(errors) {
59-
status.text("App updated with errors. No reload!");
60-
okness.text("Errors while compiling.");
61-
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
62-
header.css({borderColor: "#ebcb8b"});
63-
$errors.show(); iframe.hide();
64-
});
65-
66-
io.on("proxy-error", function(errors) {
67-
status.text("Could not proxy to content base target!");
68-
okness.text("Proxy error.");
69-
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
70-
header.css({borderColor: "#ebcb8b"});
71-
$errors.show(); iframe.hide();
72-
});
52+
var onSocketMsg = {
53+
hot: function() {
54+
hot = true;
55+
iframe.attr("src", contentPage + window.location.hash);
56+
},
57+
invalid: function() {
58+
okness.text("");
59+
status.text("App updated. Recompiling...");
60+
header.css({borderColor: "#96b5b4"});
61+
$errors.hide(); if(!hot) iframe.hide();
62+
},
63+
hash: function(hash) {
64+
currentHash = hash;
65+
},
66+
"still-ok": function() {
67+
okness.text("");
68+
status.text("App ready.");
69+
header.css({borderColor: ""});
70+
$errors.hide(); if(!hot) iframe.show();
71+
},
72+
ok: function() {
73+
okness.text("");
74+
$errors.hide();
75+
reloadApp();
76+
},
77+
warnings: function(warnings) {
78+
okness.text("Warnings while compiling.");
79+
$errors.hide();
80+
reloadApp();
81+
},
82+
errors: function(errors) {
83+
status.text("App updated with errors. No reload!");
84+
okness.text("Errors while compiling.");
85+
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
86+
header.css({borderColor: "#ebcb8b"});
87+
$errors.show(); iframe.hide();
88+
},
89+
"proxy-error": function(errors) {
90+
status.text("Could not proxy to content base target!");
91+
okness.text("Proxy error.");
92+
$errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n");
93+
header.css({borderColor: "#ebcb8b"});
94+
$errors.show(); iframe.hide();
95+
},
96+
close: function() {
97+
status.text("");
98+
okness.text("Disconnected.");
99+
$errors.text("\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n");
100+
header.css({borderColor: "#ebcb8b"});
101+
$errors.show(); iframe.hide();
102+
}
103+
};
73104

74-
io.on("disconnect", function() {
75-
status.text("");
76-
okness.text("Disconnected.");
77-
$errors.text("\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n");
78-
header.css({borderColor: "#ebcb8b"});
79-
$errors.show(); iframe.hide();
80-
});
105+
newConnection(onSocketMsg);
81106

82107
iframe.load(function() {
83108
status.text("App ready.");

lib/Server.js

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var path = require("path");
33
var webpackDevMiddleware = require("webpack-dev-middleware");
44
var express = require("express");
55
var compress = require("compression");
6-
var socketio = require("socket.io");
6+
var sockjs = require("sockjs");
77
var StreamCache = require("stream-cache");
88
var http = require("http");
99
var https = require("https");
@@ -23,15 +23,20 @@ function Server(compiler, options) {
2323
this.hot = options.hot;
2424
this.headers = options.headers;
2525

26+
this.sockWrite = function(type, data) {
27+
this.sock.write(JSON.stringify({type: type, data: data}));
28+
}
29+
2630
// Listening for events
2731
var invalidPlugin = function() {
28-
if(this.io) this.io.sockets.emit("invalid");
32+
if(this.sock) this.sockWrite("invalid");
2933
}.bind(this);
3034
compiler.plugin("compile", invalidPlugin);
3135
compiler.plugin("invalid", invalidPlugin);
3236
compiler.plugin("done", function(stats) {
33-
if(!this.io) return;
34-
this._sendStats(this.io.sockets, stats.toJson());
37+
if(!this.sock) return;
38+
39+
this._sendStats(stats.toJson());
3540
this._stats = stats;
3641
}.bind(this));
3742

@@ -146,7 +151,7 @@ function Server(compiler, options) {
146151
}
147152
proxy.web(req, res, proxyOptions, function(err){
148153
var msg = "cannot proxy to " + proxyOptions.target + " (" + err.message + ")";
149-
this.io.sockets.emit("proxy-error", [msg]);
154+
this.sockWrite("proxy-error", [msg]);
150155
res.statusCode = 502;
151156
res.end();
152157
}.bind(this));
@@ -177,7 +182,7 @@ function Server(compiler, options) {
177182
app.all("*", function(req, res) {
178183
proxy.web(req, res, contentBase, function(err) {
179184
var msg = "cannot proxy to " + contentBase.target + " (" + err.message + ")";
180-
this.io.sockets.emit("proxy-error", [msg]);
185+
this.sockWrite("proxy-error", [msg]);
181186
res.statusCode = 502;
182187
res.end();
183188
}.bind(this));
@@ -264,21 +269,32 @@ Server.prototype.setContentHeaders = function(req, res, next) {
264269
next();
265270
}
266271

267-
// delegate listen call and init socket.io
272+
// delegate listen call and init sockjs
268273
Server.prototype.listen = function() {
269274
this.listeningApp.listen.apply(this.listeningApp, arguments);
270-
this.io = socketio.listen(this.listeningApp, {
271-
"log level": 1
275+
var sockServer = sockjs.createServer({
276+
// Limit useless logs
277+
log: function(severity, line) {
278+
if (severity === 'error') {
279+
console.log(line);
280+
}
281+
}
272282
});
273-
this.io.sockets.on("connection", function(socket) {
274-
if(this.hot) socket.emit("hot");
283+
sockServer.on("connection", function(conn) {
284+
this.sock = conn;
285+
if(this.hot) this.sockWrite("hot");
275286
if(!this._stats) return;
276-
this._sendStats(socket, this._stats.toJson(), true);
287+
this._sendStats(this._stats.toJson(), true);
277288
}.bind(this));
289+
290+
sockServer.installHandlers(this.listeningApp, {
291+
prefix: '/sockjs-node'
292+
});
278293
}
279294

280295
Server.prototype.close = function() {
281-
this.io.close(); // Will also close listeningApp
296+
this.sock.close(); // Will also close listeningApp
297+
this.sock = null;
282298
this.middleware.close();
283299
}
284300

@@ -297,17 +313,17 @@ Server.prototype.serveMagicHtml = function(req, res, next) {
297313
}
298314

299315
// send stats to a socket or multiple sockets
300-
Server.prototype._sendStats = function(socket, stats, force) {
316+
Server.prototype._sendStats = function(stats, force) {
301317
if(!force && stats && (!stats.errors || stats.errors.length === 0) && stats.assets && stats.assets.every(function(asset) {
302318
return !asset.emitted;
303-
})) return socket.emit("still-ok");
304-
socket.emit("hash", stats.hash);
319+
})) return this.sockWrite("still-ok");
320+
this.sockWrite("hash", stats.hash);
305321
if(stats.errors.length > 0)
306-
socket.emit("errors", stats.errors);
322+
this.sockWrite("errors", stats.errors);
307323
else if(stats.warnings.length > 0)
308-
socket.emit("warnings", stats.warnings);
324+
this.sockWrite("warnings", stats.warnings);
309325
else
310-
socket.emit("ok");
326+
this.sockWrite("ok");
311327
}
312328

313329
Server.prototype.invalidate = function() {

0 commit comments

Comments
 (0)