diff --git a/client/index.js b/client/index.js index 3c205da669..0fed6f20ba 100644 --- a/client/index.js +++ b/client/index.js @@ -1,5 +1,5 @@ var url = require('url'); -var io = require("socket.io-client"); +var SockJS = require("sockjs-client"); var stripAnsi = require('strip-ansi'); var scriptElements = document.getElementsByTagName("script"); @@ -8,70 +8,42 @@ var urlParts = url.parse(typeof __resourceQuery === "string" && __resourceQuery scriptElements[scriptElements.length-1].getAttribute("src").replace(/\/[^\/]+$/, "") ); -io = io.connect( - url.format({ +var recInterval = null; +var sock = null; + +var newConnection = function() { + sock = new SockJS(url.format({ protocol: urlParts.protocol, auth: urlParts.auth, hostname: (urlParts.hostname === '0.0.0.0') ? window.location.hostname : urlParts.hostname, - port: urlParts.port - }), { - path: urlParts.path === '/' ? null : urlParts.path - } -); - -var hot = false; -var initial = true; -var currentHash = ""; + port: urlParts.port, + pathname: urlParts.path === '/' ? "/sockjs-node" : urlParts.path + })); -io.on("hot", function() { - hot = true; - console.log("[WDS] Hot Module Replacement enabled."); -}); + clearInterval(recInterval); -io.on("invalid", function() { - console.log("[WDS] App updated. Recompiling..."); -}); + sock.onclose = function() { + console.error("[WDS] Disconnected!"); -io.on("hash", function(hash) { - currentHash = hash; -}); + // Try to reconnect. + sock = null; + recInterval = setInterval(function () { + newConnection(); + }, 2000); + }; -io.on("still-ok", function() { - console.log("[WDS] Nothing changed.") -}); + sock.onmessage = function(e) { + // This assumes that all data sent via the websocket is JSON. + var msg = JSON.parse(e.data); + onSocketMsg[msg.type](msg.data); + }; +}; -io.on("ok", function() { - if(initial) return initial = false; - reloadApp(); -}); +newConnection(); -io.on("warnings", function(warnings) { - console.log("[WDS] Warnings while compiling."); - for(var i = 0; i < warnings.length; i++) - console.warn(stripAnsi(warnings[i])); - if(initial) return initial = false; - reloadApp(); -}); - -io.on("errors", function(errors) { - console.log("[WDS] Errors while compiling."); - for(var i = 0; i < errors.length; i++) - console.error(stripAnsi(errors[i])); - if(initial) return initial = false; - reloadApp(); -}); - -io.on("proxy-error", function(errors) { - console.log("[WDS] Proxy error."); - for(var i = 0; i < errors.length; i++) - console.error(stripAnsi(errors[i])); - if(initial) return initial = false; - reloadApp(); -}); - -io.on("disconnect", function() { - console.error("[WDS] Disconnected!"); -}); +var hot = false; +var initial = true; +var currentHash = ""; function reloadApp() { if(hot) { diff --git a/client/live.js b/client/live.js index 46bd9d7493..ecda94ba65 100644 --- a/client/live.js +++ b/client/live.js @@ -1,8 +1,40 @@ var $ = require("jquery"); -var io = require("socket.io-client"); +var SockJS = require("sockjs-client"); var stripAnsi = require('strip-ansi'); require("./style.css"); +var recInterval = null; +var sock = null; +var hot = false; +var currentHash = ""; + +var newConnection = function(handlers) { + sock = new SockJS('/sockjs-node'); + + clearInterval(recInterval); + + sock.onclose = function() { + handlers.close(); + + // Try to reconnect. + sock = null; + recInterval = setInterval(function () { + newConnection(handlers); + }, 2000); + }; + + sock.onopen = function() { + // This callback also fires on a reconnect. + handlers.ok(); + }; + + sock.onmessage = function(e) { + // This assumes that all data sent via the websocket is JSON. + var msg = JSON.parse(e.data); + handlers[msg.type](msg.data); + }; +}; + $(function() { var body = $("body").html(require("./page.jade")()); var status = $("#status"); @@ -10,74 +42,67 @@ $(function() { var $errors = $("#errors"); var iframe = $("#iframe"); var header = $(".header"); - var hot = false; - var currentHash = ""; var contentPage = window.location.pathname.substr("/webpack-dev-server".length) + window.location.search; - status.text("Connecting to socket.io server..."); + status.text("Connecting to sockjs server..."); $errors.hide(); iframe.hide(); header.css({borderColor: "#96b5b4"}); - io = io.connect(); - io.on("hot", function() { - hot = true; - iframe.attr("src", contentPage + window.location.hash); - }); - - io.on("invalid", function() { - okness.text(""); - status.text("App updated. Recompiling..."); - header.css({borderColor: "#96b5b4"}); - $errors.hide(); if(!hot) iframe.hide(); - }); - - io.on("hash", function(hash) { - currentHash = hash; - }); - - io.on("still-ok", function() { - okness.text(""); - status.text("App ready."); - header.css({borderColor: ""}); - $errors.hide(); if(!hot) iframe.show(); - }); - - io.on("ok", function() { - okness.text(""); - $errors.hide(); - reloadApp(); - }); - - io.on("warnings", function(warnings) { - okness.text("Warnings while compiling."); - $errors.hide(); - reloadApp(); - }); - - io.on("errors", function(errors) { - status.text("App updated with errors. No reload!"); - okness.text("Errors while compiling."); - $errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n"); - header.css({borderColor: "#ebcb8b"}); - $errors.show(); iframe.hide(); - }); - - io.on("proxy-error", function(errors) { - status.text("Could not proxy to content base target!"); - okness.text("Proxy error."); - $errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n"); - header.css({borderColor: "#ebcb8b"}); - $errors.show(); iframe.hide(); - }); + var onSocketMsg = { + hot: function() { + hot = true; + iframe.attr("src", contentPage + window.location.hash); + }, + invalid: function() { + okness.text(""); + status.text("App updated. Recompiling..."); + header.css({borderColor: "#96b5b4"}); + $errors.hide(); if(!hot) iframe.hide(); + }, + hash: function(hash) { + currentHash = hash; + }, + "still-ok": function() { + okness.text(""); + status.text("App ready."); + header.css({borderColor: ""}); + $errors.hide(); if(!hot) iframe.show(); + }, + ok: function() { + okness.text(""); + $errors.hide(); + reloadApp(); + }, + warnings: function(warnings) { + okness.text("Warnings while compiling."); + $errors.hide(); + reloadApp(); + }, + errors: function(errors) { + status.text("App updated with errors. No reload!"); + okness.text("Errors while compiling."); + $errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n"); + header.css({borderColor: "#ebcb8b"}); + $errors.show(); iframe.hide(); + }, + "proxy-error": function(errors) { + status.text("Could not proxy to content base target!"); + okness.text("Proxy error."); + $errors.text("\n" + stripAnsi(errors.join("\n\n\n")) + "\n\n"); + header.css({borderColor: "#ebcb8b"}); + $errors.show(); iframe.hide(); + }, + close: function() { + status.text(""); + okness.text("Disconnected."); + $errors.text("\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n"); + header.css({borderColor: "#ebcb8b"}); + $errors.show(); iframe.hide(); + } + }; - io.on("disconnect", function() { - status.text(""); - okness.text("Disconnected."); - $errors.text("\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n"); - header.css({borderColor: "#ebcb8b"}); - $errors.show(); iframe.hide(); - }); + newConnection(onSocketMsg); iframe.load(function() { status.text("App ready."); diff --git a/lib/Server.js b/lib/Server.js index 0e43182a08..ee427c00c2 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -3,7 +3,7 @@ var path = require("path"); var webpackDevMiddleware = require("webpack-dev-middleware"); var express = require("express"); var compress = require("compression"); -var socketio = require("socket.io"); +var sockjs = require("sockjs"); var StreamCache = require("stream-cache"); var http = require("http"); var https = require("https"); @@ -23,15 +23,20 @@ function Server(compiler, options) { this.hot = options.hot; this.headers = options.headers; + this.sockWrite = function(type, data) { + this.sock.write(JSON.stringify({type: type, data: data})); + } + // Listening for events var invalidPlugin = function() { - if(this.io) this.io.sockets.emit("invalid"); + if(this.sock) this.sockWrite("invalid"); }.bind(this); compiler.plugin("compile", invalidPlugin); compiler.plugin("invalid", invalidPlugin); compiler.plugin("done", function(stats) { - if(!this.io) return; - this._sendStats(this.io.sockets, stats.toJson()); + if(!this.sock) return; + + this._sendStats(stats.toJson()); this._stats = stats; }.bind(this)); @@ -146,7 +151,7 @@ function Server(compiler, options) { } proxy.web(req, res, proxyOptions, function(err){ var msg = "cannot proxy to " + proxyOptions.target + " (" + err.message + ")"; - this.io.sockets.emit("proxy-error", [msg]); + this.sockWrite("proxy-error", [msg]); res.statusCode = 502; res.end(); }.bind(this)); @@ -177,7 +182,7 @@ function Server(compiler, options) { app.all("*", function(req, res) { proxy.web(req, res, contentBase, function(err) { var msg = "cannot proxy to " + contentBase.target + " (" + err.message + ")"; - this.io.sockets.emit("proxy-error", [msg]); + this.sockWrite("proxy-error", [msg]); res.statusCode = 502; res.end(); }.bind(this)); @@ -264,21 +269,32 @@ Server.prototype.setContentHeaders = function(req, res, next) { next(); } -// delegate listen call and init socket.io +// delegate listen call and init sockjs Server.prototype.listen = function() { this.listeningApp.listen.apply(this.listeningApp, arguments); - this.io = socketio.listen(this.listeningApp, { - "log level": 1 + var sockServer = sockjs.createServer({ + // Limit useless logs + log: function(severity, line) { + if (severity === 'error') { + console.log(line); + } + } }); - this.io.sockets.on("connection", function(socket) { - if(this.hot) socket.emit("hot"); + sockServer.on("connection", function(conn) { + this.sock = conn; + if(this.hot) this.sockWrite("hot"); if(!this._stats) return; - this._sendStats(socket, this._stats.toJson(), true); + this._sendStats(this._stats.toJson(), true); }.bind(this)); + + sockServer.installHandlers(this.listeningApp, { + prefix: '/sockjs-node' + }); } Server.prototype.close = function() { - this.io.close(); // Will also close listeningApp + this.sock.close(); // Will also close listeningApp + this.sock = null; this.middleware.close(); } @@ -297,17 +313,17 @@ Server.prototype.serveMagicHtml = function(req, res, next) { } // send stats to a socket or multiple sockets -Server.prototype._sendStats = function(socket, stats, force) { +Server.prototype._sendStats = function(stats, force) { if(!force && stats && (!stats.errors || stats.errors.length === 0) && stats.assets && stats.assets.every(function(asset) { return !asset.emitted; - })) return socket.emit("still-ok"); - socket.emit("hash", stats.hash); + })) return this.sockWrite("still-ok"); + this.sockWrite("hash", stats.hash); if(stats.errors.length > 0) - socket.emit("errors", stats.errors); + this.sockWrite("errors", stats.errors); else if(stats.warnings.length > 0) - socket.emit("warnings", stats.warnings); + this.sockWrite("warnings", stats.warnings); else - socket.emit("ok"); + this.sockWrite("ok"); } Server.prototype.invalidate = function() { diff --git a/package.json b/package.json index d6155d232a..b69a7f2358 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "http-proxy": "^1.11.2", "optimist": "~0.6.0", "serve-index": "^1.7.2", - "socket.io": "^1.3.6", - "socket.io-client": "^1.3.6", + "sockjs": "^0.3.15", + "sockjs-client": "^1.0.3", "stream-cache": "~0.0.1", "strip-ansi": "^3.0.0", "supports-color": "^3.1.1",