webpack-dev-server 4.7.4 → 4.9.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/client/overlay.js CHANGED
@@ -23,9 +23,24 @@ var containerElement;
23
23
  /** @type {Array<(element: HTMLDivElement) => void>} */
24
24
 
25
25
  var onLoadQueue = [];
26
+ /** @type {TrustedTypePolicy | undefined} */
27
+
28
+ var overlayTrustedTypesPolicy;
26
29
  ansiHTML.setColors(colors);
30
+ /**
31
+ * @param {string | null} trustedTypesPolicyName
32
+ */
33
+
34
+ function createContainer(trustedTypesPolicyName) {
35
+ // Enable Trusted Types if they are available in the current browser.
36
+ if (window.trustedTypes) {
37
+ overlayTrustedTypesPolicy = window.trustedTypes.createPolicy(trustedTypesPolicyName || "webpack-dev-server#overlay", {
38
+ createHTML: function createHTML(value) {
39
+ return value;
40
+ }
41
+ });
42
+ }
27
43
 
28
- function createContainer() {
29
44
  iframeContainerElement = document.createElement("iframe");
30
45
  iframeContainerElement.id = "webpack-dev-server-client-overlay";
31
46
  iframeContainerElement.src = "about:blank";
@@ -101,10 +116,11 @@ function createContainer() {
101
116
  }
102
117
  /**
103
118
  * @param {(element: HTMLDivElement) => void} callback
119
+ * @param {string | null} trustedTypesPolicyName
104
120
  */
105
121
 
106
122
 
107
- function ensureOverlayExists(callback) {
123
+ function ensureOverlayExists(callback, trustedTypesPolicyName) {
108
124
  if (containerElement) {
109
125
  // Everything is ready, call the callback right away.
110
126
  callback(containerElement);
@@ -117,7 +133,7 @@ function ensureOverlayExists(callback) {
117
133
  return;
118
134
  }
119
135
 
120
- createContainer();
136
+ createContainer(trustedTypesPolicyName);
121
137
  } // Successful compilation.
122
138
 
123
139
 
@@ -162,10 +178,11 @@ function formatProblem(type, item) {
162
178
  /**
163
179
  * @param {string} type
164
180
  * @param {Array<string | { file?: string, moduleName?: string, loc?: string, message?: string }>} messages
181
+ * @param {string | null} trustedTypesPolicyName
165
182
  */
166
183
 
167
184
 
168
- function show(type, messages) {
185
+ function show(type, messages, trustedTypesPolicyName) {
169
186
  ensureOverlayExists(function () {
170
187
  messages.forEach(function (message) {
171
188
  var entryElement = document.createElement("div");
@@ -180,7 +197,7 @@ function show(type, messages) {
180
197
 
181
198
  var text = ansiHTML(encode(body));
182
199
  var messageTextNode = document.createElement("div");
183
- messageTextNode.innerHTML = text;
200
+ messageTextNode.innerHTML = overlayTrustedTypesPolicy ? overlayTrustedTypesPolicy.createHTML(text) : text;
184
201
  entryElement.appendChild(typeElement);
185
202
  entryElement.appendChild(document.createElement("br"));
186
203
  entryElement.appendChild(document.createElement("br"));
@@ -191,7 +208,7 @@ function show(type, messages) {
191
208
 
192
209
  containerElement.appendChild(entryElement);
193
210
  });
194
- });
211
+ }, trustedTypesPolicyName);
195
212
  }
196
213
 
197
214
  export { formatProblem, show, hide };
package/client/socket.js CHANGED
@@ -9,8 +9,11 @@ typeof __webpack_dev_server_client__ !== "undefined" ? typeof __webpack_dev_serv
9
9
  /* eslint-enable camelcase */
10
10
 
11
11
  var retries = 0;
12
- var maxRetries = 10;
13
- var client = null;
12
+ var maxRetries = 10; // Initialized client is exported so external consumers can utilize the same instance
13
+ // It is mutable to enforce singleton
14
+ // eslint-disable-next-line import/no-mutable-exports
15
+
16
+ export var client = null;
14
17
  /**
15
18
  * @param {string} url
16
19
  * @param {{ [handler: string]: (data?: any, params?: any) => any }} handlers
@@ -9,7 +9,7 @@ function parseURL(resourceQuery) {
9
9
  var options = {};
10
10
 
11
11
  if (typeof resourceQuery === "string" && resourceQuery !== "") {
12
- var searchParams = resourceQuery.substr(1).split("&");
12
+ var searchParams = resourceQuery.slice(1).split("&");
13
13
 
14
14
  for (var i = 0; i < searchParams.length; i++) {
15
15
  var pair = searchParams[i].split("=");
@@ -0,0 +1,20 @@
1
+ var ansiRegex = new RegExp(["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|"), "g");
2
+ /**
3
+ *
4
+ * Strip [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) from a string.
5
+ * Adapted from code originally released by Sindre Sorhus
6
+ * Licensed the MIT License
7
+ *
8
+ * @param {string} string
9
+ * @return {string}
10
+ */
11
+
12
+ function stripAnsi(string) {
13
+ if (typeof string !== "string") {
14
+ throw new TypeError("Expected a `string`, got `".concat(typeof string, "`"));
15
+ }
16
+
17
+ return string.replace(ansiRegex, "");
18
+ }
19
+
20
+ export default stripAnsi;
package/lib/Server.js CHANGED
@@ -25,12 +25,11 @@ const schema = require("./options.json");
25
25
  /** @typedef {import("express").NextFunction} NextFunction */
26
26
  /** @typedef {import("express").RequestHandler} ExpressRequestHandler */
27
27
  /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
28
- /** @typedef {import("anymatch").Matcher} AnymatchMatcher */
29
28
  /** @typedef {import("chokidar").WatchOptions} WatchOptions */
30
29
  /** @typedef {import("chokidar").FSWatcher} FSWatcher */
31
30
  /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
32
- /** @typedef {import("bonjour").Bonjour} Bonjour */
33
- /** @typedef {import("bonjour").BonjourOptions} BonjourOptions */
31
+ /** @typedef {import("bonjour-service").Bonjour} Bonjour */
32
+ /** @typedef {import("bonjour-service").Service} BonjourOptions */
34
33
  /** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */
35
34
  /** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */
36
35
  /** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */
@@ -65,7 +64,7 @@ const schema = require("./options.json");
65
64
  /**
66
65
  * @typedef {Object} WatchFiles
67
66
  * @property {string | string[]} paths
68
- * @property {WatchOptions & { aggregateTimeout?: number, ignored?: AnymatchMatcher | string[], poll?: number | boolean }} [options]
67
+ * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
69
68
  */
70
69
 
71
70
  /**
@@ -74,7 +73,7 @@ const schema = require("./options.json");
74
73
  * @property {string | string[]} [publicPath]
75
74
  * @property {boolean | ServeIndexOptions} [serveIndex]
76
75
  * @property {ServeStaticOptions} [staticOptions]
77
- * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: AnymatchMatcher | string[], poll?: number | boolean }} [watch]
76
+ * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
78
77
  */
79
78
 
80
79
  /**
@@ -188,7 +187,7 @@ const schema = require("./options.json");
188
187
  * @property {"auto" | "all" | string | string[]} [allowedHosts]
189
188
  * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
190
189
  * @property {boolean} [setupExitSignals]
191
- * @property {boolean | BonjourOptions} [bonjour]
190
+ * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
192
191
  * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
193
192
  * @property {boolean | string | Static | Array<string | Static>} [static]
194
193
  * @property {boolean | ServerOptions} [https]
@@ -386,17 +385,17 @@ class Server {
386
385
 
387
386
  /**
388
387
  * @param {Port} port
388
+ * @param {string} host
389
389
  * @returns {Promise<number | string>}
390
390
  */
391
- static async getFreePort(port) {
391
+ static async getFreePort(port, host) {
392
392
  if (typeof port !== "undefined" && port !== null && port !== "auto") {
393
393
  return port;
394
394
  }
395
395
 
396
396
  const pRetry = require("p-retry");
397
- const portfinder = require("portfinder");
398
-
399
- portfinder.basePort =
397
+ const getPort = require("./getPort");
398
+ const basePort =
400
399
  typeof process.env.WEBPACK_DEV_SERVER_BASE_PORT !== "undefined"
401
400
  ? parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
402
401
  : 8080;
@@ -408,7 +407,7 @@ class Server {
408
407
  ? parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
409
408
  : 3;
410
409
 
411
- return pRetry(() => portfinder.getPortPromise(), {
410
+ return pRetry(() => getPort(basePort, host), {
412
411
  retries: defaultPortRetry,
413
412
  });
414
413
  }
@@ -755,7 +754,7 @@ class Server {
755
754
  // TODO remove `{}` after drop webpack v4 support
756
755
  const compilerWatchOptions = compilerOptions.watchOptions || {};
757
756
  /**
758
- * @param {WatchOptions & { aggregateTimeout?: number, ignored?: AnymatchMatcher | string[], poll?: number | boolean }} watchOptions
757
+ * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions
759
758
  * @returns {WatchOptions}
760
759
  */
761
760
  const getWatchOptions = (watchOptions = {}) => {
@@ -1133,13 +1132,15 @@ class Server {
1133
1132
 
1134
1133
  // cert is more than 30 days old, kill it with fire
1135
1134
  if ((now - Number(certificateStat.ctime)) / certificateTtl > 30) {
1136
- const del = require("del");
1135
+ const { promisify } = require("util");
1136
+ const rimraf = require("rimraf");
1137
+ const del = promisify(rimraf);
1137
1138
 
1138
1139
  this.logger.info(
1139
1140
  "SSL certificate is more than 30 days old. Removing..."
1140
1141
  );
1141
1142
 
1142
- await del([certificatePath], { force: true });
1143
+ await del(certificatePath);
1143
1144
 
1144
1145
  certificateExists = false;
1145
1146
  }
@@ -2592,14 +2593,18 @@ class Server {
2592
2593
  * @returns {void}
2593
2594
  */
2594
2595
  runBonjour() {
2596
+ const { Bonjour } = require("bonjour-service");
2595
2597
  /**
2596
2598
  * @private
2597
- * @type {import("bonjour").Bonjour | undefined}
2599
+ * @type {Bonjour | undefined}
2598
2600
  */
2599
- this.bonjour = require("bonjour")();
2601
+ this.bonjour = new Bonjour();
2600
2602
  this.bonjour.publish({
2603
+ // @ts-expect-error
2601
2604
  name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
2605
+ // @ts-expect-error
2602
2606
  port: /** @type {number} */ (this.options.port),
2607
+ // @ts-expect-error
2603
2608
  type:
2604
2609
  /** @type {ServerConfiguration} */
2605
2610
  (this.options.server).type === "http" ? "http" : "https",
@@ -3196,7 +3201,8 @@ class Server {
3196
3201
  /** @type {Host} */ (this.options.host)
3197
3202
  );
3198
3203
  this.options.port = await Server.getFreePort(
3199
- /** @type {Port} */ (this.options.port)
3204
+ /** @type {Port} */ (this.options.port),
3205
+ this.options.host
3200
3206
  );
3201
3207
  }
3202
3208
 
package/lib/getPort.js ADDED
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+
3
+ /*
4
+ * Based on the packages get-port https://www.npmjs.com/package/get-port
5
+ * and portfinder https://www.npmjs.com/package/portfinder
6
+ * The code structure is similar to get-port, but it searches
7
+ * ports deterministically like portfinder
8
+ */
9
+ const net = require("net");
10
+ const os = require("os");
11
+
12
+ const minPort = 1024;
13
+ const maxPort = 65_535;
14
+
15
+ /**
16
+ * @return {Set<string|undefined>}
17
+ */
18
+ const getLocalHosts = () => {
19
+ const interfaces = os.networkInterfaces();
20
+
21
+ // Add undefined value for createServer function to use default host,
22
+ // and default IPv4 host in case createServer defaults to IPv6.
23
+ // eslint-disable-next-line no-undefined
24
+ const results = new Set([undefined, "0.0.0.0"]);
25
+
26
+ for (const _interface of Object.values(interfaces)) {
27
+ if (_interface) {
28
+ for (const config of _interface) {
29
+ results.add(config.address);
30
+ }
31
+ }
32
+ }
33
+
34
+ return results;
35
+ };
36
+
37
+ /**
38
+ * @param {number} basePort
39
+ * @param {string | undefined} host
40
+ * @return {Promise<number>}
41
+ */
42
+ const checkAvailablePort = (basePort, host) =>
43
+ new Promise((resolve, reject) => {
44
+ const server = net.createServer();
45
+ server.unref();
46
+ server.on("error", reject);
47
+
48
+ server.listen(basePort, host, () => {
49
+ // Next line should return AdressInfo because we're calling it after listen() and before close()
50
+ const { port } = /** @type {import("net").AddressInfo} */ (
51
+ server.address()
52
+ );
53
+ server.close(() => {
54
+ resolve(port);
55
+ });
56
+ });
57
+ });
58
+
59
+ /**
60
+ * @param {number} port
61
+ * @param {Set<string|undefined>} hosts
62
+ * @return {Promise<number>}
63
+ */
64
+ const getAvailablePort = async (port, hosts) => {
65
+ /**
66
+ * Errors that mean that host is not available.
67
+ * @type {Set<string | undefined>}
68
+ */
69
+ const nonExistentInterfaceErrors = new Set(["EADDRNOTAVAIL", "EINVAL"]);
70
+ /* Check if the post is available on every local host name */
71
+ for (const host of hosts) {
72
+ try {
73
+ await checkAvailablePort(port, host); // eslint-disable-line no-await-in-loop
74
+ } catch (error) {
75
+ /* We throw an error only if the interface exists */
76
+ if (
77
+ !nonExistentInterfaceErrors.has(
78
+ /** @type {NodeJS.ErrnoException} */ (error).code
79
+ )
80
+ ) {
81
+ throw error;
82
+ }
83
+ }
84
+ }
85
+
86
+ return port;
87
+ };
88
+
89
+ /**
90
+ * @param {number} basePort
91
+ * @param {string=} host
92
+ * @return {Promise<number>}
93
+ */
94
+ async function getPorts(basePort, host) {
95
+ if (basePort < minPort || basePort > maxPort) {
96
+ throw new Error(`Port number must lie between ${minPort} and ${maxPort}`);
97
+ }
98
+
99
+ let port = basePort;
100
+ const localhosts = getLocalHosts();
101
+ let hosts;
102
+ if (host && !localhosts.has(host)) {
103
+ hosts = new Set([host]);
104
+ } else {
105
+ /* If the host is equivalent to localhost
106
+ we need to check every equivalent host
107
+ else the port might falsely appear as available
108
+ on some operating systems */
109
+ hosts = localhosts;
110
+ }
111
+ /** @type {Set<string | undefined>} */
112
+ const portUnavailableErrors = new Set(["EADDRINUSE", "EACCES"]);
113
+ while (port <= maxPort) {
114
+ try {
115
+ const availablePort = await getAvailablePort(port, hosts); // eslint-disable-line no-await-in-loop
116
+ return availablePort;
117
+ } catch (error) {
118
+ /* Try next port if port is busy; throw for any other error */
119
+ if (
120
+ !portUnavailableErrors.has(
121
+ /** @type {NodeJS.ErrnoException} */ (error).code
122
+ )
123
+ ) {
124
+ throw error;
125
+ }
126
+ port += 1;
127
+ }
128
+ }
129
+
130
+ throw new Error("No available ports found");
131
+ }
132
+
133
+ module.exports = getPorts;
package/lib/options.json CHANGED
@@ -28,7 +28,10 @@
28
28
  "Bonjour": {
29
29
  "anyOf": [
30
30
  {
31
- "type": "boolean"
31
+ "type": "boolean",
32
+ "cli": {
33
+ "negatedDescription": "Disallows to broadcasts dev server via ZeroConf networking on start."
34
+ }
32
35
  },
33
36
  {
34
37
  "type": "object",
@@ -37,17 +40,17 @@
37
40
  }
38
41
  ],
39
42
  "description": "Allows to broadcasts dev server via ZeroConf networking on start.",
40
- "link": " https://webpack.js.org/configuration/dev-server/#devserverbonjour",
41
- "cli": {
42
- "negatedDescription": "Disallows to broadcasts dev server via ZeroConf networking on start."
43
- }
43
+ "link": " https://webpack.js.org/configuration/dev-server/#devserverbonjour"
44
44
  },
45
45
  "Client": {
46
46
  "description": "Allows to specify options for client script in the browser or disable client script.",
47
47
  "link": "https://webpack.js.org/configuration/dev-server/#devserverclient",
48
48
  "anyOf": [
49
49
  {
50
- "enum": [false]
50
+ "enum": [false],
51
+ "cli": {
52
+ "negatedDescription": "Disables client script."
53
+ }
51
54
  },
52
55
  {
53
56
  "type": "object",
@@ -87,7 +90,7 @@
87
90
  "link": "https://webpack.js.org/configuration/dev-server/#overlay",
88
91
  "type": "boolean",
89
92
  "cli": {
90
- "negatedDescription": "Disables a full-screen overlay in the browser when there are compiler errors or warnings."
93
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors or warnings."
91
94
  }
92
95
  },
93
96
  {
@@ -96,11 +99,21 @@
96
99
  "properties": {
97
100
  "errors": {
98
101
  "description": "Enables a full-screen overlay in the browser when there are compiler errors.",
99
- "type": "boolean"
102
+ "type": "boolean",
103
+ "cli": {
104
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors."
105
+ }
100
106
  },
101
107
  "warnings": {
102
108
  "description": "Enables a full-screen overlay in the browser when there are compiler warnings.",
103
- "type": "boolean"
109
+ "type": "boolean",
110
+ "cli": {
111
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler warnings."
112
+ }
113
+ },
114
+ "trustedTypesPolicyName": {
115
+ "description": "The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.",
116
+ "type": "string"
104
117
  }
105
118
  }
106
119
  }
@@ -119,16 +132,16 @@
119
132
  "link": "https://webpack.js.org/configuration/dev-server/#reconnect",
120
133
  "anyOf": [
121
134
  {
122
- "type": "boolean"
135
+ "type": "boolean",
136
+ "cli": {
137
+ "negatedDescription": "Tells dev-server to not to try to reconnect the client."
138
+ }
123
139
  },
124
140
  {
125
141
  "type": "number",
126
142
  "minimum": 0
127
143
  }
128
- ],
129
- "cli": {
130
- "negatedDescription": "Tells dev-server to not to try to connect the client."
131
- }
144
+ ]
132
145
  },
133
146
  "ClientWebSocketTransport": {
134
147
  "anyOf": [
@@ -448,7 +461,10 @@
448
461
  "HistoryApiFallback": {
449
462
  "anyOf": [
450
463
  {
451
- "type": "boolean"
464
+ "type": "boolean",
465
+ "cli": {
466
+ "negatedDescription": "Disallows to proxy requests through a specified index page."
467
+ }
452
468
  },
453
469
  {
454
470
  "type": "object",
@@ -475,17 +491,17 @@
475
491
  "Hot": {
476
492
  "anyOf": [
477
493
  {
478
- "type": "boolean"
494
+ "type": "boolean",
495
+ "cli": {
496
+ "negatedDescription": "Disables Hot Module Replacement."
497
+ }
479
498
  },
480
499
  {
481
500
  "enum": ["only"]
482
501
  }
483
502
  ],
484
503
  "description": "Enables Hot Module Replacement.",
485
- "link": "https://webpack.js.org/configuration/dev-server/#devserverhot",
486
- "cli": {
487
- "negatedDescription": "Disables Hot Module Replacement."
488
- }
504
+ "link": "https://webpack.js.org/configuration/dev-server/#devserverhot"
489
505
  },
490
506
  "IPC": {
491
507
  "anyOf": [
@@ -731,7 +747,10 @@
731
747
  },
732
748
  "requestCert": {
733
749
  "type": "boolean",
734
- "description": "Request for an SSL certificate."
750
+ "description": "Request for an SSL certificate.",
751
+ "cli": {
752
+ "negatedDescription": "Does not request for an SSL certificate."
753
+ }
735
754
  },
736
755
  "ca": {
737
756
  "anyOf": [
@@ -916,7 +935,10 @@
916
935
  }
917
936
  },
918
937
  {
919
- "type": "boolean"
938
+ "type": "boolean",
939
+ "cli": {
940
+ "negatedDescription": "Disallows to configure options for serving static files from directory."
941
+ }
920
942
  },
921
943
  {
922
944
  "$ref": "#/definitions/StaticString"
@@ -962,7 +984,10 @@
962
984
  "serveIndex": {
963
985
  "anyOf": [
964
986
  {
965
- "type": "boolean"
987
+ "type": "boolean",
988
+ "cli": {
989
+ "negatedDescription": "Does not tell dev server to use serveIndex middleware."
990
+ }
966
991
  },
967
992
  {
968
993
  "type": "object",
@@ -970,15 +995,15 @@
970
995
  }
971
996
  ],
972
997
  "description": "Tells dev server to use serveIndex middleware when enabled.",
973
- "cli": {
974
- "negatedDescription": "Does not tell dev server to use serveIndex middleware."
975
- },
976
998
  "link": "https://webpack.js.org/configuration/dev-server/#serveindex"
977
999
  },
978
1000
  "watch": {
979
1001
  "anyOf": [
980
1002
  {
981
- "type": "boolean"
1003
+ "type": "boolean",
1004
+ "cli": {
1005
+ "negatedDescription": "Does not watch for files in static content directory."
1006
+ }
982
1007
  },
983
1008
  {
984
1009
  "type": "object",
@@ -987,9 +1012,6 @@
987
1012
  }
988
1013
  ],
989
1014
  "description": "Watches for files in static content directory.",
990
- "cli": {
991
- "negatedDescription": "Does not watch for files in static content directory."
992
- },
993
1015
  "link": "https://webpack.js.org/configuration/dev-server/#watch"
994
1016
  }
995
1017
  }
@@ -1082,7 +1104,10 @@
1082
1104
  "WebSocketServerEnum": {
1083
1105
  "anyOf": [
1084
1106
  {
1085
- "enum": [false]
1107
+ "enum": [false],
1108
+ "cli": {
1109
+ "negatedDescription": "Disallows to set web socket server and options."
1110
+ }
1086
1111
  },
1087
1112
  {
1088
1113
  "$ref": "#/definitions/WebSocketServerType"