webpack-dev-server 3.6.0 → 3.8.0
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 +56 -0
- package/bin/options.js +4 -1
- package/bin/webpack-dev-server.js +13 -20
- package/client/clients/BaseClient.js +27 -0
- package/client/clients/SockJSClient.js +74 -0
- package/client/clients/WebsocketClient.js +74 -0
- package/client/index.bundle.js +1 -1
- package/client/live.bundle.js +3 -3
- package/client/overlay.js +19 -22
- package/client/socket.js +9 -2
- package/client/sockjs.bundle.js +1 -1
- package/client/utils/createSocketUrl.js +7 -3
- package/client/utils/reloadApp.js +1 -1
- package/lib/Server.js +68 -71
- 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 +49 -5
- package/lib/utils/createConfig.js +7 -2
- package/lib/utils/createLogger.js +1 -1
- package/lib/utils/findPort.js +17 -6
- 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/tryParseInt.js +2 -0
- package/lib/utils/updateCompiler.js +2 -2
- package/package.json +42 -33
- package/lib/clients/BaseClient.js +0 -10
- package/lib/clients/SockJSClient.js +0 -33
- package/lib/clients/WebsocketClient.js +0 -5
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
|
|
|
@@ -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))) {
|
|
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) {
|
|
@@ -694,10 +689,15 @@ class Server {
|
|
|
694
689
|
}
|
|
695
690
|
});
|
|
696
691
|
|
|
692
|
+
if (this.clientLogLevel) {
|
|
693
|
+
this.sockWrite([connection], 'log-level', this.clientLogLevel);
|
|
694
|
+
}
|
|
695
|
+
|
|
697
696
|
if (this.hot) {
|
|
698
697
|
this.sockWrite([connection], 'hot');
|
|
699
698
|
}
|
|
700
699
|
|
|
700
|
+
// TODO: change condition at major version
|
|
701
701
|
if (this.options.liveReload !== false) {
|
|
702
702
|
this.sockWrite([connection], 'liveReload', this.options.liveReload);
|
|
703
703
|
}
|
|
@@ -710,10 +710,6 @@ class Server {
|
|
|
710
710
|
this.sockWrite([connection], 'overlay', this.clientOverlay);
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
-
if (this.clientLogLevel) {
|
|
714
|
-
this.sockWrite([connection], 'log-level', this.clientLogLevel);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
713
|
if (!this._stats) {
|
|
718
714
|
return;
|
|
719
715
|
}
|
|
@@ -853,13 +849,18 @@ class Server {
|
|
|
853
849
|
// an IPv6-address in URLs,
|
|
854
850
|
// these are removed from the hostname in url.parse(),
|
|
855
851
|
// so we have the pure IPv6-address in hostname.
|
|
856
|
-
|
|
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) {
|
|
857
861
|
return true;
|
|
858
862
|
}
|
|
859
863
|
// always allow localhost host, for convenience
|
|
860
|
-
if (hostname === 'localhost') {
|
|
861
|
-
return true;
|
|
862
|
-
}
|
|
863
864
|
// allow if hostname is in allowedHosts
|
|
864
865
|
if (this.allowedHosts && this.allowedHosts.length) {
|
|
865
866
|
for (let hostIdx = 0; hostIdx < this.allowedHosts.length; hostIdx++) {
|
|
@@ -872,23 +873,18 @@ class Server {
|
|
|
872
873
|
// support "." as a subdomain wildcard
|
|
873
874
|
// e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
|
|
874
875
|
if (allowedHost[0] === '.') {
|
|
875
|
-
// "example.com"
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
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
|
+
) {
|
|
881
882
|
return true;
|
|
882
883
|
}
|
|
883
884
|
}
|
|
884
885
|
}
|
|
885
886
|
}
|
|
886
887
|
|
|
887
|
-
// allow hostname of listening address
|
|
888
|
-
if (hostname === this.hostname) {
|
|
889
|
-
return true;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
888
|
// also allow public hostname if provided
|
|
893
889
|
if (typeof this.publicHost === 'string') {
|
|
894
890
|
const idxPublic = this.publicHost.indexOf(':');
|
|
@@ -938,13 +934,14 @@ class Server {
|
|
|
938
934
|
|
|
939
935
|
// send stats to a socket or multiple sockets
|
|
940
936
|
_sendStats(sockets, stats, force) {
|
|
941
|
-
|
|
937
|
+
const shouldEmit =
|
|
942
938
|
!force &&
|
|
943
939
|
stats &&
|
|
944
940
|
(!stats.errors || stats.errors.length === 0) &&
|
|
945
941
|
stats.assets &&
|
|
946
|
-
stats.assets.every((asset) => !asset.emitted)
|
|
947
|
-
|
|
942
|
+
stats.assets.every((asset) => !asset.emitted);
|
|
943
|
+
|
|
944
|
+
if (shouldEmit) {
|
|
948
945
|
return this.sockWrite(sockets, 'still-ok');
|
|
949
946
|
}
|
|
950
947
|
|
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.headers);
|
|
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,38 @@ 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) => {
|
|
113
|
+
/** @type {Boolean} */
|
|
72
114
|
const webTarget =
|
|
73
115
|
config.target === 'web' ||
|
|
74
116
|
config.target === 'webworker' ||
|
|
75
117
|
config.target === 'electron-renderer' ||
|
|
76
118
|
config.target === 'node-webkit' ||
|
|
77
119
|
config.target == null;
|
|
120
|
+
/** @type {Entry} */
|
|
78
121
|
const additionalEntries = checkInject(
|
|
79
122
|
options.injectClient,
|
|
80
123
|
config,
|
|
@@ -93,8 +136,9 @@ function addEntries(config, options, server) {
|
|
|
93
136
|
config.plugins = config.plugins || [];
|
|
94
137
|
if (
|
|
95
138
|
!config.plugins.find(
|
|
96
|
-
|
|
97
|
-
|
|
139
|
+
// Check for the name rather than the constructor reference in case
|
|
140
|
+
// there are multiple copies of webpack installed
|
|
141
|
+
(plugin) => plugin.constructor.name === 'HotModuleReplacementPlugin'
|
|
98
142
|
)
|
|
99
143
|
) {
|
|
100
144
|
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
|
}
|
package/lib/utils/findPort.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const pRetry = require('p-retry');
|
|
4
|
+
const portfinder = require('portfinder');
|
|
4
5
|
const defaultPort = require('./defaultPort');
|
|
5
6
|
const defaultTo = require('./defaultTo');
|
|
6
7
|
const tryParseInt = require('./tryParseInt');
|
|
7
8
|
|
|
9
|
+
function runPortFinder() {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
portfinder.basePort = defaultPort;
|
|
12
|
+
portfinder.getPort((error, port) => {
|
|
13
|
+
if (error) {
|
|
14
|
+
return reject(error);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return resolve(port);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
8
22
|
function findPort(port) {
|
|
9
|
-
if (
|
|
23
|
+
if (port) {
|
|
10
24
|
return Promise.resolve(port);
|
|
11
25
|
}
|
|
12
26
|
|
|
@@ -19,10 +33,7 @@ function findPort(port) {
|
|
|
19
33
|
3
|
|
20
34
|
);
|
|
21
35
|
|
|
22
|
-
return
|
|
23
|
-
port: defaultPort,
|
|
24
|
-
stopPort: defaultPort + defaultPortRetry,
|
|
25
|
-
});
|
|
36
|
+
return pRetry(runPortFinder, { retries: defaultPortRetry });
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
module.exports = findPort;
|