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/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.serverMode === undefined) {
71
- this.options.serverMode = 'sockjs';
72
- } else {
64
+ if (this.options.transportMode !== undefined) {
73
65
  this.log.warn(
74
- 'serverMode is an experimental option, meaning its usage could potentially change without warning'
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
- const progressPlugin = new webpack.ProgressPlugin(
148
- (percent, msg, addInfo) => {
149
- percent = Math.floor(percent * 100);
139
+ // for CLI output
140
+ new webpack.ProgressPlugin({
141
+ profile: !!this.options.profile,
142
+ }).apply(this.compiler);
150
143
 
151
- if (percent === 100) {
152
- msg = 'Compilation completed';
153
- }
144
+ // for browser console output
145
+ new webpack.ProgressPlugin((percent, msg, addInfo) => {
146
+ percent = Math.floor(percent * 100);
154
147
 
155
- if (addInfo) {
156
- msg = `${msg} (${addInfo})`;
157
- }
148
+ if (percent === 100) {
149
+ msg = 'Compilation completed';
150
+ }
158
151
 
159
- this.sockWrite(this.sockets, 'progress-update', { percent, msg });
152
+ if (addInfo) {
153
+ msg = `${msg} (${addInfo})`;
160
154
  }
161
- );
162
155
 
163
- progressPlugin.apply(this.compiler);
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
- if (typeof proxyConfigOrCallback === 'function') {
287
- proxyConfig = proxyConfigOrCallback();
288
- } else {
289
- proxyConfig = proxyConfigOrCallback;
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 (/^(https?:)?\/\//.test(contentBase)) {
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
- !/^(https?:)?\/\//.test(contentBase) &&
403
- typeof contentBase !== 'number'
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
- !this.checkHost(connection.headers) ||
678
- !this.checkOrigin(connection.headers)
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
- connection.close();
677
+ this.socketServer.close(connection);
683
678
 
684
679
  return;
685
680
  }
686
681
 
687
682
  this.sockets.push(connection);
688
683
 
689
- connection.on('close', () => {
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
- if (ip.isV4Format(hostname) || ip.isV6Format(hostname)) {
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
- if (hostname === allowedHost.substring(1)) {
877
- return true;
878
- }
879
- // "*.example.com"
880
- if (hostname.endsWith(allowedHost)) {
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
- if (
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 [ 'info', 'warn', 'error', 'debug', 'trace', 'silent' ]\n\n (https://webpack.js.org/configuration/dev-server/#devserverclientloglevel)",
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 return the resulting connection
64
+ // f should be passed the resulting connection and the connection headers
61
65
  onConnection(f) {
62
- this.socket.on('connection', f);
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
- // const ws = require('ws');
3
+ /* eslint-disable
4
+ class-methods-use-this
5
+ */
6
+ const ws = require('ws');
4
7
  const BaseServer = require('./BaseServer');
5
8
 
6
- // ws server implementation under construction
7
- // will need changes in the client as well to function
8
- module.exports = class WebsocketServer extends BaseServer {};
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
+ };
@@ -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, config, defaultValue) => {
105
+ const checkInject = (option, _config, defaultValue) => {
65
106
  if (typeof option === 'boolean') return option;
66
- if (typeof option === 'function') return option(config);
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
- (plugin) =>
97
- plugin.constructor === webpack.HotModuleReplacementPlugin
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
- !/^(https?:)?\/\//.test(options.publicPath) &&
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 (!/^(https?:)?\/\//.test(options.contentBase)) {
117
+ } else if (!isAbsoluteUrl(String(options.contentBase))) {
113
118
  options.contentBase = path.resolve(options.contentBase);
114
119
  }
115
120
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const log = require('webpack-log');
4
4
 
5
- function createLogger(options) {
5
+ function createLogger(options = {}) {
6
6
  let level = options.logLevel || 'info';
7
7
 
8
8
  if (options.noInfo === true) {
@@ -1,12 +1,26 @@
1
1
  'use strict';
2
2
 
3
- const { getPortPromise } = require('portfinder');
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 (typeof port !== 'undefined') {
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 getPortPromise({
23
- port: defaultPort,
24
- stopPort: defaultPort + defaultPortRetry,
25
- });
36
+ return pRetry(runPortFinder, { retries: defaultPortRetry });
26
37
  }
27
38
 
28
39
  module.exports = findPort;