Skip to content

Commit

Permalink
refactor: code
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed May 25, 2021
1 parent dadcd7a commit b2fde95
Show file tree
Hide file tree
Showing 27 changed files with 424 additions and 1,487 deletions.
21 changes: 6 additions & 15 deletions client-src/utils/createSocketURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ const url = require('url');
function createSocketURL(parsedURL) {
let { auth, hostname, protocol, port } = parsedURL;

const getURLSearchParam = (name) => {
if (parsedURL.searchParams) {
return parsedURL.searchParams.get(name);
}

return parsedURL.query && parsedURL.query[name];
};

// Node.js module parses it as `::`
// `new URL(urlString, [baseURLstring])` parses it as '[::]'
const isInAddrAny =
Expand Down Expand Up @@ -66,22 +58,21 @@ function createSocketURL(parsedURL) {
//
// All of these sock url params are optionally passed in through resourceQuery,
// so we need to fall back to the default if they are not provided
const socketURLHostname = (
getURLSearchParam('host') ||
hostname ||
'localhost'
).replace(/^\[(.*)\]$/, '$1');
const socketURLHostname = (hostname || 'localhost').replace(
/^\[(.*)\]$/,
'$1'
);

if (!port || port === '0') {
port = self.location.port;
}

const socketURLPort = getURLSearchParam('port') || port;
const socketURLPort = port;

// If path is provided it'll be passed in via the resourceQuery as a
// query param so it has to be parsed out of the querystring in order for the
// client to open the socket to the correct location.
const socketURLPathname = getURLSearchParam('path') || '/ws';
const socketURLPathname = parsedURL.pathname || '/ws';

return url.format({
protocol: socketURLProtocol,
Expand Down
17 changes: 11 additions & 6 deletions client-src/utils/parseURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ function parseURL(resourceQuery) {

if (typeof resourceQuery === 'string' && resourceQuery !== '') {
// If this bundle is inlined, use the resource query to get the correct url.
// format is like `?http://0.0.0.0:8096&port=8097&host=localhost`
// for backward compatibility we supports:
// - ?ws://0.0.0.0:8096&3Flogging=info
// - ?ws%3A%2F%2F192.168.0.5%3A8080%2F%3Flogging%3Dinfo
// Also we support `http` and `https` for backward compatibility too
options = url.parse(
resourceQuery
// strip leading `?` from query string to get a valid URL
.substr(1)
// replace first `&` with `?` to have a valid query string
.replace('&', '?'),
decodeURIComponent(
resourceQuery
// strip leading `?` from query string to get a valid URL
.substr(1)
// replace first `&` with `?` to have a valid query string
.replace('&', '?')
),
true
);
} else {
Expand Down
6 changes: 0 additions & 6 deletions examples/cli/public-protocol/app.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# CLI: Public Option
# CLI: Web Socket URL

```console
npm run webpack-dev-server -- --open-target --host 0.0.0.0 --public <insert local ip>:8080
npm run webpack-dev-server -- --open-target --host 0.0.0.0 --web-socket-url ws://<insert local ip>:8080
```

_NOTE: replace `<insert local ip>` with your local IP Address._

In order to make the server publicly accessible the client needs to know with
what host to connect to the server. If `--host 0.0.0.0` is given, the client
would try to connect to `0.0.0.0`. With the `--public` options it is possible to
would try to connect to `0.0.0.0`. With the `--web-socket-url` options it is possible to
override this.

## What Should Happen
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions examples/cli/web-socket-url/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

const target = document.querySelector('#target');

target.innerHTML =
'Please check the ws request in devtools, it should try to connect to the protocol + server defined in the webSocketURL setting.';
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = setup({
devServer: {
host: '0.0.0.0',
client: {
webSocketURL: 'https://localhost:8080',
webSocketURL: 'ws://localhost:8080',
},
firewall: false,
},
Expand Down
14 changes: 3 additions & 11 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -1013,17 +1013,9 @@ class Server {
}
}

// also allow public hostname if provided
if (typeof this.options.client.webSocketURL === 'string') {
const idxPublic = this.options.client.webSocketURL.indexOf(':');
const publicHostname =
idxPublic >= 0
? this.options.client.webSocketURL.substr(0, idxPublic)
: this.options.client.webSocketURL;

if (hostname === publicHostname) {
return true;
}
// Also allow if `client.webSocketURL.host` provided
if (typeof this.options.client.webSocketURL !== 'undefined') {
return this.options.client.webSocketURL.host === hostname;
}

// disallow
Expand Down
23 changes: 9 additions & 14 deletions lib/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,31 +283,30 @@
"webSocketURL": {
"anyOf": [
{
"type": "string"
"type": "string",
"minLength": 1
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"host": {
"type": "string",
"minLength": 1,
"description": "Tells clients connected to devServer to use the provided host."
},
"port": {
"type": "number",
"description": "Tells clients connected to devServer to use the provided port."
},
"path": {
"type": "string",
"description": "Tells clients connected to devServer to use the provided path to connect."
},
"port": {
"anyOf": [
{
"type": "number"
}
],
"description": "Tells clients connected to devServer to use the provided port."
}
}
}
]
],
"description": "When using dev server and you're proxying dev-server, the client script does not always know where to connect to."
}
},
"description": "Specifies client properties. https://webpack.js.org/configuration/dev-server/#devserverclient",
Expand Down Expand Up @@ -547,10 +546,6 @@
],
"description": "Proxying some URLs can be useful when you have a separate API backend development server and you want to send API requests on the same domain. https://webpack.js.org/configuration/dev-server/#devserverproxy"
},
"public": {
"type": "string",
"description": "When using dev server and you're proxying dev-server, the client script does not always know where to connect to. It will try to guess the URL of the server based on window.location, but if that fails you'll need to use this. https://webpack.js.org/configuration/dev-server/#devserverpublic"
},
"setupExitSignals": {
"type": "boolean",
"description": "It takes a boolean and if true (default on CLI), the server will close and exit the process on SIGINT and SIGTERM. https://webpack.js.org/configuration/dev-server/#devserversetupexitsignals"
Expand Down
134 changes: 90 additions & 44 deletions lib/utils/DevServerPlugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

const webpack = require('webpack');
const createDomain = require('./createDomain');
const getSocketClientPath = require('./getSocketClientPath');

// @ts-ignore
Expand All @@ -28,62 +27,107 @@ class DevServerPlugin {
apply(compiler) {
const { options } = this;

/** @type {"ws" | "wss"} */
const protocol = options.https ? 'wss' : 'ws';

/** @type {string} */
const domain = createDomain(options);
let host;

// SockJS is not supported server mode, so `host` and `port` can't specified, let's ignore them
// TODO show warning about this
const isSockJSType = options.webSocketServer.type === 'sockjs';

/** @type {string} */
let clientEntry = '';
// We are proxying dev server and need to specify custom `host`
if (typeof options.client.webSocketURL.host !== 'undefined') {
host = options.client.webSocketURL.host;
}
// Web socket server works on custom `host`, only for `ws` because `sock-js` is not support custom `host`
else if (
typeof options.webSocketServer.options.host !== 'undefined' &&
!isSockJSType
) {
host = options.webSocketServer.options.host;
}
// The `host` option is specified
else if (typeof this.options.host !== 'undefined') {
host = this.options.host;
}
// The `port` option is not specified
else {
host = '0.0.0.0';
}

/** @type {string} */
const logging =
options.client && options.client.logging
? `&logging=${options.client.logging}`
: '';

if (typeof options.client.webSocketURL === 'string') {
clientEntry = options.client.webSocketURL;
} else if (typeof options.client.webSocketURL === 'object') {
/** @type {string} */
let host = '';

if (options.client.webSocketURL.host) {
host = `&host=${options.client.webSocketURL.host}`;
} else if (options.webSocketServer.options.host && !isSockJSType) {
host = `&host=${options.webSocketServer.options.host}`;
}
/** @type {number | string} */
let port;

/** @type {string} */
let port = '';

if (options.client.webSocketURL.port) {
port = `&port=${options.client.webSocketURL.port}`;
} else if (options.webSocketServer.options.port && !isSockJSType) {
port = `&port=${options.webSocketServer.options.port}`;
} else if (options.port) {
port = `&port=${options.port}`;
} else {
port = '';
}
// We are proxying dev server and need to specify custom `port`
if (typeof options.client.webSocketURL.port !== 'undefined') {
port = options.client.webSocketURL.port;
}
// Web socket server works on custom `port`, only for `ws` because `sock-js` is not support custom `port`
else if (
typeof options.webSocketServer.options.port !== 'undefined' &&
!isSockJSType
) {
port = options.webSocketServer.options.port;
}
// The `port` option is specified
else if (typeof options.port === 'number') {
port = options.port;
}
// The `port` option is specified using `string`
else if (typeof options.port === 'string' && options.port !== 'auto') {
port = Number(options.port);
}
// The `port` option is not specified or set to `auto`
else {
port = 0;
}

/** @type {string} */
let path = '';
/** @type {string} */
let path = '';

// Only add the path if it is not default
if (options.client.webSocketURL.path) {
path = `&path=${options.client.webSocketURL.path}`;
} else if (options.webSocketServer.options.path) {
path = `&path=${options.webSocketServer.options.path}`;
}
// We are proxying dev server and need to specify custom `path`
if (typeof options.client.webSocketURL.path !== 'undefined') {
path = options.client.webSocketURL.path;
}
// Web socket server works on custom `path`
else if (
typeof options.webSocketServer.options.prefix !== 'undefined' ||
typeof options.webSocketServer.options.path !== 'undefined'
) {
path =
options.webSocketServer.options.prefix ||
options.webSocketServer.options.path;
}

clientEntry = `${require.resolve(
'../../client/index.js'
)}?${domain}${host}${path}${port}${logging}`;
/** @type {Record<string, any>} */
const searchParams = {};

if (typeof options.client.logging !== 'undefined') {
searchParams.logging = options.client.logging;
}

const webSocketURL = encodeURIComponent(
new URL(
`${protocol}://${host}${port ? `:${port}` : ''}${path || '/'}${
Object.keys(searchParams).length > 0
? `?${Object.entries(searchParams)
.map(([key, value]) => `${key}=${value}`)
.join('&')}`
: ''
}`
).toString()
).replace(
/[!'()*]/g,
(character) => `%${character.charCodeAt(0).toString(16)}`
);

/** @type {string} */
const clientEntry = `${require.resolve(
'../../client/index.js'
)}?${webSocketURL}`;

/** @type {(string[] | string)} */
let hotEntry;

Expand Down Expand Up @@ -123,11 +167,13 @@ class DevServerPlugin {
// make sure that we do not add duplicates.
/** @type {Entry} */
const entriesClone = additionalEntries.slice(0);

[].concat(originalEntry).forEach((newEntry) => {
if (!entriesClone.includes(newEntry)) {
entriesClone.push(newEntry);
}
});

return entriesClone;
};

Expand Down
31 changes: 0 additions & 31 deletions lib/utils/createDomain.js

This file was deleted.

Loading

0 comments on commit b2fde95

Please sign in to comment.