From abe78122e7e1b84482109c18b703ab9a2574b20a Mon Sep 17 00:00:00 2001 From: shellscape Date: Thu, 5 Jul 2018 20:09:36 -0400 Subject: [PATCH 1/4] feat: client-server port config, better server support --- README.md | 16 +++++++++++++--- lib/options.js | 40 +++++++++++++++++++++++++++++----------- lib/socket-server.js | 11 +++++++++-- schemas/options.json | 17 ++++++++++++++++- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cd43495..84740b6 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,8 @@ Default: `'localhost'` Sets the host that the `WebSocket` server will listen on. If this doesn't match the host of the server the module is used with, the module may not function -properly. If the `server` option is defined, this option is ignored. +properly. If the `server` option is defined, and the server has been instructed +to listen, this option is ignored. If using the module in a specialized environment, you may choose to specify an `object` to define `client` and `server` host separately. The `object` value @@ -198,12 +199,21 @@ If true, instructs the internal logger to prepend log output with a timestamp. ##### port -Type: `Number` +Type: `Number|Object` Default: `0` The port the `WebSocket` server should listen on. By default, the socket server will allocate a port. If a different port is chosen, the consumer of the module -must ensure that the port is free before hand. +must ensure that the port is free before hand. If the `server` option is defined, +and the server has been instructed to listen, this option is ignored. + +If using the module in a specialized environment, you may choose to specify an +`object` to define `client` and `server` port separately. The `object` value +should match `{ client: , server: }`. Be aware that the `client` +port will be used _in the browser_ by `WebSockets`. You should not use this +option in this way unless _you know what you're doing._ Using a mismatched +`client` and `server` port will be **unsupported by the project** as the behavior +in the browser can be unpredictable and is specific to a particular environment. ##### reload diff --git a/lib/options.js b/lib/options.js index 739e321..393e7b4 100644 --- a/lib/options.js +++ b/lib/options.js @@ -46,8 +46,8 @@ module.exports = (opts = {}) => { if (typeof options.host === 'string') { options.host = { - server: options.host, client: options.host, + server: options.host, }; } else if (!options.host.server) { throw new HotClientError( @@ -59,23 +59,41 @@ module.exports = (opts = {}) => { ); } - const { server } = options; - - if (server && !server.listening) { + if (typeof options.port === 'number') { + options.port = { + client: options.port, + server: options.port, + }; + } else if (!options.port.server) { + throw new HotClientError( + '`port.server` must be defined when setting host to an Object' + ); + } else if (!options.port.client) { throw new HotClientError( - '`options.server` must be a running/listening net.Server instance' + '`port.client` must be defined when setting host to an Object' ); - } else if (server) { + } + + const { server } = options; + + if ( + server && + server instanceof HttpsServer && + typeof options.https === 'undefined' + ) { + options.https = true; + } + + if (server && server.listening) { options.webSocket = { host: server.address().address, port: server.address().port, }; - - if (server instanceof HttpsServer && typeof options.https === 'undefined') { - options.https = true; - } } else { - options.webSocket = { host: options.host.client, port: options.port }; + options.webSocket = { + host: options.host.client, + port: options.port.client, + }; } return options; diff --git a/lib/socket-server.js b/lib/socket-server.js index 9d6f1bd..82ffa11 100644 --- a/lib/socket-server.js +++ b/lib/socket-server.js @@ -4,7 +4,14 @@ const WebSocket = require('ws'); function getServer(options) { const { host, log, port, server } = options; - const wssOptions = server ? { server } : { host: host.server, port }; + const wssOptions = server + ? { server } + : { host: host.server, port: port.server }; + + if (!server.listening) { + server.listen(port.server, host.server); + } + const wss = new WebSocket.Server(wssOptions); onConnection(wss, options); @@ -87,7 +94,7 @@ function onListening(server, options) { /* eslint-disable no-underscore-dangle, no-param-reassign */ const { host, log } = options; - if (options.server) { + if (options.server && options.server.listening) { const addr = options.server.address(); server.host = addr.address; server.port = addr.port; diff --git a/schemas/options.json b/schemas/options.json index ba16796..967f663 100644 --- a/schemas/options.json +++ b/schemas/options.json @@ -41,7 +41,22 @@ "type": "boolean" }, "port": { - "type": "integer" + "anyOf": [ + { + "type": "integer" + }, + { + "properties": { + "client": { + "type": "integer" + }, + "server": { + "type": "integer" + } + }, + "type": "object" + } + ] }, "reload": { "type": "boolean" From 490dc36561818316c0379d8db7a2782212b12d85 Mon Sep 17 00:00:00 2001 From: shellscape Date: Thu, 5 Jul 2018 20:10:17 -0400 Subject: [PATCH 2/4] chore: beta --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4138749..adc9647 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { "name": "webpack-hot-client", - "version": "4.0.4", + "version": "4.1.0-beta.1", + "publishConfig": { + "tag": "beta" + }, "description": "A client for enabling, and interacting with, webpack Hot Module Replacement", "license": "MIT", "repository": "webpack-contrib/webpack-hot-client", From 720961d6fe60df308ca69f41ebe87c834b35299b Mon Sep 17 00:00:00 2001 From: shellscape Date: Thu, 5 Jul 2018 20:55:59 -0400 Subject: [PATCH 3/4] docs: add https note about firefox --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 84740b6..b1777e4 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,10 @@ module won't function properly. The module will examine the `server` instance passed and if `server` _is an instance of `https.Server`, and `https` is not already set_, will set `https` to `true`. +_Note: When using a self-signed certificate on Firefox, you must add a "Server +Exception" for `localhost:{port}` where `{port}` is either the `port` or the +`port.server` option for secure `WebSocket` to work correctly._ + ##### logLevel Type: `String` From 3af8c99daa2a3d6c058e1ffd25f6a67ba69c82a2 Mon Sep 17 00:00:00 2001 From: shellscape Date: Thu, 5 Jul 2018 21:22:29 -0400 Subject: [PATCH 4/4] test: fix tests --- lib/socket-server.js | 2 +- test/__snapshots__/options.test.js.snap | 20 ++++++++++++++++---- test/fixtures/app.js | 4 ++++ test/options.test.js | 13 ------------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/socket-server.js b/lib/socket-server.js index 82ffa11..4059c21 100644 --- a/lib/socket-server.js +++ b/lib/socket-server.js @@ -8,7 +8,7 @@ function getServer(options) { ? { server } : { host: host.server, port: port.server }; - if (!server.listening) { + if (server && !server.listening) { server.listen(port.server, host.server); } diff --git a/test/__snapshots__/options.test.js.snap b/test/__snapshots__/options.test.js.snap index 26502d5..62e9185 100644 --- a/test/__snapshots__/options.test.js.snap +++ b/test/__snapshots__/options.test.js.snap @@ -51,7 +51,10 @@ Object { }, "logLevel": "trace", "logTime": true, - "port": 0, + "port": Object { + "client": 0, + "server": 0, + }, "reload": false, "send": Object { "errors": false, @@ -124,7 +127,10 @@ Object { }, "logLevel": "info", "logTime": false, - "port": 0, + "port": Object { + "client": 0, + "server": 0, + }, "reload": true, "send": Object { "errors": true, @@ -196,7 +202,10 @@ Object { }, "logLevel": "info", "logTime": false, - "port": 0, + "port": Object { + "client": 0, + "server": 0, + }, "reload": true, "send": Object { "errors": true, @@ -268,7 +277,10 @@ Object { }, "logLevel": "info", "logTime": false, - "port": 0, + "port": Object { + "client": 0, + "server": 0, + }, "reload": true, "send": Object { "errors": true, diff --git a/test/fixtures/app.js b/test/fixtures/app.js index b91c3c4..0655950 100644 --- a/test/fixtures/app.js +++ b/test/fixtures/app.js @@ -17,3 +17,7 @@ console.log('dirty'); console.log('dirty'); console.log('dirty'); + +console.log('dirty'); +console.log('dirty'); +console.log('dirty'); diff --git a/test/options.test.js b/test/options.test.js index 58adef0..d1b1db0 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -1,6 +1,5 @@ const { readFileSync: read } = require('fs'); const { resolve } = require('path'); -const { createServer } = require('http'); const https = require('https'); const killable = require('killable'); @@ -102,16 +101,4 @@ describe('options', () => { const t = () => getOptions({ host: { client: 'localhost' } }); expect(t).toThrow(); }); - - test('reject non-http.Server server', () => { - const server = {}; - const t = () => getOptions({ server }); - expect(t).toThrow(); - }); - - test('reject non-running server', () => { - const server = createServer(); - const t = () => getOptions({ server }); - expect(t).toThrow(); - }); });