webpack-dev-server 4.13.2 → 4.14.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.
@@ -85,8 +85,18 @@ const runCli = (cli) => {
85
85
  const pkgPath = require.resolve(`${cli.package}/package.json`);
86
86
  // eslint-disable-next-line import/no-dynamic-require
87
87
  const pkg = require(pkgPath);
88
- // eslint-disable-next-line import/no-dynamic-require
89
- require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
88
+
89
+ if (pkg.type === "module" || /\.mjs/i.test(pkg.bin[cli.binName])) {
90
+ import(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName])).catch(
91
+ (error) => {
92
+ console.error(error);
93
+ process.exitCode = 1;
94
+ }
95
+ );
96
+ } else {
97
+ // eslint-disable-next-line import/no-dynamic-require
98
+ require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
99
+ }
90
100
  };
91
101
 
92
102
  /**
package/client/index.js CHANGED
@@ -15,12 +15,20 @@ import sendMessage from "./utils/sendMessage.js";
15
15
  import reloadApp from "./utils/reloadApp.js";
16
16
  import createSocketURL from "./utils/createSocketURL.js";
17
17
 
18
+ /**
19
+ * @typedef {Object} OverlayOptions
20
+ * @property {boolean | (error: Error) => boolean} [warnings]
21
+ * @property {boolean | (error: Error) => boolean} [errors]
22
+ * @property {boolean | (error: Error) => boolean} [runtimeErrors]
23
+ * @property {string} [trustedTypesPolicyName]
24
+ */
25
+
18
26
  /**
19
27
  * @typedef {Object} Options
20
28
  * @property {boolean} hot
21
29
  * @property {boolean} liveReload
22
30
  * @property {boolean} progress
23
- * @property {boolean | { warnings?: boolean, errors?: boolean, runtimeErrors?: boolean, trustedTypesPolicyName?: string }} overlay
31
+ * @property {boolean | OverlayOptions} overlay
24
32
  * @property {string} [logging]
25
33
  * @property {number} [reconnect]
26
34
  */
@@ -32,6 +40,23 @@ import createSocketURL from "./utils/createSocketURL.js";
32
40
  * @property {string} [previousHash]
33
41
  */
34
42
 
43
+ /**
44
+ * @param {boolean | { warnings?: boolean | string; errors?: boolean | string; runtimeErrors?: boolean | string; }} overlayOptions
45
+ */
46
+ var decodeOverlayOptions = function decodeOverlayOptions(overlayOptions) {
47
+ if (typeof overlayOptions === "object") {
48
+ ["warnings", "errors", "runtimeErrors"].forEach(function (property) {
49
+ if (typeof overlayOptions[property] === "string") {
50
+ var overlayFilterFunctionString = decodeURIComponent(overlayOptions[property]);
51
+
52
+ // eslint-disable-next-line no-new-func
53
+ var overlayFilterFunction = new Function("message", "var callback = ".concat(overlayFilterFunctionString, "\n return callback(message)"));
54
+ overlayOptions[property] = overlayFilterFunction;
55
+ }
56
+ });
57
+ }
58
+ };
59
+
35
60
  /**
36
61
  * @type {Status}
37
62
  */
@@ -82,6 +107,7 @@ if (parsedResourceQuery.overlay) {
82
107
  warnings: true,
83
108
  runtimeErrors: true
84
109
  }, options.overlay);
110
+ decodeOverlayOptions(options.overlay);
85
111
  }
86
112
  enabledFeatures.Overlay = true;
87
113
  }
@@ -156,6 +182,7 @@ var onSocketMessage = {
156
182
  return;
157
183
  }
158
184
  options.overlay = value;
185
+ decodeOverlayOptions(options.overlay);
159
186
  },
