webpack-dev-server 3.7.1 → 3.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -6
- package/bin/options.js +4 -1
- package/bin/webpack-dev-server.js +13 -20
- package/client/clients/SockJSClient.js +5 -0
- package/client/clients/WebsocketClient.js +45 -2
- package/client/index.bundle.js +1 -1
- package/client/live.bundle.js +3 -17
- package/client/overlay.js +19 -22
- package/client/socket.js +9 -2
- package/client/sockjs.bundle.js +1 -1
- package/client/utils/createSocketUrl.js +13 -5
- package/client/utils/reloadApp.js +1 -1
- package/lib/Server.js +67 -76
- package/lib/options.json +32 -12
- package/lib/servers/SockJSServer.js +13 -3
- package/lib/servers/WebsocketServer.js +41 -4
- package/lib/utils/addEntries.js +57 -11
- package/lib/utils/createConfig.js +7 -2
- package/lib/utils/getSocketClientPath.js +37 -0
- package/lib/utils/getSocketServerImplementation.js +8 -7
- package/lib/utils/getVersions.js +0 -2
- package/lib/utils/normalizeOptions.js +38 -0
- package/lib/utils/processOptions.js +16 -1
- package/lib/utils/routes.js +16 -30
- package/lib/utils/runBonjour.js +2 -3
- package/lib/utils/runOpen.js +10 -3
- package/lib/utils/setupExitSignals.js +3 -3
- package/lib/utils/status.js +10 -0
- package/lib/utils/updateCompiler.js +2 -4
- package/package.json +42 -36
package/lib/Server.js
CHANGED
|
@@ -23,6 +23,8 @@ const serveIndex = require('serve-index');
|
|
|
23
23
|
const webpack = require('webpack');
|
|
24
24
|
const webpackDevMiddleware = require('webpack-dev-middleware');
|
|
25
25
|
const validateOptions = require('schema-utils');
|
|
26
|
+
const isAbsoluteUrl = require('is-absolute-url');
|
|
27
|
+
const normalizeOptions = require('./utils/normalizeOptions');
|
|
26
28
|
const updateCompiler = require('./utils/updateCompiler');
|
|
27
29
|
const createLogger = require('./utils/createLogger');
|
|
28
30
|
const getCertificate = require('./utils/getCertificate');
|
|
@@ -54,27 +56,21 @@ class Server {
|
|
|
54
56
|
|
|
55
57
|
validateOptions(schema, options, 'webpack Dev Server');
|
|
56
58
|
|
|
57
|
-
updateCompiler(compiler, options);
|
|
58
|
-
|
|
59
59
|
this.compiler = compiler;
|
|
60
60
|
this.options = options;
|
|
61
61
|
|
|
62
|
-
// Setup default value
|
|
63
|
-
this.options.contentBase =
|
|
64
|
-
this.options.contentBase !== undefined
|
|
65
|
-
? this.options.contentBase
|
|
66
|
-
: process.cwd();
|
|
67
|
-
|
|
68
62
|
this.log = _log || createLogger(options);
|
|
69
63
|
|
|
70
|
-
if (this.options.
|
|
71
|
-
this.options.serverMode = 'sockjs';
|
|
72
|
-
} else {
|
|
64
|
+
if (this.options.transportMode !== undefined) {
|
|
73
65
|
this.log.warn(
|
|
74
|
-
'
|
|
66
|
+
'transportMode is an experimental option, meaning its usage could potentially change without warning'
|
|
75
67
|
);
|
|
76
68
|
}
|
|
77
69
|
|
|
70
|
+
normalizeOptions(this.compiler, this.options);
|
|
71
|
+
|
|
72
|
+
updateCompiler(this.compiler, this.options);
|
|
73
|
+
|
|
78
74
|
// this.SocketServerImplementation is a class, so it must be instantiated before use
|
|
79
75
|
this.socketServerImplementation = getSocketServerImplementation(
|
|
80
76
|
this.options
|
|
@@ -102,10 +98,6 @@ class Server {
|
|
|
102
98
|
this.allowedHosts = this.options.allowedHosts;
|
|
103
99
|
this.disableHostCheck = !!this.options.disableHostCheck;
|
|
104
100
|
|
|
105
|
-
if (!this.options.watchOptions) {
|
|
106
|
-
this.options.watchOptions = {};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
101
|
this.watchOptions = options.watchOptions || {};
|
|
110
102
|
|
|
111
103
|
// Replace leading and trailing slashes to normalize path
|
|
@@ -144,23 +136,25 @@ class Server {
|
|
|
144
136
|
}
|
|
145
137
|
|
|
146
138
|
setupProgressPlugin() {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
139
|
+
// for CLI output
|
|
140
|
+
new webpack.ProgressPlugin({
|
|
141
|
+
profile: !!this.options.profile,
|
|
142
|
+
}).apply(this.compiler);
|
|
150
143
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
144
|
+
// for browser console output
|
|
145
|
+
new webpack.ProgressPlugin((percent, msg, addInfo) => {
|
|
146
|
+
percent = Math.floor(percent * 100);
|
|
154
147
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
if (percent === 100) {
|
|
149
|
+
msg = 'Compilation completed';
|
|
150
|
+
}
|
|
158
151
|
|
|
159
|
-
|
|
152
|
+
if (addInfo) {
|
|
153
|
+
msg = `${msg} (${addInfo})`;
|
|
160
154
|
}
|
|
161
|
-
);
|
|
162
155
|
|
|
163
|
-
|
|
156
|
+
this.sockWrite(this.sockets, 'progress-update', { percent, msg });
|
|
157
|
+
}).apply(this.compiler);
|
|
164
158
|
}
|
|
165
159
|
|
|
166
160
|
setupApp() {
|
|
@@ -280,14 +274,12 @@ class Server {
|
|
|
280
274
|
* ]
|
|
281
275
|
*/
|
|
282
276
|
this.options.proxy.forEach((proxyConfigOrCallback) => {
|
|
283
|
-
let proxyConfig;
|
|
284
277
|
let proxyMiddleware;
|
|
285
278
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
279
|
+
let proxyConfig =
|
|
280
|
+
typeof proxyConfigOrCallback === 'function'
|
|
281
|
+
? proxyConfigOrCallback()
|
|
282
|
+
: proxyConfigOrCallback;
|
|
291
283
|
|
|
292
284
|
proxyMiddleware = getProxyMiddleware(proxyConfig);
|
|
293
285
|
|
|
@@ -307,7 +299,7 @@ class Server {
|
|
|
307
299
|
|
|
308
300
|
// - Check if we have a bypass function defined
|
|
309
301
|
// - In case the bypass function is defined we'll retrieve the
|
|
310
|
-
// bypassUrl from it otherwise
|
|
302
|
+
// bypassUrl from it otherwise bypassUrl would be null
|
|
311
303
|
const isByPassFuncDefined = typeof proxyConfig.bypass === 'function';
|
|
312
304
|
const bypassUrl = isByPassFuncDefined
|
|
313
305
|
? proxyConfig.bypass(req, res, proxyConfig)
|
|
@@ -347,7 +339,7 @@ class Server {
|
|
|
347
339
|
contentBase.forEach((item) => {
|
|
348
340
|
this.app.get('*', express.static(item));
|
|
349
341
|
});
|
|
350
|
-
} else if (
|
|
342
|
+
} else if (isAbsoluteUrl(String(contentBase))) {
|
|
351
343
|
this.log.warn(
|
|
352
344
|
'Using a URL as contentBase is deprecated and will be removed in the next major version. Please use the proxy option instead.'
|
|
353
345
|
);
|
|
@@ -399,8 +391,8 @@ class Server {
|
|
|
399
391
|
this.app.get('*', serveIndex(item));
|
|
400
392
|
});
|
|
401
393
|
} else if (
|
|
402
|
-
|
|
403
|
-
|
|
394
|
+
typeof contentBase !== 'number' &&
|
|
395
|
+
!isAbsoluteUrl(String(contentBase))
|
|
404
396
|
) {
|
|
405
397
|
this.app.get('*', serveIndex(contentBase));
|
|
406
398
|
}
|
|
@@ -409,13 +401,13 @@ class Server {
|
|
|
409
401
|
setupWatchStaticFeature() {
|
|
410
402
|
const contentBase = this.options.contentBase;
|
|
411
403
|
|
|
412
|
-
if (
|
|
413
|
-
/^(https?:)?\/\//.test(contentBase) ||
|
|
414
|
-
typeof contentBase === 'number'
|
|
415
|
-
) {
|
|
404
|
+
if (isAbsoluteUrl(String(contentBase)) || typeof contentBase === 'number') {
|
|
416
405
|
throw new Error('Watching remote files is not supported.');
|
|
417
406
|
} else if (Array.isArray(contentBase)) {
|
|
418
407
|
contentBase.forEach((item) => {
|
|
408
|
+
if (isAbsoluteUrl(String(item)) || typeof item === 'number') {
|
|
409
|
+
throw new Error('Watching remote files is not supported.');
|
|
410
|
+
}
|
|
419
411
|
this._watch(item);
|
|
420
412
|
});
|
|
421
413
|
} else {
|
|
@@ -653,7 +645,6 @@ class Server {
|
|
|
653
645
|
// The relevant issues are:
|
|
654
646
|
// https://github.com/spdy-http2/node-spdy/issues/350
|
|
655
647
|
// https://github.com/webpack/webpack-dev-server/issues/1592
|
|
656
|
-
// eslint-disable-next-line global-require
|
|
657
648
|
this.listeningApp = require('spdy').createServer(
|
|
658
649
|
this.options.https,
|
|
659
650
|
this.app
|
|
@@ -668,25 +659,29 @@ class Server {
|
|
|
668
659
|
const SocketServerImplementation = this.socketServerImplementation;
|
|
669
660
|
this.socketServer = new SocketServerImplementation(this);
|
|
670
661
|
|
|
671
|
-
this.socketServer.onConnection((connection) => {
|
|
662
|
+
this.socketServer.onConnection((connection, headers) => {
|
|
672
663
|
if (!connection) {
|
|
673
664
|
return;
|
|
674
665
|
}
|
|
675
666
|
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
667
|
+
if (!headers) {
|
|
668
|
+
this.log.warn(
|
|
669
|
+
'transportMode.server implementation must pass headers to the callback of onConnection(f) ' +
|
|
670
|
+
'via f(connection, headers) in order for clients to pass a headers security check'
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (!headers || !this.checkHost(headers) || !this.checkOrigin(headers)) {
|
|
680
675
|
this.sockWrite([connection], 'error', 'Invalid Host/Origin header');
|
|
681
676
|
|
|
682
|
-
|
|
677
|
+
this.socketServer.close(connection);
|
|
683
678
|
|
|
684
679
|
return;
|
|
685
680
|
}
|
|
686
681
|
|
|
687
682
|
this.sockets.push(connection);
|
|
688
683
|
|
|
689
|
-
|
|
684
|
+
this.socketServer.onConnectionClose(connection, () => {
|
|
690
685
|
const idx = this.sockets.indexOf(connection);
|
|
691
686
|
|
|
692
687
|
if (idx >= 0) {
|
|
@@ -854,13 +849,18 @@ class Server {
|
|
|
854
849
|
// an IPv6-address in URLs,
|
|
855
850
|
// these are removed from the hostname in url.parse(),
|
|
856
851
|
// so we have the pure IPv6-address in hostname.
|
|
857
|
-
|
|
852
|
+
// always allow localhost host, for convenience (hostname === 'localhost')
|
|
853
|
+
// allow hostname of listening address (hostname === this.hostname)
|
|
854
|
+
const isValidHostname =
|
|
855
|
+
ip.isV4Format(hostname) ||
|
|
856
|
+
ip.isV6Format(hostname) ||
|
|
857
|
+
hostname === 'localhost' ||
|
|
858
|
+
hostname === this.hostname;
|
|
859
|
+
|
|
860
|
+
if (isValidHostname) {
|
|
858
861
|
return true;
|
|
859
862
|
}
|
|
860
863
|
// always allow localhost host, for convenience
|
|
861
|
-
if (hostname === 'localhost') {
|
|
862
|
-
return true;
|
|
863
|
-
}
|
|
864
864
|
// allow if hostname is in allowedHosts
|
|
865
865
|
if (this.allowedHosts && this.allowedHosts.length) {
|
|
866
866
|
for (let hostIdx = 0; hostIdx < this.allowedHosts.length; hostIdx++) {
|
|
@@ -873,23 +873,18 @@ class Server {
|
|
|
873
873
|
// support "." as a subdomain wildcard
|
|
874
874
|
// e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
|
|
875
875
|
if (allowedHost[0] === '.') {
|
|
876
|
-
// "example.com"
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
876
|
+
// "example.com" (hostname === allowedHost.substring(1))
|
|
877
|
+
// "*.example.com" (hostname.endsWith(allowedHost))
|
|
878
|
+
if (
|
|
879
|
+
hostname === allowedHost.substring(1) ||
|
|
880
|
+
hostname.endsWith(allowedHost)
|
|
881
|
+
) {
|
|
882
882
|
return true;
|
|
883
883
|
}
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
886
|
}
|
|
887
887
|
|
|
888
|
-
// allow hostname of listening address
|
|
889
|
-
if (hostname === this.hostname) {
|
|
890
|
-
return true;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
888
|
// also allow public hostname if provided
|
|
894
889
|
if (typeof this.publicHost === 'string') {
|
|
895
890
|
const idxPublic = this.publicHost.indexOf(':');
|
|
@@ -924,14 +919,9 @@ class Server {
|
|
|
924
919
|
return next();
|
|
925
920
|
}
|
|
926
921
|
// Serve a page that executes the javascript
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
);
|
|
930
|
-
res.write(_path);
|
|
931
|
-
res.write('.js');
|
|
932
|
-
res.write(req._parsedUrl.search || '');
|
|
933
|
-
|
|
934
|
-
res.end('"></script></body></html>');
|
|
922
|
+
const queries = req._parsedUrl.search || '';
|
|
923
|
+
const responsePage = `<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body><script type="text/javascript" charset="utf-8" src="${_path}.js${queries}"></script></body></html>`;
|
|
924
|
+
res.send(responsePage);
|
|
935
925
|
} catch (err) {
|
|
936
926
|
return next();
|
|
937
927
|
}
|
|
@@ -939,13 +929,14 @@ class Server {
|
|
|
939
929
|
|
|
940
930
|
// send stats to a socket or multiple sockets
|
|
941
931
|
_sendStats(sockets, stats, force) {
|
|
942
|
-
|
|
932
|
+
const shouldEmit =
|
|
943
933
|
!force &&
|
|
944
934
|
stats &&
|
|
945
935
|
(!stats.errors || stats.errors.length === 0) &&
|
|
946
936
|
stats.assets &&
|
|
947
|
-
stats.assets.every((asset) => !asset.emitted)
|
|
948
|
-
|
|
937
|
+
stats.assets.every((asset) => !asset.emitted);
|
|
938
|
+
|
|
939
|
+
if (shouldEmit) {
|
|
949
940
|
return this.sockWrite(sockets, 'still-ok');
|
|
950
941
|
}
|
|
951
942
|
|
package/lib/options.json
CHANGED
|
@@ -255,6 +255,9 @@
|
|
|
255
255
|
}
|
|
256
256
|
]
|
|
257
257
|
},
|
|
258
|
+
"profile": {
|
|
259
|
+
"type": "boolean"
|
|
260
|
+
},
|
|
258
261
|
"progress": {
|
|
259
262
|
"type": "boolean"
|
|
260
263
|
},
|
|
@@ -297,16 +300,6 @@
|
|
|
297
300
|
"serveIndex": {
|
|
298
301
|
"type": "boolean"
|
|
299
302
|
},
|
|
300
|
-
"serverMode": {
|
|
301
|
-
"anyOf": [
|
|
302
|
-
{
|
|
303
|
-
"type": "string"
|
|
304
|
-
},
|
|
305
|
-
{
|
|
306
|
-
"instanceof": "Function"
|
|
307
|
-
}
|
|
308
|
-
]
|
|
309
|
-
},
|
|
310
303
|
"serverSideRender": {
|
|
311
304
|
"type": "boolean"
|
|
312
305
|
},
|
|
@@ -358,6 +351,32 @@
|
|
|
358
351
|
}
|
|
359
352
|
]
|
|
360
353
|
},
|
|
354
|
+
"transportMode": {
|
|
355
|
+
"anyOf": [
|
|
356
|
+
{
|
|
357
|
+
"type": "object",
|
|
358
|
+
"properties": {
|
|
359
|
+
"client": {
|
|
360
|
+
"type": "string"
|
|
361
|
+
},
|
|
362
|
+
"server": {
|
|
363
|
+
"anyOf": [
|
|
364
|
+
{
|
|
365
|
+
"type": "string"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"instanceof": "Function"
|
|
369
|
+
}
|
|
370
|
+
]
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
"additionalProperties": false
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"enum": ["sockjs", "ws"]
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
},
|
|
361
380
|
"useLocalIp": {
|
|
362
381
|
"type": "boolean"
|
|
363
382
|
},
|
|
@@ -389,7 +408,7 @@
|
|
|
389
408
|
"bonjour": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverbonjour)",
|
|
390
409
|
"ca": "should be {String|Buffer}",
|
|
391
410
|
"cert": "should be {String|Buffer}",
|
|
392
|
-
"clientLogLevel": "should be {String} and equal to one of the allowed values\n\n [ '
|
|
411
|
+
"clientLogLevel": "should be {String} and equal to one of the allowed values\n\n [ 'none', 'silent', 'info', 'debug', 'trace', 'error', 'warning', 'warn' ]\n\n (https://webpack.js.org/configuration/dev-server/#devserverclientloglevel)",
|
|
393
412
|
"compress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devservercompress)",
|
|
394
413
|
"contentBase": "should be {Number|String|Array} (https://webpack.js.org/configuration/dev-server/#devservercontentbase)",
|
|
395
414
|
"disableHostCheck": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck)",
|
|
@@ -422,6 +441,7 @@
|
|
|
422
441
|
"pfx": "should be {String|Buffer} (https://webpack.js.org/configuration/dev-server/#devserverpfx)",
|
|
423
442
|
"pfxPassphrase": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpfxpassphrase)",
|
|
424
443
|
"port": "should be {Number|String|Null} (https://webpack.js.org/configuration/dev-server/#devserverport)",
|
|
444
|
+
"profile": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprofile)",
|
|
425
445
|
"progress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprogress---cli-only)",
|
|
426
446
|
"proxy": "should be {Object|Array} (https://webpack.js.org/configuration/dev-server/#devserverproxy)",
|
|
427
447
|
"public": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpublic)",
|
|
@@ -430,7 +450,6 @@
|
|
|
430
450
|
"reporter": "should be {Function} (https://github.com/webpack/webpack-dev-middleware#reporter)",
|
|
431
451
|
"requestCert": "should be {Boolean}",
|
|
432
452
|
"serveIndex": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverserveindex)",
|
|
433
|
-
"serverMode": "should be {String|Function} (https://webpack.js.org/configuration/dev-server/#devserverservermode-)",
|
|
434
453
|
"serverSideRender": "should be {Boolean} (https://github.com/webpack/webpack-dev-middleware#serversiderender)",
|
|
435
454
|
"setup": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserversetup)",
|
|
436
455
|
"sockHost": "should be {String|Null} (https://webpack.js.org/configuration/dev-server/#devserversockhost)",
|
|
@@ -439,6 +458,7 @@
|
|
|
439
458
|
"socket": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserversocket)",
|
|
440
459
|
"staticOptions": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverstaticoptions)",
|
|
441
460
|
"stats": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverstats-)",
|
|
461
|
+
"transportMode": "should be {String|Object} (https://webpack.js.org/configuration/dev-server/#devservertransportmode)",
|
|
442
462
|
"useLocalIp": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserveruselocalip)",
|
|
443
463
|
"warn": "should be {Function}",
|
|
444
464
|
"watchContentBase": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverwatchcontentbase)",
|
|
@@ -11,7 +11,6 @@ const BaseServer = require('./BaseServer');
|
|
|
11
11
|
// sockjs will remove Origin header, however Origin header is required for checking host.
|
|
12
12
|
// See https://github.com/webpack/webpack-dev-server/issues/1604 for more information
|
|
13
13
|
{
|
|
14
|
-
// eslint-disable-next-line global-require
|
|
15
14
|
const SockjsSession = require('sockjs/lib/transport').Session;
|
|
16
15
|
const decorateConnection = SockjsSession.prototype.decorateConnection;
|
|
17
16
|
SockjsSession.prototype.decorateConnection = function(req) {
|
|
@@ -50,6 +49,11 @@ module.exports = class SockJSServer extends BaseServer {
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
send(connection, message) {
|
|
52
|
+
// prevent cases where the server is trying to send data while connection is closing
|
|
53
|
+
if (connection.readyState !== 1) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
53
57
|
connection.write(message);
|
|
54
58
|
}
|
|
55
59
|
|
|
@@ -57,8 +61,14 @@ module.exports = class SockJSServer extends BaseServer {
|
|
|
57
61
|
connection.close();
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
// f should
|
|
64
|
+
// f should be passed the resulting connection and the connection headers
|
|
61
65
|
onConnection(f) {
|
|
62
|
-
this.socket.on('connection',
|
|
66
|
+
this.socket.on('connection', (connection) => {
|
|
67
|
+
f(connection, connection ? connection.headers : null);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onConnectionClose(connection, f) {
|
|
72
|
+
connection.on('close', f);
|
|
63
73
|
}
|
|
64
74
|
};
|
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/* eslint-disable
|
|
4
|
+
class-methods-use-this
|
|
5
|
+
*/
|
|
6
|
+
const ws = require('ws');
|
|
4
7
|
const BaseServer = require('./BaseServer');
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
module.exports = class WebsocketServer extends BaseServer {
|
|
10
|
+
constructor(server) {
|
|
11
|
+
super(server);
|
|
12
|
+
this.wsServer = new ws.Server({
|
|
13
|
+
server: this.server.listeningApp,
|
|
14
|
+
path: this.server.sockPath,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
this.wsServer.on('error', (err) => {
|
|
18
|
+
this.server.log.error(err.message);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
send(connection, message) {
|
|
23
|
+
// prevent cases where the server is trying to send data while connection is closing
|
|
24
|
+
if (connection.readyState !== 1) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
connection.send(message);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
close(connection) {
|
|
32
|
+
connection.close();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// f should be passed the resulting connection and the connection headers
|
|
36
|
+
onConnection(f) {
|
|
37
|
+
this.wsServer.on('connection', (connection, req) => {
|
|
38
|
+
f(connection, req.headers);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onConnectionClose(connection, f) {
|
|
43
|
+
connection.on('close', f);
|
|
44
|
+
}
|
|
45
|
+
};
|
package/lib/utils/addEntries.js
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
const webpack = require('webpack');
|
|
4
4
|
const createDomain = require('./createDomain');
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* A Entry, it can be of type string or string[] or Object<string | string[],string>
|
|
8
|
+
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Add entries Method
|
|
13
|
+
* @param {?Object} config - Webpack config
|
|
14
|
+
* @param {?Object} options - Dev-Server options
|
|
15
|
+
* @param {?Object} server
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
6
18
|
function addEntries(config, options, server) {
|
|
7
19
|
if (options.inline !== false) {
|
|
8
20
|
// we're stubbing the app in this method as it's static and doesn't require
|
|
@@ -15,13 +27,20 @@ function addEntries(config, options, server) {
|
|
|
15
27
|
},
|
|
16
28
|
};
|
|
17
29
|
|
|
30
|
+
/** @type {string} */
|
|
18
31
|
const domain = createDomain(options, app);
|
|
32
|
+
/** @type {string} */
|
|
19
33
|
const sockHost = options.sockHost ? `&sockHost=${options.sockHost}` : '';
|
|
34
|
+
/** @type {string} */
|
|
20
35
|
const sockPath = options.sockPath ? `&sockPath=${options.sockPath}` : '';
|
|
36
|
+
/** @type {string} */
|
|
21
37
|
const sockPort = options.sockPort ? `&sockPort=${options.sockPort}` : '';
|
|
38
|
+
/** @type {string} */
|
|
22
39
|
const clientEntry = `${require.resolve(
|
|
23
40
|
'../../client/'
|
|
24
41
|
)}?${domain}${sockHost}${sockPath}${sockPort}`;
|
|
42
|
+
|
|
43
|
+
/** @type {(string[] | string)} */
|
|
25
44
|
let hotEntry;
|
|
26
45
|
|
|
27
46
|
if (options.hotOnly) {
|
|
@@ -29,7 +48,12 @@ function addEntries(config, options, server) {
|
|
|
29
48
|
} else if (options.hot) {
|
|
30
49
|
hotEntry = require.resolve('webpack/hot/dev-server');
|
|
31
50
|
}
|
|
32
|
-
|
|
51
|
+
/**
|
|
52
|
+
* prependEntry Method
|
|
53
|
+
* @param {Entry} originalEntry
|
|
54
|
+
* @param {Entry} additionalEntries
|
|
55
|
+
* @returns {Entry}
|
|
56
|
+
*/
|
|
33
57
|
const prependEntry = (originalEntry, additionalEntries) => {
|
|
34
58
|
if (typeof originalEntry === 'function') {
|
|
35
59
|
return () =>
|
|
@@ -39,6 +63,7 @@ function addEntries(config, options, server) {
|
|
|
39
63
|
}
|
|
40
64
|
|
|
41
65
|
if (typeof originalEntry === 'object' && !Array.isArray(originalEntry)) {
|
|
66
|
+
/** @type {Object<string,string>} */
|
|
42
67
|
const clone = {};
|
|
43
68
|
|
|
44
69
|
Object.keys(originalEntry).forEach((key) => {
|
|
@@ -51,6 +76,7 @@ function addEntries(config, options, server) {
|
|
|
51
76
|
|
|
52
77
|
// in this case, entry is a string or an array.
|
|
53
78
|
// make sure that we do not add duplicates.
|
|
79
|
+
/** @type {Entry} */
|
|
54
80
|
const entriesClone = additionalEntries.slice(0);
|
|
55
81
|
[].concat(originalEntry).forEach((newEntry) => {
|
|
56
82
|
if (!entriesClone.includes(newEntry)) {
|
|
@@ -60,21 +86,40 @@ function addEntries(config, options, server) {
|
|
|
60
86
|
return entriesClone;
|
|
61
87
|
};
|
|
62
88
|
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* Description of the option for checkInject method
|
|
92
|
+
* @typedef {Function} checkInjectOptionsParam
|
|
93
|
+
* @param {Object} _config - compilerConfig
|
|
94
|
+
* @return {Boolean}
|
|
95
|
+
*/
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
*
|
|
99
|
+
* @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
|
|
100
|
+
* @param {Object} _config
|
|
101
|
+
* @param {Boolean} defaultValue
|
|
102
|
+
* @return {Boolean}
|
|
103
|
+
*/
|
|
63
104
|
// eslint-disable-next-line no-shadow
|
|
64
|
-
const checkInject = (option,
|
|
105
|
+
const checkInject = (option, _config, defaultValue) => {
|
|
65
106
|
if (typeof option === 'boolean') return option;
|
|
66
|
-
if (typeof option === 'function') return option(
|
|
107
|
+
if (typeof option === 'function') return option(_config);
|
|
67
108
|
return defaultValue;
|
|
68
109
|
};
|
|
69
110
|
|
|
70
111
|
// eslint-disable-next-line no-shadow
|
|
71
112
|
[].concat(config).forEach((config) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
113
|
+
/** @type {Boolean} */
|
|
114
|
+
const webTarget = [
|
|
115
|
+
'web',
|
|
116
|
+
'webworker',
|
|
117
|
+
'electron-renderer',
|
|
118
|
+
'node-webkit',
|
|
119
|
+
undefined, // eslint-disable-line
|
|
120
|
+
null,
|
|
121
|
+
].includes(config.target);
|
|
122
|
+
/** @type {Entry} */
|
|
78
123
|
const additionalEntries = checkInject(
|
|
79
124
|
options.injectClient,
|
|
80
125
|
config,
|
|
@@ -93,8 +138,9 @@ function addEntries(config, options, server) {
|
|
|
93
138
|
config.plugins = config.plugins || [];
|
|
94
139
|
if (
|
|
95
140
|
!config.plugins.find(
|
|
96
|
-
|
|
97
|
-
|
|
141
|
+
// Check for the name rather than the constructor reference in case
|
|
142
|
+
// there are multiple copies of webpack installed
|
|
143
|
+
(plugin) => plugin.constructor.name === 'HotModuleReplacementPlugin'
|
|
98
144
|
)
|
|
99
145
|
) {
|
|
100
146
|
config.plugins.push(new webpack.HotModuleReplacementPlugin());
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const isAbsoluteUrl = require('is-absolute-url');
|
|
4
5
|
const defaultTo = require('./defaultTo');
|
|
5
6
|
|
|
6
7
|
function createConfig(config, argv, { port }) {
|
|
@@ -46,6 +47,10 @@ function createConfig(config, argv, { port }) {
|
|
|
46
47
|
options.liveReload = false;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
if (argv.profile) {
|
|
51
|
+
options.profile = argv.profile;
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
if (argv.progress) {
|
|
50
55
|
options.progress = argv.progress;
|
|
51
56
|
}
|
|
@@ -60,7 +65,7 @@ function createConfig(config, argv, { port }) {
|
|
|
60
65
|
(firstWpOpt.output && firstWpOpt.output.publicPath) || '';
|
|
61
66
|
|
|
62
67
|
if (
|
|
63
|
-
|
|
68
|
+
!isAbsoluteUrl(String(options.publicPath)) &&
|
|
64
69
|
options.publicPath[0] !== '/'
|
|
65
70
|
) {
|
|
66
71
|
options.publicPath = `/${options.publicPath}`;
|
|
@@ -109,7 +114,7 @@ function createConfig(config, argv, { port }) {
|
|
|
109
114
|
options.contentBase = options.contentBase.map((p) => path.resolve(p));
|
|
110
115
|
} else if (/^[0-9]$/.test(options.contentBase)) {
|
|
111
116
|
options.contentBase = +options.contentBase;
|
|
112
|
-
} else if (
|
|
117
|
+
} else if (!isAbsoluteUrl(String(options.contentBase))) {
|
|
113
118
|
options.contentBase = path.resolve(options.contentBase);
|
|
114
119
|
}
|
|
115
120
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function getSocketClientPath(options) {
|
|
4
|
+
let ClientImplementation;
|
|
5
|
+
let clientImplFound = true;
|
|
6
|
+
switch (typeof options.transportMode.client) {
|
|
7
|
+
case 'string':
|
|
8
|
+
// could be 'sockjs', 'ws', or a path that should be required
|
|
9
|
+
if (options.transportMode.client === 'sockjs') {
|
|
10
|
+
ClientImplementation = require('../../client/clients/SockJSClient');
|
|
11
|
+
} else if (options.transportMode.client === 'ws') {
|
|
12
|
+
ClientImplementation = require('../../client/clients/WebsocketClient');
|
|
13
|
+
} else {
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
16
|
+
ClientImplementation = require(options.transportMode.client);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
clientImplFound = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
clientImplFound = false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!clientImplFound) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"transportMode.client must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to " +
|
|
29
|
+
'a JS file which exports a class extending BaseClient (webpack-dev-server/client-src/clients/BaseClient) ' +
|
|
30
|
+
'via require.resolve(...)'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return ClientImplementation.getClientPath(options);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = getSocketClientPath;
|