Skip to content

Commit 1581adc

Browse files
hiroppyevilebottnawi
authored andcommitted
refactor(client): create createSocketUrl module into utils (#1954)
1 parent 9a1ad89 commit 1581adc

File tree

4 files changed

+151
-72
lines changed

4 files changed

+151
-72
lines changed

client-src/default/index.js

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22

33
/* global __resourceQuery WorkerGlobalScope self */
44
/* eslint prefer-destructuring: off */
5-
const querystring = require('querystring');
6-
const url = require('url');
75
const stripAnsi = require('strip-ansi');
86
const log = require('loglevel').getLogger('webpack-dev-server');
97
const socket = require('./socket');
108
const overlay = require('./overlay');
119
const sendMessage = require('./utils/sendMessage');
1210
const reloadApp = require('./utils/reloadApp');
13-
const getCurrentScriptSource = require('./utils/getCurrentScriptSource');
11+
const createSocketUrl = require('./utils/createSocketUrl');
1412

15-
let urlParts;
1613
const status = {
1714
isUnloading: false,
1815
currentHash: '',
@@ -26,6 +23,7 @@ const options = {
2623
useErrorOverlay: false,
2724
useProgress: false,
2825
};
26+
const socketUrl = createSocketUrl(__resourceQuery);
2927

3028
self.addEventListener('beforeunload', () => {
3129
status.isUnloading = true;
@@ -35,20 +33,6 @@ if (typeof window !== 'undefined') {
3533
const qs = window.location.search.toLowerCase();
3634
options.hotReload = qs.indexOf('hotreload=false') === -1;
3735
}
38-
if (typeof __resourceQuery === 'string' && __resourceQuery) {
39-
// If this bundle is inlined, use the resource query to get the correct url.
40-
urlParts = url.parse(__resourceQuery.substr(1));
41-
} else {
42-
// Else, get the url from the <script> this file was called with.
43-
let scriptHost = getCurrentScriptSource();
44-
// eslint-disable-next-line no-useless-escape
45-
scriptHost = scriptHost.replace(/\/[^\/]+$/, '');
46-
urlParts = url.parse(scriptHost || '/', false, true);
47-
}
48-
49-
if (!urlParts.port || urlParts.port === '0') {
50-
urlParts.port = self.location.port;
51-
}
5236

5337
const INFO = 'info';
5438
const WARN = 'warn';
@@ -192,58 +176,4 @@ const onSocketMsg = {
192176
},
193177
};
194178

195-
let { hostname, protocol } = urlParts;
196-
197-
// check ipv4 and ipv6 `all hostname`
198-
if (hostname === '0.0.0.0' || hostname === '::') {
199-
// why do we need this check?
200-
// hostname n/a for file protocol (example, when using electron, ionic)
201-
// see: https://github.com/webpack/webpack-dev-server/pull/384
202-
// eslint-disable-next-line no-bitwise
203-
if (self.location.hostname && !!~self.location.protocol.indexOf('http')) {
204-
hostname = self.location.hostname;
205-
}
206-
}
207-
208-
// `hostname` can be empty when the script path is relative. In that case, specifying
209-
// a protocol would result in an invalid URL.
210-
// When https is used in the app, secure websockets are always necessary
211-
// because the browser doesn't accept non-secure websockets.
212-
if (
213-
hostname &&
214-
(self.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0')
215-
) {
216-
protocol = self.location.protocol;
217-
}
218-
219-
// default values of the sock url if they are not provided
220-
let sockHost = hostname;
221-
let sockPath = '/sockjs-node';
222-
let sockPort = urlParts.port;
223-
if (
224-
urlParts.path !== null &&
225-
// eslint-disable-next-line no-undefined
226-
urlParts.path !== undefined &&
227-
urlParts.path !== '/'
228-
) {
229-
const parsedQuery = querystring.parse(urlParts.path);
230-
// all of these sock url params are optionally passed in through
231-
// __resourceQuery, so we need to fall back to the default if
232-
// they are not provided
233-
sockHost = parsedQuery.sockHost || sockHost;
234-
sockPath = parsedQuery.sockPath || sockPath;
235-
sockPort = parsedQuery.sockPort || sockPort;
236-
}
237-
238-
const socketUrl = url.format({
239-
protocol,
240-
auth: urlParts.auth,
241-
hostname: sockHost,
242-
port: sockPort,
243-
// If sockPath is provided it'll be passed in via the __resourceQuery as a
244-
// query param so it has to be parsed out of the querystring in order for the
245-
// client to open the socket to the correct location.
246-
pathname: sockPath,
247-
});
248-
249179
socket(socketUrl, onSocketMsg);
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
3+
/* global self */
4+
5+
const url = require('url');
6+
const querystring = require('querystring');
7+
const getCurrentScriptSource = require('./getCurrentScriptSource');
8+
9+
function createSocketUrl(resourceQuery) {
10+
let urlParts;
11+
12+
if (typeof resourceQuery === 'string' && resourceQuery !== '') {
13+
// If this bundle is inlined, use the resource query to get the correct url.
14+
urlParts = url.parse(resourceQuery.substr(1));
15+
} else {
16+
// Else, get the url from the <script> this file was called with.
17+
let scriptHost = getCurrentScriptSource();
18+
19+
// eslint-disable-next-line no-useless-escape
20+
scriptHost = scriptHost.replace(/\/[^\/]+$/, '');
21+
urlParts = url.parse(scriptHost || '/', false, true);
22+
}
23+
24+
if (!urlParts.port || urlParts.port === '0') {
25+
urlParts.port = self.location.port;
26+
}
27+
28+
const { auth, path } = urlParts;
29+
let { hostname, protocol } = urlParts;
30+
31+
// check ipv4 and ipv6 `all hostname`
32+
// why do we need this check?
33+
// hostname n/a for file protocol (example, when using electron, ionic)
34+
// see: https://github.com/webpack/webpack-dev-server/pull/384
35+
if (
36+
(hostname === '0.0.0.0' || hostname === '::') &&
37+
self.location.hostname &&
38+
// eslint-disable-next-line no-bitwise
39+
!!~self.location.protocol.indexOf('http')
40+
) {
41+
hostname = self.location.hostname;
42+
}
43+
44+
// `hostname` can be empty when the script path is relative. In that case, specifying
45+
// a protocol would result in an invalid URL.
46+
// When https is used in the app, secure websockets are always necessary
47+
// because the browser doesn't accept non-secure websockets.
48+
if (
49+
hostname &&
50+
(self.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0')
51+
) {
52+
protocol = self.location.protocol;
53+
}
54+
55+
// default values of the sock url if they are not provided
56+
let sockHost = hostname;
57+
let sockPath = '/sockjs-node';
58+
let sockPort = urlParts.port;
59+
60+
// eslint-disable-next-line no-undefined
61+
if (path !== null && path !== undefined && path !== '/') {
62+
const parsedQuery = querystring.parse(path);
63+
// all of these sock url params are optionally passed in through
64+
// resourceQuery, so we need to fall back to the default if
65+
// they are not provided
66+
sockHost = parsedQuery.sockHost || sockHost;
67+
sockPath = parsedQuery.sockPath || sockPath;
68+
sockPort = parsedQuery.sockPort || sockPort;
69+
}
70+
71+
return url.format({
72+
protocol,
73+
auth,
74+
hostname: sockHost,
75+
port: sockPort,
76+
// If sockPath is provided it'll be passed in via the resourceQuery as a
77+
// query param so it has to be parsed out of the querystring in order for the
78+
// client to open the socket to the correct location.
79+
pathname: sockPath,
80+
});
81+
}
82+
83+
module.exports = createSocketUrl;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`createSocketUrl should return the url when __resourceQuery is ?test 1`] = `"/sockjs-node"`;
4+
5+
exports[`createSocketUrl should return the url when __resourceQuery is http://0.0.0.0 1`] = `"http://localhost/sockjs-node"`;
6+
7+
exports[`createSocketUrl should return the url when __resourceQuery is http://user:pass@[::]:8080 1`] = `"ttp:user:pass@localhost:8080/sockjs-node"`;
8+
9+
exports[`createSocketUrl should return the url when __resourceQuery is http://user:password@localhost/ 1`] = `"ttp:user:password@localhost/sockjs-node"`;
10+
11+
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com 1`] = `"ttps:example.com/sockjs-node"`;
12+
13+
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com/path 1`] = `"ttps:example.com/sockjs-node"`;
14+
15+
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com/path/foo.js 1`] = `"ttps:example.com/sockjs-node"`;
16+
17+
exports[`createSocketUrl should return the url when __resourceQuery is https://localhost:123 1`] = `"ttps:localhost:123/sockjs-node"`;
18+
19+
exports[`createSocketUrl should return the url when the current script source is ?test 1`] = `"/sockjs-node"`;
20+
21+
exports[`createSocketUrl should return the url when the current script source is http://0.0.0.0 1`] = `"http:/sockjs-node"`;
22+
23+
exports[`createSocketUrl should return the url when the current script source is http://user:pass@[::]:8080 1`] = `"http:/sockjs-node"`;
24+
25+
exports[`createSocketUrl should return the url when the current script source is http://user:password@localhost/ 1`] = `"http://user:password@localhost/sockjs-node"`;
26+
27+
exports[`createSocketUrl should return the url when the current script source is https://example.com 1`] = `"https:/sockjs-node"`;
28+
29+
exports[`createSocketUrl should return the url when the current script source is https://example.com/path 1`] = `"https://example.com/sockjs-node"`;
30+
31+
exports[`createSocketUrl should return the url when the current script source is https://example.com/path/foo.js 1`] = `"https://example.com/sockjs-node"`;
32+
33+
exports[`createSocketUrl should return the url when the current script source is https://localhost:123 1`] = `"https:/sockjs-node"`;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
describe('createSocketUrl', () => {
4+
const samples = [
5+
'?test',
6+
'https://example.com',
7+
'https://example.com/path',
8+
'https://example.com/path/foo.js',
9+
'http://user:password@localhost/',
10+
'http://0.0.0.0',
11+
'https://localhost:123',
12+
'http://user:pass@[::]:8080',
13+
// TODO: comment out after the major release
14+
// https://github.com/webpack/webpack-dev-server/pull/1954#issuecomment-498043376
15+
// 'file://filename',
16+
];
17+
18+
samples.forEach((url) => {
19+
jest.doMock('../../../../client-src/default/utils/getCurrentScriptSource.js', () => () => url);
20+
const createSocketUrl = require('../../../../client-src/default/utils/createSocketUrl');
21+
22+
test(`should return the url when __resourceQuery is ${url}`, () => {
23+
expect(createSocketUrl(url)).toMatchSnapshot();
24+
});
25+
26+
test(`should return the url when the current script source is ${url}`, () => {
27+
expect(createSocketUrl()).toMatchSnapshot();
28+
});
29+
30+
// put here because resetModules mustn't be reset when L20 is finished
31+
jest.resetModules();
32+
});
33+
});

0 commit comments

Comments
 (0)