160
187
  /**
161
188
  * @param {number} value
@@ -230,13 +257,16 @@ var onSocketMessage = {
230
257
  for (var i = 0; i < printableWarnings.length; i++) {
231
258
  log.warn(printableWarnings[i]);
232
259
  }
233
- var needShowOverlayForWarnings = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.warnings;
234
- if (needShowOverlayForWarnings) {
235
- overlay.send({
236
- type: "BUILD_ERROR",
237
- level: "warning",
238
- messages: _warnings
239
- });
260
+ var overlayWarningsSetting = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.warnings;
261
+ if (overlayWarningsSetting) {
262
+ var warningsToDisplay = typeof overlayWarningsSetting === "function" ? _warnings.filter(overlayWarningsSetting) : _warnings;
263
+ if (warningsToDisplay.length) {
264
+ overlay.send({
265
+ type: "BUILD_ERROR",
266
+ level: "warning",
267
+ messages: _warnings
268
+ });
269
+ }
240
270
  }
241
271
  if (params && params.preventReloading) {
242
272
  return;
@@ -258,13 +288,16 @@ var onSocketMessage = {
258
288
  for (var i = 0; i < printableErrors.length; i++) {
259
289
  log.error(printableErrors[i]);
260
290
  }
261
- var needShowOverlayForErrors = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.errors;
262
- if (needShowOverlayForErrors) {
263
- overlay.send({
264
- type: "BUILD_ERROR",
265
- level: "error",
266
- messages: _errors
267
- });
291
+ var overlayErrorsSettings = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.errors;
292
+ if (overlayErrorsSettings) {
293
+ var errorsToDisplay = typeof overlayErrorsSettings === "function" ? _errors.filter(overlayErrorsSettings) : _errors;
294
+ if (errorsToDisplay.length) {
295
+ overlay.send({
296
+ type: "BUILD_ERROR",
297
+ level: "error",
298
+ messages: _errors
299
+ });
300
+ }
268
301
  }
269
302
  },
270
303
  /**
@@ -4,6 +4,7 @@ import createMachine from "./fsm.js";
4
4
  * @typedef {Object} ShowOverlayData
5
5
  * @property {'warning' | 'error'} level
6
6
  * @property {Array<string | { moduleIdentifier?: string, moduleName?: string, loc?: string, message?: string }>} messages
7
+ * @property {'build' | 'runtime'} messageSource
7
8
  */
8
9
 
9
10
  /**
@@ -22,7 +23,8 @@ var createOverlayMachine = function createOverlayMachine(options) {
22
23
  initial: "hidden",
23
24
  context: {
24
25
  level: "error",
25
- messages: []
26
+ messages: [],
27
+ messageSource: "build"
26
28
  },
27
29
  states: {
28
30
  hidden: {
@@ -71,19 +73,22 @@ var createOverlayMachine = function createOverlayMachine(options) {
71
73
  dismissMessages: function dismissMessages() {
72
74
  return {
73
75
  messages: [],
74
- level: "error"
76
+ level: "error",
77
+ messageSource: "build"
75
78
  };
76
79
  },
77
80
  appendMessages: function appendMessages(context, event) {
78
81
  return {
79
82
  messages: context.messages.concat(event.messages),
80
- level: event.level || context.level
83
+ level: event.level || context.level,
84
+ messageSource: event.type === "RUNTIME_ERROR" ? "runtime" : "build"
81
85
  };
82
86
  },
83
87
  setMessages: function setMessages(context, event) {
84
88
  return {
85
89
  messages: event.messages,
86
- level: event.level || context.level
90
+ level: event.level || context.level,
91
+ messageSource: event.type === "RUNTIME_ERROR" ? "runtime" : "build"
87
92
  };
88
93
  },
89
94
  hideOverlay: hideOverlay,
package/client/overlay.js CHANGED
@@ -59,7 +59,7 @@ function formatProblem(type, item) {
59
59
  /**
60
60
  * @typedef {Object} CreateOverlayOptions
61
61
  * @property {string | null} trustedTypesPolicyName
62
- * @property {boolean} [catchRuntimeError]
62
+ * @property {boolean | (error: Error) => void} [catchRuntimeError]
63
63
  */
64
64
 
65
65
  /**
@@ -71,6 +71,8 @@ var createOverlay = function createOverlay(options) {
71
71
  var iframeContainerElement;
72
72
  /** @type {HTMLDivElement | null | undefined} */
73
73
  var containerElement;
74
+ /** @type {HTMLDivElement | null | undefined} */
75
+ var headerElement;
74
76
  /** @type {Array<(element: HTMLDivElement) => void>} */
75
77
  var onLoadQueue = [];
76
78
  /** @type {TrustedTypePolicy | undefined} */
