Skip to content

Commit ffb2c79

Browse files
hiroppyevilebottnawi
authored andcommitted
refactor(client): separate into modules (#1948)
1 parent fb31770 commit ffb2c79

12 files changed

+340
-119
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ npm-debug.log
66
.nyc_output
77

88
client
9+
!/test/client
910
coverage
1011
ssl/*.pem
1112
node_modules

client-src/default/index.js

Lines changed: 51 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,32 @@ const stripAnsi = require('strip-ansi');
88
const log = require('loglevel').getLogger('webpack-dev-server');
99
const socket = require('./socket');
1010
const overlay = require('./overlay');
11-
12-
function getCurrentScriptSource() {
13-
// `document.currentScript` is the most accurate way to find the current script,
14-
// but is not supported in all browsers.
15-
if (document.currentScript) {
16-
return document.currentScript.getAttribute('src');
17-
}
18-
// Fall back to getting all scripts in the document.
19-
const scriptElements = document.scripts || [];
20-
const currentScript = scriptElements[scriptElements.length - 1];
21-
if (currentScript) {
22-
return currentScript.getAttribute('src');
23-
}
24-
// Fail as there was no script to use.
25-
throw new Error('[WDS] Failed to get current script source.');
26-
}
11+
const sendMessage = require('./utils/sendMessage');
12+
const reloadApp = require('./utils/reloadApp');
13+
const getCurrentScriptSource = require('./utils/getCurrentScriptSource');
2714

2815
let urlParts;
29-
let hotReload = true;
16+
const status = {
17+
isUnloading: false,
18+
currentHash: '',
19+
};
20+
const options = {
21+
hot: false,
22+
hotReload: true,
23+
liveReload: false,
24+
initial: true,
25+
useWarningOverlay: false,
26+
useErrorOverlay: false,
27+
useProgress: false,
28+
};
29+
30+
self.addEventListener('beforeunload', () => {
31+
status.isUnloading = true;
32+
});
33+
3034
if (typeof window !== 'undefined') {
3135
const qs = window.location.search.toLowerCase();
32-
hotReload = qs.indexOf('hotreload=false') === -1;
36+
options.hotReload = qs.indexOf('hotreload=false') === -1;
3337
}
3438
if (typeof __resourceQuery === 'string' && __resourceQuery) {
3539
// If this bundle is inlined, use the resource query to get the correct url.
@@ -46,21 +50,12 @@ if (!urlParts.port || urlParts.port === '0') {
4650
urlParts.port = self.location.port;
4751
}
4852

49-
let hot = false;
50-
let liveReload = false;
51-
let initial = true;
52-
let currentHash = '';
53-
let useWarningOverlay = false;
54-
let useErrorOverlay = false;
55-
let useProgress = false;
56-
5753
const INFO = 'info';
5854
const WARN = 'warn';
5955
const ERROR = 'error';
6056
const DEBUG = 'debug';
6157
const TRACE = 'trace';
6258
const SILENT = 'silent';
63-
6459
// deprecated
6560
// TODO: remove these at major released
6661
// https://github.com/webpack/webpack-dev-server/pull/1825
@@ -70,49 +65,32 @@ const NONE = 'none';
7065
// Set the default log level
7166
log.setDefaultLevel(INFO);
7267

73-
// Send messages to the outside, so plugins can consume it.
74-
function sendMsg(type, data) {
75-
if (
76-
typeof self !== 'undefined' &&
77-
(typeof WorkerGlobalScope === 'undefined' ||
78-
!(self instanceof WorkerGlobalScope))
79-
) {
80-
self.postMessage(
81-
{
82-
type: `webpack${type}`,
83-
data,
84-
},
85-
'*'
86-
);
87-
}
88-
}
89-
9068
const onSocketMsg = {
9169
hot() {
92-
hot = true;
70+
options.hot = true;
9371
log.info('[WDS] Hot Module Replacement enabled.');
9472
},
9573
liveReload() {
96-
liveReload = true;
74+
options.liveReload = true;
9775
log.info('[WDS] Live Reloading enabled.');
9876
},
9977
invalid() {
10078
log.info('[WDS] App updated. Recompiling...');
10179
// fixes #1042. overlay doesn't clear if errors are fixed but warnings remain.
102-
if (useWarningOverlay || useErrorOverlay) {
80+
if (options.useWarningOverlay || options.useErrorOverlay) {
10381
overlay.clear();
10482
}
105-
sendMsg('Invalid');
83+
sendMessage('Invalid');
10684
},
10785
hash(hash) {
108-
currentHash = hash;
86+
status.currentHash = hash;
10987
},
11088
'still-ok': function stillOk() {
11189
log.info('[WDS] Nothing changed.');
112-
if (useWarningOverlay || useErrorOverlay) {
90+
if (options.useWarningOverlay || options.useErrorOverlay) {
11391
overlay.clear();
11492
}
115-
sendMsg('StillOk');
93+
sendMessage('StillOk');
11694
},
11795
'log-level': function logLevel(level) {
11896
const hotCtx = require.context('webpack/hot', false, /^\.\/log$/);
@@ -144,34 +122,34 @@ const onSocketMsg = {
144122
overlay(value) {
145123
if (typeof document !== 'undefined') {
146124
if (typeof value === 'boolean') {
147-
useWarningOverlay = false;
148-
useErrorOverlay = value;
125+
options.useWarningOverlay = false;
126+
options.useErrorOverlay = value;
149127
} else if (value) {
150-
useWarningOverlay = value.warnings;
151-
useErrorOverlay = value.errors;
128+
options.useWarningOverlay = value.warnings;
129+
options.useErrorOverlay = value.errors;
152130
}
153131
}
154132
},
155133
progress(progress) {
156134
if (typeof document !== 'undefined') {
157-
useProgress = progress;
135+
options.useProgress = progress;
158136
}
159137
},
160138
'progress-update': function progressUpdate(data) {
161-
if (useProgress) {
139+
if (options.useProgress) {
162140
log.info(`[WDS] ${data.percent}% - ${data.msg}.`);
163141
}
164-
sendMsg('Progress', data);
142+
sendMessage('Progress', data);
165143
},
166144
ok() {
167-
sendMsg('Ok');
168-
if (useWarningOverlay || useErrorOverlay) {
145+
sendMessage('Ok');
146+
if (options.useWarningOverlay || options.useErrorOverlay) {
169147
overlay.clear();
170148
}
171-
if (initial) {
172-
return (initial = false);
149+
if (options.initial) {
150+
return (options.initial = false);
173151
} // eslint-disable-line no-return-assign
174-
reloadApp();
152+
reloadApp(options, status);
175153
},
176154
'content-changed': function contentChanged() {
177155
log.info('[WDS] Content base changed. Reloading...');
@@ -180,42 +158,41 @@ const onSocketMsg = {
180158
warnings(warnings) {
181159
log.warn('[WDS] Warnings while compiling.');
182160
const strippedWarnings = warnings.map((warning) => stripAnsi(warning));
183-
sendMsg('Warnings', strippedWarnings);
161+
sendMessage('Warnings', strippedWarnings);
184162
for (let i = 0; i < strippedWarnings.length; i++) {
185163
log.warn(strippedWarnings[i]);
186164
}
187-
if (useWarningOverlay) {
165+
if (options.useWarningOverlay) {
188166
overlay.showMessage(warnings);
189167
}
190168

191-
if (initial) {
192-
return (initial = false);
169+
if (options.initial) {
170+
return (options.initial = false);
193171
} // eslint-disable-line no-return-assign
194-
reloadApp();
172+
reloadApp(options, status);
195173
},
196174
errors(errors) {
197175
log.error('[WDS] Errors while compiling. Reload prevented.');
198176
const strippedErrors = errors.map((error) => stripAnsi(error));
199-
sendMsg('Errors', strippedErrors);
177+
sendMessage('Errors', strippedErrors);
200178
for (let i = 0; i < strippedErrors.length; i++) {
201179
log.error(strippedErrors[i]);
202180
}
203-
if (useErrorOverlay) {
181+
if (options.useErrorOverlay) {
204182
overlay.showMessage(errors);
205183
}
206-
initial = false;
184+
options.initial = false;
207185
},
208186
error(error) {
209187
log.error(error);
210188
},
211189
close() {
212190
log.error('[WDS] Disconnected!');
213-
sendMsg('Close');
191+
sendMessage('Close');
214192
},
215193
};
216194

217-
let hostname = urlParts.hostname;
218-
let protocol = urlParts.protocol;
195+
let { hostname, protocol } = urlParts;
219196

220197
// check ipv4 and ipv6 `all hostname`
221198
if (hostname === '0.0.0.0' || hostname === '::') {
@@ -270,47 +247,3 @@ const socketUrl = url.format({
270247
});
271248

272249
socket(socketUrl, onSocketMsg);
273-
274-
let isUnloading = false;
275-
self.addEventListener('beforeunload', () => {
276-
isUnloading = true;
277-
});
278-
279-
function reloadApp() {
280-
if (isUnloading || !hotReload) {
281-
return;
282-
}
283-
if (hot) {
284-
log.info('[WDS] App hot update...');
285-
// eslint-disable-next-line global-require
286-
const hotEmitter = require('webpack/hot/emitter');
287-
hotEmitter.emit('webpackHotUpdate', currentHash);
288-
if (typeof self !== 'undefined' && self.window) {
289-
// broadcast update to window
290-
self.postMessage(`webpackHotUpdate${currentHash}`, '*');
291-
}
292-
}
293-
// allow refreshing the page only if liveReload isn't disabled
294-
else if (liveReload) {
295-
let rootWindow = self;
296-
// use parent window for reload (in case we're in an iframe with no valid src)
297-
const intervalId = self.setInterval(() => {
298-
if (rootWindow.location.protocol !== 'about:') {
299-
// reload immediately if protocol is valid
300-
applyReload(rootWindow, intervalId);
301-
} else {
302-
rootWindow = rootWindow.parent;
303-
if (rootWindow.parent === rootWindow) {
304-
// if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways
305-
applyReload(rootWindow, intervalId);
306-
}
307-
}
308-
});
309-
}
310-
311-
function applyReload(rootWindow, intervalId) {
312-
clearInterval(intervalId);
313-
log.info('[WDS] App updated. Reloading...');
314-
rootWindow.location.reload();
315-
}
316-
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
function getCurrentScriptSource() {
4+
// `document.currentScript` is the most accurate way to find the current script,
5+
// but is not supported in all browsers.
6+
if (document.currentScript) {
7+
return document.currentScript.getAttribute('src');
8+
}
9+
// Fall back to getting all scripts in the document.
10+
const scriptElements = document.scripts || [];
11+
const currentScript = scriptElements[scriptElements.length - 1];
12+
13+
if (currentScript) {
14+
return currentScript.getAttribute('src');
15+
}
16+
// Fail as there was no script to use.
17+
throw new Error('[WDS] Failed to get current script source.');
18+
}
19+
20+
module.exports = getCurrentScriptSource;

client-src/default/utils/reloadApp.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
/* global WorkerGlobalScope self */
4+
5+
const log = require('loglevel').getLogger('webpack-dev-server');
6+
7+
function reloadApp(
8+
{ hotReload, hot, liveReload },
9+
{ isUnloading, currentHash }
10+
) {
11+
if (isUnloading || !hotReload) {
12+
return;
13+
}
14+
if (hot) {
15+
log.info('[WDS] App hot update...');
16+
// eslint-disable-next-line global-require
17+
const hotEmitter = require('webpack/hot/emitter');
18+
hotEmitter.emit('webpackHotUpdate', currentHash);
19+
if (typeof self !== 'undefined' && self.window) {
20+
// broadcast update to window
21+
self.postMessage(`webpackHotUpdate${currentHash}`, '*');
22+
}
23+
}
24+
// allow refreshing the page only if liveReload isn't disabled
25+
else if (liveReload) {
26+
let rootWindow = self;
27+
// use parent window for reload (in case we're in an iframe with no valid src)
28+
const intervalId = self.setInterval(() => {
29+
if (rootWindow.location.protocol !== 'about:') {
30+
// reload immediately if protocol is valid
31+
applyReload(rootWindow, intervalId);
32+
} else {
33+
rootWindow = rootWindow.parent;
34+
if (rootWindow.parent === rootWindow) {
35+
// if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways
36+
applyReload(rootWindow, intervalId);
37+
}
38+
}
39+
});
40+
}
41+
42+
function applyReload(rootWindow, intervalId) {
43+
clearInterval(intervalId);
44+
log.info('[WDS] App updated. Reloading...');
45+
rootWindow.location.reload();
46+
}
47+
}
48+
49+
module.exports = reloadApp;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
/* global __resourceQuery WorkerGlobalScope self */
4+
5+
// Send messages to the outside, so plugins can consume it.
6+
function sendMsg(type, data) {
7+
if (
8+
typeof self !== 'undefined' &&
9+
(typeof WorkerGlobalScope === 'undefined' ||
10+
!(self instanceof WorkerGlobalScope))
11+
) {
12+
self.postMessage(
13+
{
14+
type: `webpack${type}`,
15+
data,
16+
},
17+
'*'
18+
);
19+
}
20+
}
21+
22+
module.exports = sendMsg;

test/__snapshots__/Routes.test.js.snap

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`getCurrentScriptSource should fail when script source doesn't exist 1`] = `[Error: [WDS] Failed to get current script source.]`;

0 commit comments

Comments
 (0)