From c3df0f5aeda0e59e1a77d2300282597e0d8444da Mon Sep 17 00:00:00 2001 From: Gadzhi Gadzhiev Date: Tue, 18 Oct 2016 15:14:17 +0300 Subject: [PATCH 1/2] Option for listening to socket --- bin/webpack-dev-server.js | 81 +++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/bin/webpack-dev-server.js b/bin/webpack-dev-server.js index 3c43ce2df9..3039372515 100755 --- a/bin/webpack-dev-server.js +++ b/bin/webpack-dev-server.js @@ -3,6 +3,7 @@ var path = require("path"); var open = require("opn"); var fs = require("fs"); +var net = require("net"); var url = require("url"); // Local version replaces global one @@ -130,6 +131,11 @@ yargs.options({ default: 8080, group: CONNECTION_GROUP }, + "socket": { + type: "String", + describe: "Socket to listen", + group: CONNECTION_GROUP + }, "public": { type: "string", describe: "The public hostname/ip address of the server", @@ -172,6 +178,9 @@ function processOptions(wpOpt) { if(argv.port !== 8080 || !options.port) options.port = argv.port; + if(argv.socket) + options.socket = argv.socket; + if(!options.publicPath) { options.publicPath = firstWpOpt.output && firstWpOpt.output.publicPath || ""; if(!/^(https?:)?\/\//.test(options.publicPath) && options.publicPath[0] !== "/") @@ -299,27 +308,65 @@ function processOptions(wpOpt) { })); } - new Server(compiler, options).listen(options.port, options.host, function(err) { - if(err) throw err; + var uri = url.format({ + protocol: protocol, + hostname: options.host, + pathname: options.inline !== false ? "/" : "webpack-dev-server/", + port: options.socket ? 0 : options.port.toString() + }); - var uri = url.format({ - protocol: protocol, - hostname: options.host, - port: options.port.toString(), - pathname: options.inline !== false ? "/" : "webpack-dev-server/" + var server = new Server(compiler, options); + + if(options.socket) { + server.listeningApp.on("error", function(e) { + if(e.code === "EADDRINUSE") { + var clientSocket = new net.Socket(); + clientSocket.on("error", function(e) { + if(e.code === "ECONNREFUSED") { + // No other server listening on this socket so it can be safely removed + fs.unlinkSync(options.socket); + server.listen(options.socket, options.host, function(err) { + if(err) throw err; + }); + } + }); + clientSocket.connect({ path: options.socket }, function() { + throw new Error("This socket is already used"); + }); + } }); + server.listen(options.socket, options.host, function(err) { + if(err) throw err; + var READ_WRITE = 438; // chmod 666 (rw rw rw) + fs.chmod(options.socket, READ_WRITE, function(err) { + if(err) throw err; + reportReadiness(uri, options); + }); + }); + } else { + server.listen(options.port, options.host, function(err) { + if(err) throw err; + reportReadiness(uri, options); + }); + } +} + +function reportReadiness(uri, options) { + if(options.socket) { + console.log("Listening to socket", options.socket); + } else { console.log(" " + uri); + } - console.log("webpack result is served from " + options.publicPath); - if(Array.isArray(options.contentBase)) - console.log("content is served from " + options.contentBase.join(", ")); - else if(options.contentBase) - console.log("content is served from " + options.contentBase); - if(options.historyApiFallback) - console.log("404s will fallback to %s", options.historyApiFallback.index || "/index.html"); - if(options.open) - open(uri); - }); + console.log("webpack result is served from " + options.publicPath); + if(Array.isArray(options.contentBase)) + console.log("content is served from " + options.contentBase.join(", ")); + else if(options.contentBase) + console.log("content is served from " + options.contentBase); + if(options.historyApiFallback) + console.log("404s will fallback to %s", options.historyApiFallback.index || "/index.html"); + if(options.open) + open(uri); } processOptions(wpOpt); From bf150aadd45bf50c71d148b7157b5f3ea5f54a8b Mon Sep 17 00:00:00 2001 From: Gadzhi Gadzhiev Date: Tue, 18 Oct 2016 16:30:36 +0300 Subject: [PATCH 2/2] Add example of socket mode usage --- examples/listen-socket/README.md | 43 ++++++++++++++++++++++++ examples/listen-socket/app.js | 1 + examples/listen-socket/check-socket.js | 9 +++++ examples/listen-socket/webpack.config.js | 4 +++ 4 files changed, 57 insertions(+) create mode 100644 examples/listen-socket/README.md create mode 100644 examples/listen-socket/app.js create mode 100644 examples/listen-socket/check-socket.js create mode 100644 examples/listen-socket/webpack.config.js diff --git a/examples/listen-socket/README.md b/examples/listen-socket/README.md new file mode 100644 index 0000000000..9b79361c08 --- /dev/null +++ b/examples/listen-socket/README.md @@ -0,0 +1,43 @@ +# Listen to socket + +Start dev server in socket mode: + +```shell +node ../../bin/webpack-dev-server.js --socket ./webpack.sock +``` + +And then start node server that will use that socket: + +```shell +node check-socket.js +``` + +You should see this responses to this command: + +```shell +Successfully connected to socket, exiting +``` + +Common use-case for this feature is configuring upstream in nginx that points to webpack socket. +Listening to socket instead of port is much more convenient because if you have many applications you don't have to resolve port conflicts since each of them has own unique socket. + +Example of configuring upstream with Websockets support in nginx: + +``` +location /webpack/ { + proxy_pass http://unix:/home/happywebpackuser/apps/todo/webpack.sock; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://unix:/home/resure/code/statface-raw/app/run/statbox.sock; + proxy_redirect off; +} +location /sockjs-node/ { + proxy_pass http://unix:/home/happywebpackuser/apps/todo/webpack.sock; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; +} +``` + +Replace `/webpack/` with your `publicPath` param value and path in `proxy_pass` to your actual proxy location. diff --git a/examples/listen-socket/app.js b/examples/listen-socket/app.js new file mode 100644 index 0000000000..82ac1968f5 --- /dev/null +++ b/examples/listen-socket/app.js @@ -0,0 +1 @@ +document.write("It's working."); diff --git a/examples/listen-socket/check-socket.js b/examples/listen-socket/check-socket.js new file mode 100644 index 0000000000..2e5f9c6287 --- /dev/null +++ b/examples/listen-socket/check-socket.js @@ -0,0 +1,9 @@ +"use strict"; + +var net = require("net"); + +var client = net.createConnection("./webpack.sock"); +client.on("connect", function() { + console.log("Successfully connected to socket, exiting"); + process.exit(1); // eslint-disable-line +}); diff --git a/examples/listen-socket/webpack.config.js b/examples/listen-socket/webpack.config.js new file mode 100644 index 0000000000..9addf604cd --- /dev/null +++ b/examples/listen-socket/webpack.config.js @@ -0,0 +1,4 @@ +module.exports = { + context: __dirname, + entry: "./app.js", +}