@@ -112,7 +114,7 @@ var createOverlay = function createOverlay(options) {
112
114
  iframeContainerElement.contentDocument.createElement("div");
113
115
  contentElement.id = "webpack-dev-server-client-overlay-div";
114
116
  applyStyle(contentElement, containerStyle);
115
- var headerElement = document.createElement("div");
117
+ headerElement = document.createElement("div");
116
118
  headerElement.innerText = "Compiled with problems:";
117
119
  applyStyle(headerElement, headerStyle);
118
120
  var closeButtonElement = document.createElement("button");
@@ -178,9 +180,11 @@ var createOverlay = function createOverlay(options) {
178
180
  * @param {string} type
179
181
  * @param {Array<string | { moduleIdentifier?: string, moduleName?: string, loc?: string, message?: string }>} messages
180
182
  * @param {string | null} trustedTypesPolicyName
183
+ * @param {'build' | 'runtime'} messageSource
181
184
  */
182
- function show(type, messages, trustedTypesPolicyName) {
185
+ function show(type, messages, trustedTypesPolicyName, messageSource) {
183
186
  ensureOverlayExists(function () {
187
+ headerElement.innerText = messageSource === "runtime" ? "Uncaught runtime errors:" : "Compiled with problems:";
184
188
  messages.forEach(function (message) {
185
189
  var entryElement = document.createElement("div");
186
190
  var msgStyle = type === "warning" ? msgStyles.warning : msgStyles.error;
@@ -221,8 +225,9 @@ var createOverlay = function createOverlay(options) {
221
225
  showOverlay: function showOverlay(_ref) {
222
226
  var _ref$level = _ref.level,
223
227
  level = _ref$level === void 0 ? "error" : _ref$level,
224
- messages = _ref.messages;
225
- return show(level, messages, options.trustedTypesPolicyName);
228
+ messages = _ref.messages,
229
+ messageSource = _ref.messageSource;
230
+ return show(level, messages, options.trustedTypesPolicyName, messageSource);
226
231
  },
227
232
  hideOverlay: hide
228
233
  });
@@ -235,13 +240,16 @@ var createOverlay = function createOverlay(options) {
235
240
  return;
236
241
  }
237
242
  var errorObject = error instanceof Error ? error : new Error(error || message);
238
- overlayService.send({
239
- type: "RUNTIME_ERROR",
240
- messages: [{
241
- message: errorObject.message,
242
- stack: parseErrorToStacks(errorObject)
243
- }]
244
- });
243
+ var shouldDisplay = typeof options.catchRuntimeError === "function" ? options.catchRuntimeError(errorObject) : true;
244
+ if (shouldDisplay) {
245
+ overlayService.send({
246
+ type: "RUNTIME_ERROR",
247
+ messages: [{
248
+ message: errorObject.message,
249
+ stack: parseErrorToStacks(errorObject)
250
+ }]
251
+ });
252
+ }
245
253
  });
246
254
  }
247
255
  return overlayService;
package/lib/Server.js CHANGED
@@ -6,8 +6,6 @@ const url = require("url");
6
6
  const util = require("util");
7
7
  const fs = require("graceful-fs");
8
8
  const ipaddr = require("ipaddr.js");
9
- const defaultGateway = require("default-gateway");
10
- const express = require("express");
11
9
  const { validate } = require("schema-utils");
12
10
  const schema = require("./options.json");
13
11
 
@@ -156,10 +154,14 @@ const schema = require("./options.json");
156
154
  * @property {string} [username]
157
155
  */
158
156
 
157
+ /**
158
+ * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
159
+ */
160
+
159
161
  /**
160
162
  * @typedef {Object} ClientConfiguration
161
163
  * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
162
- * @property {boolean | { warnings?: boolean, errors?: boolean, runtimeErrors?: boolean }} [overlay]
164
+ * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
163
165
  * @property {boolean} [progress]
164
166
  * @property {boolean | number} [reconnect]
165
167
  * @property {"ws" | "sockjs" | string} [webSocketTransport]
@@ -210,6 +212,44 @@ if (!process.env.WEBPACK_SERVE) {
210
212
  process.env.WEBPACK_SERVE = true;
211
213
  }
212
214
 
215
+ /**
216
+ * @template T
217
+ * @param fn {(function(): any) | undefined}
218
+ * @returns {function(): T}
219
+ */
220
+ const memoize = (fn) => {
221
+ let cache = false;
222
+ /** @type {T} */
223
+ let result;
224
+
225
+ return () => {
226
+ if (cache) {
227
+ return result;
228
+ }
229
+
230
+ result = /** @type {function(): any} */ (fn)();
231
+ cache = true;
232
+ // Allow to clean up memory for fn
233
+ // and all dependent resources
234
+ // eslint-disable-next-line no-undefined
235
+ fn = undefined;
236
+
237
+ return result;
238
+ };
239
+ };
240
+
241
+ const getExpress = memoize(() => require("express"));
242
+
243
+ /**
244
+ *
245
+ * @param {OverlayMessageOptions} [setting]
246
+ * @returns
247
+ */
248
+ const encodeOverlaySettings = (setting) =>
249
+ typeof setting === "function"
250
+ ? encodeURIComponent(setting.toString())
251
+ : setting;
252
+
213
253
  class Server {
214
254
  /**
215
255
  * @param {Configuration | Compiler | MultiCompiler} options
@@ -342,7 +382,7 @@ class Server {
342
382
  */
343
383
  static async internalIP(family) {
344
384
  try {
345
- const { gateway } = await defaultGateway[family]();
385
+ const { gateway } = await require("default-gateway")[family]();
346
386
  return Server.findIp(gateway);
347
387
  } catch {
348
388
  // ignore
@@ -355,7 +395,7 @@ class Server {
355
395
  */
356
396
  static internalIPSync(family) {
357
397
  try {
358
- const { gateway } = defaultGateway[family].sync();
398
+ const { gateway } = require("default-gateway")[family].sync();
359
399
  return Server.findIp(gateway);
360
400
  } catch {
361
401
  // ignore
@@ -628,12 +668,19 @@ class Server {
628
668
  }
629
669
 
630
670
  if (typeof client.overlay !== "undefined") {
631
- searchParams.set(
632
- "overlay",
671
+ const overlayString =
633
672
  typeof client.overlay === "boolean"
634
673
  ? String(client.overlay)
635
- : JSON.stringify(client.overlay)
636
- );
674
+ : JSON.stringify({
675
+ ...client.overlay,
676
+ errors: encodeOverlaySettings(client.overlay.errors),
677
+ warnings: encodeOverlaySettings(client.overlay.warnings),
678
+ runtimeErrors: encodeOverlaySettings(
679
+ client.overlay.runtimeErrors
680
+ ),
681
+ });
682
+
683
+ searchParams.set("overlay", overlayString);
637
684
  }
638
685
 
639
686
  if (typeof client.reconnect !== "undefined") {
@@ -1144,7 +1191,7 @@ class Server {
1144
1191
  // Ignore error
1145
1192
  }
1146
1193
 
1147
- // It is file
1194
+ // It is a file
1148
1195
  return stats ? fs.readFileSync(item) : item;
1149
1196
  }
1150
1197
  };
@@ -1898,8 +1945,7 @@ class Server {
1898
1945
  */
1899
1946
  setupApp() {
1900
1947
  /** @type {import("express").Application | undefined}*/
1901
- // eslint-disable-next-line new-cap
1902
- this.app = new /** @type {any} */ (express)();
1948
+ this.app = new /** @type {any} */ (getExpress())();
1903
1949
  }
1904
1950
 
1905
1951
  /**
@@ -2318,7 +2364,7 @@ class Server {
2318
2364
  middlewares.push({
2319
2365
  name: "express-static",
2320
2366
  path: publicPath,
2321
- middleware: express.static(
2367
+ middleware: getExpress().static(
2322
2368
  staticOption.directory,
2323
2369
  staticOption.staticOptions
2324
2370
  ),
@@ -2373,7 +2419,7 @@ class Server {
2373
2419
  middlewares.push({
2374
2420
  name: "express-static",
2375
2421
  path: publicPath,
2376
- middleware: express.static(
2422
+ middleware: getExpress().static(
2377
2423
  staticOption.directory,
2378
2424
  staticOption.staticOptions
2379
2425
  ),
@@ -2602,11 +2648,27 @@ class Server {
2602
2648
  /** @type {ClientConfiguration} */
2603
2649
  (this.options.client).overlay
2604
2650
  ) {
2651
+ const overlayConfig = /** @type {ClientConfiguration} */ (
2652
+ this.options.client
2653
+ ).overlay;
2654
+
2605
2655
  this.sendMessage(
2606
2656
  [client],
2607
2657
  "overlay",
2608
- /** @type {ClientConfiguration} */
2609
- (this.options.client).overlay
2658
+ typeof overlayConfig === "object"
2659
+ ? {
2660
+ ...overlayConfig,
2661
+ errors:
2662
+ overlayConfig.errors &&
2663
+ encodeOverlaySettings(overlayConfig.errors),
2664
+ warnings:
2665
+ overlayConfig.warnings &&
2666
+ encodeOverlaySettings(overlayConfig.warnings),
2667
+ runtimeErrors:
2668
+ overlayConfig.runtimeErrors &&
2669
+ encodeOverlaySettings(overlayConfig.runtimeErrors),
2670
+ }
2671
+ : overlayConfig
2610
2672
  );
2611
2673
  }
2612
2674
 
@@ -3257,7 +3319,7 @@ class Server {
3257
3319
  */
3258
3320
  (error) => {
3259
3321
  if (error.code === "ECONNREFUSED") {
3260
- // No other server listening on this socket so it can be safely removed
3322
+ // No other server listening on this socket, so it can be safely removed
3261
3323
  fs.unlinkSync(/** @type {string} */ (this.options.ipc));
3262
3324
 
3263
3325
  resolve();
package/lib/options.json CHANGED
@@ -98,25 +98,49 @@
98
98
  "additionalProperties": false,
99
99
  "properties": {
100
100
  "errors": {
101
- "description": "Enables a full-screen overlay in the browser when there are compiler errors.",
102
- "type": "boolean",
103
- "cli": {
104
- "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors."
105
- }
101
+ "anyOf": [
102
+ {
103
+ "description": "Enables a full-screen overlay in the browser when there are compiler errors.",
104
+ "type": "boolean",
105
+ "cli": {
106
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors."
107
+ }
108
+ },
109
+ {
110
+ "instanceof": "Function",
111
+ "description": "Filter compiler errors. Return true to include and return false to exclude."
112
+ }
113
+ ]
106
114
  },
107
115
  "warnings": {
108
- "description": "Enables a full-screen overlay in the browser when there are compiler warnings.",
109
- "type": "boolean",
110
- "cli": {
111
- "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler warnings."
112
- }
116
+ "anyOf": [
117
+ {
118
+ "description": "Enables a full-screen overlay in the browser when there are compiler warnings.",
119
+ "type": "boolean",
120
+ "cli": {
121
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler warnings."
122
+ }
123
+ },
124
+ {
125
+ "instanceof": "Function",
126
+ "description": "Filter compiler warnings. Return true to include and return false to exclude."
127
+ }
128
+ ]
113
129
  },
114
130
  "runtimeErrors": {
115
- "description": "Enables a full-screen overlay in the browser when there are uncaught runtime errors.",
116
- "type": "boolean",
117
- "cli": {
118
- "negatedDescription": "Disables the full-screen overlay in the browser when there are uncaught runtime errors."
119
- }
131
+ "anyOf": [
132
+ {
133
+ "description": "Enables a full-screen overlay in the browser when there are uncaught runtime errors.",
134
+ "type": "boolean",
135
+ "cli": {
136
+ "negatedDescription": "Disables the full-screen overlay in the browser when there are uncaught runtime errors."
137
+ }
138
+ },
139
+ {
140
+ "instanceof": "Function",
141
+ "description": "Filter uncaught runtime errors. Return true to include and return false to exclude."
142
+ }
143
+ ]
120
144
  },
121
145
  "trustedTypesPolicyName": {
122
146
  "description": "The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack-dev-server",
3
- "version": "4.13.2",
3
+ "version": "4.14.0",
4
4
  "description": "Serves a webpack app. Updates the browser on changes.",
5
5
  "bin": "bin/webpack-dev-server.js",
6
6
  "main": "lib/Server.js",
@@ -129,7 +129,7 @@
129
129
  "typescript": "^4.9.3",
130
130
  "url-loader": "^4.1.1",
131
131
  "wait-for-expect": "^3.0.2",
132
- "webpack": "^5.76.1",
132
+ "webpack": "^5.81.0",
133
133
  "webpack-cli": "^4.7.2",
134
134
  "webpack-merge": "^5.8.0"
135
135
  },