Skip to content

Commit 9b7a14e

Browse files
Gadzhi GadzhievSpaceK33z
Gadzhi Gadzhiev
authored andcommitted
Option for listening to unix socket (#661)
1 parent 964c652 commit 9b7a14e

File tree

5 files changed

+121
-17
lines changed

5 files changed

+121
-17
lines changed

bin/webpack-dev-server.js

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var path = require("path");
44
var open = require("opn");
55
var fs = require("fs");
6+
var net = require("net");
67
var url = require("url");
78

89
// Local version replaces global one
@@ -130,6 +131,11 @@ yargs.options({
130131
default: 8080,
131132
group: CONNECTION_GROUP
132133
},
134+
"socket": {
135+
type: "String",
136+
describe: "Socket to listen",
137+
group: CONNECTION_GROUP
138+
},
133139
"public": {
134140
type: "string",
135141
describe: "The public hostname/ip address of the server",
@@ -172,6 +178,9 @@ function processOptions(wpOpt) {
172178
if(argv.port !== 8080 || !options.port)
173179
options.port = argv.port;
174180

181+
if(argv.socket)
182+
options.socket = argv.socket;
183+
175184
if(!options.publicPath) {
176185
options.publicPath = firstWpOpt.output && firstWpOpt.output.publicPath || "";
177186
if(!/^(https?:)?\/\//.test(options.publicPath) && options.publicPath[0] !== "/")
@@ -299,27 +308,65 @@ function processOptions(wpOpt) {
299308
}));
300309
}
301310

302-
new Server(compiler, options).listen(options.port, options.host, function(err) {
303-
if(err) throw err;
311+
var uri = url.format({
312+
protocol: protocol,
313+
hostname: options.host,
314+
pathname: options.inline !== false ? "/" : "webpack-dev-server/",
315+
port: options.socket ? 0 : options.port.toString()
316+
});
304317

305-
var uri = url.format({
306-
protocol: protocol,
307-
hostname: options.host,
308-
port: options.port.toString(),
309-
pathname: options.inline !== false ? "/" : "webpack-dev-server/"
318+
var server = new Server(compiler, options);
319+
320+
if(options.socket) {
321+
server.listeningApp.on("error", function(e) {
322+
if(e.code === "EADDRINUSE") {
323+
var clientSocket = new net.Socket();
324+
clientSocket.on("error", function(e) {
325+
if(e.code === "ECONNREFUSED") {
326+
// No other server listening on this socket so it can be safely removed
327+
fs.unlinkSync(options.socket);
328+
server.listen(options.socket, options.host, function(err) {
329+
if(err) throw err;
330+
});
331+
}
332+
});
333+
clientSocket.connect({ path: options.socket }, function() {
334+
throw new Error("This socket is already used");
335+
});
336+
}
310337
});
338+
server.listen(options.socket, options.host, function(err) {
339+
if(err) throw err;
340+
var READ_WRITE = 438; // chmod 666 (rw rw rw)
341+
fs.chmod(options.socket, READ_WRITE, function(err) {
342+
if(err) throw err;
343+
reportReadiness(uri, options);
344+
});
345+
});
346+
} else {
347+
server.listen(options.port, options.host, function(err) {
348+
if(err) throw err;
349+
reportReadiness(uri, options);
350+
});
351+
}
352+
}
353+
354+
function reportReadiness(uri, options) {
355+
if(options.socket) {
356+
console.log("Listening to socket", options.socket);
357+
} else {
311358
console.log(" " + uri);
359+
}
312360

313-
console.log("webpack result is served from " + options.publicPath);
314-
if(Array.isArray(options.contentBase))
315-
console.log("content is served from " + options.contentBase.join(", "));
316-
else if(options.contentBase)
317-
console.log("content is served from " + options.contentBase);
318-
if(options.historyApiFallback)
319-
console.log("404s will fallback to %s", options.historyApiFallback.index || "/index.html");
320-
if(options.open)
321-
open(uri);
322-
});
361+
console.log("webpack result is served from " + options.publicPath);
362+
if(Array.isArray(options.contentBase))
363+
console.log("content is served from " + options.contentBase.join(", "));
364+
else if(options.contentBase)
365+
console.log("content is served from " + options.contentBase);
366+
if(options.historyApiFallback)
367+
console.log("404s will fallback to %s", options.historyApiFallback.index || "/index.html");
368+
if(options.open)
369+
open(uri);
323370
}
324371

325372
processOptions(wpOpt);

examples/listen-socket/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Listen to socket
2+
3+
Start dev server in socket mode:
4+
5+
```shell
6+
node ../../bin/webpack-dev-server.js --socket ./webpack.sock
7+
```
8+
9+
And then start node server that will use that socket:
10+
11+
```shell
12+
node check-socket.js
13+
```
14+
15+
You should see this responses to this command:
16+
17+
```shell
18+
Successfully connected to socket, exiting
19+
```
20+
21+
Common use-case for this feature is configuring upstream in nginx that points to webpack socket.
22+
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.
23+
24+
Example of configuring upstream with Websockets support in nginx:
25+
26+
```
27+
location /webpack/ {
28+
proxy_pass http://unix:/home/happywebpackuser/apps/todo/webpack.sock;
29+
proxy_set_header Host $host;
30+
proxy_set_header X-Real-IP $remote_addr;
31+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
32+
proxy_pass http://unix:/home/resure/code/statface-raw/app/run/statbox.sock;
33+
proxy_redirect off;
34+
}
35+
location /sockjs-node/ {
36+
proxy_pass http://unix:/home/happywebpackuser/apps/todo/webpack.sock;
37+
proxy_http_version 1.1;
38+
proxy_set_header Upgrade $http_upgrade;
39+
proxy_set_header Connection "upgrade";
40+
}
41+
```
42+
43+
Replace `/webpack/` with your `publicPath` param value and path in `proxy_pass` to your actual proxy location.

examples/listen-socket/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
document.write("It's working.");
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"use strict";
2+
3+
var net = require("net");
4+
5+
var client = net.createConnection("./webpack.sock");
6+
client.on("connect", function() {
7+
console.log("Successfully connected to socket, exiting");
8+
process.exit(1); // eslint-disable-line
9+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
context: __dirname,
3+
entry: "./app.js",
4+
}

0 commit comments

Comments
 (0)