webpack-dev-server 5.2.2 → 5.2.3

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
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
- const os = require("os");
4
- const path = require("path");
5
- const url = require("url");
6
- const util = require("util");
3
+ const os = require("node:os");
4
+ const path = require("node:path");
5
+ const url = require("node:url");
6
+ const util = require("node:util");
7
7
  const fs = require("graceful-fs");
8
8
  const ipaddr = require("ipaddr.js");
9
9
  const { validate } = require("schema-utils");
@@ -31,7 +31,7 @@ const schema = require("./options.json");
31
31
  /** @typedef {import("ipaddr.js").IPv4} IPv4 */
32
32
  /** @typedef {import("ipaddr.js").IPv6} IPv6 */
33
33
  /** @typedef {import("net").Socket} Socket */
34
- /** @typedef {import("http").Server} HTTPServer*/
34
+ /** @typedef {import("http").Server} HTTPServer */
35
35
  /** @typedef {import("http").IncomingMessage} IncomingMessage */
36
36
  /** @typedef {import("http").ServerResponse} ServerResponse */
37
37
  /** @typedef {import("open").Options} OpenOptions */
@@ -41,10 +41,13 @@ const schema = require("./options.json");
41
41
  /** @typedef {import("express").Request} ExpressRequest */
42
42
  /** @typedef {import("express").Response} ExpressResponse */
43
43
 
44
- /** @typedef {(err?: any) => void} NextFunction */
44
+ // eslint-disable-next-line jsdoc/no-restricted-syntax
45
+ /** @typedef {any} EXPECTED_ANY */
46
+
47
+ /** @typedef {(err?: EXPECTED_ANY) => void} NextFunction */
45
48
  /** @typedef {(req: IncomingMessage, res: ServerResponse) => void} SimpleHandleFunction */
46
49
  /** @typedef {(req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} NextHandleFunction */
47
- /** @typedef {(err: any, req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} ErrorHandleFunction */
50
+ /** @typedef {(err: EXPECTED_ANY, req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} ErrorHandleFunction */
48
51
  /** @typedef {SimpleHandleFunction | NextHandleFunction | ErrorHandleFunction} HandleFunction */
49
52
 
50
53
  /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
@@ -79,22 +82,22 @@ const schema = require("./options.json");
79
82
  */
80
83
 
81
84
  /**
82
- * @typedef {Object} WatchFiles
83
- * @property {string | string[]} paths
84
- * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
85
+ * @typedef {object} WatchFiles
86
+ * @property {string | string[]} paths paths
87
+ * @property {(WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean })=} options options
85
88
  */
86
89
 
87
90
  /**
88
- * @typedef {Object} Static
89
- * @property {string} [directory]
90
- * @property {string | string[]} [publicPath]
91
- * @property {boolean | ServeIndexOptions} [serveIndex]
92
- * @property {ServeStaticOptions} [staticOptions]
93
- * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
91
+ * @typedef {object} Static
92
+ * @property {string=} directory directory
93
+ * @property {(string | string[])=} publicPath public path
94
+ * @property {(boolean | ServeIndexOptions)=} serveIndex serve index
95
+ * @property {ServeStaticOptions=} staticOptions static options
96
+ * @property {(boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean })=} watch watch and watch options
94
97
  */
95
98
 
96
99
  /**
97
- * @typedef {Object} NormalizedStatic
100
+ * @typedef {object} NormalizedStatic
98
101
  * @property {string} directory
99
102
  * @property {string[]} publicPath
100
103
  * @property {false | ServeIndexOptions} serveIndex
@@ -105,21 +108,21 @@ const schema = require("./options.json");
105
108
  /**
106
109
  * @template {BasicApplication} [A=ExpressApplication]
107
110
  * @template {BasicServer} [S=import("http").Server]
108
- * @typedef {"http" | "https" | "spdy" | "http2" | string | function(ServerOptions, A): S} ServerType
111
+ * @typedef {"http" | "https" | "spdy" | "http2" | string | ((serverOptions: ServerOptions, application: A) => S)} ServerType
109
112
  */
110
113
 
111
114
  /**
112
115
  * @template {BasicApplication} [A=ExpressApplication]
113
116
  * @template {BasicServer} [S=import("http").Server]
114
- * @typedef {Object} ServerConfiguration
115
- * @property {ServerType<A, S>} [type]
116
- * @property {ServerOptions} [options]
117
+ * @typedef {object} ServerConfiguration
118
+ * @property {ServerType<A, S>=} type type
119
+ * @property {ServerOptions=} options options
117
120
  */
118
121
 
119
122
  /**
120
- * @typedef {Object} WebSocketServerConfiguration
121
- * @property {"sockjs" | "ws" | string | Function} [type]
122
- * @property {Record<string, any>} [options]
123
+ * @typedef {object} WebSocketServerConfiguration
124
+ * @property {("sockjs" | "ws" | string | (() => WebSocketServerConfiguration))=} type type
125
+ * @property {Record<string, EXPECTED_ANY>=} options options
123
126
  */
124
127
 
125
128
  /**
@@ -150,31 +153,31 @@ const schema = require("./options.json");
150
153
  */
151
154
 
152
155
  /**
153
- * @typedef {Object} OpenApp
154
- * @property {string} [name]
155
- * @property {string[]} [arguments]
156
+ * @typedef {object} OpenApp
157
+ * @property {string=} name
158
+ * @property {string[]=} arguments
156
159
  */
157
160
 
158
161
  /**
159
- * @typedef {Object} Open
160
- * @property {string | string[] | OpenApp} [app]
161
- * @property {string | string[]} [target]
162
+ * @typedef {object} Open
163
+ * @property {(string | string[] | OpenApp)=} app
164
+ * @property {(string | string[])=} target target
162
165
  */
163
166
 
164
167
  /**
165
- * @typedef {Object} NormalizedOpen
168
+ * @typedef {object} NormalizedOpen
166
169
  * @property {string} target
167
170
  * @property {import("open").Options} options
168
171
  */
169
172
 
170
173
  /**
171
- * @typedef {Object} WebSocketURL
172
- * @property {string} [hostname]
173
- * @property {string} [password]
174
- * @property {string} [pathname]
175
- * @property {number | string} [port]
176
- * @property {string} [protocol]
177
- * @property {string} [username]
174
+ * @typedef {object} WebSocketURL
175
+ * @property {string=} hostname hostname
176
+ * @property {string=} password password
177
+ * @property {string=} pathname pathname
178
+ * @property {(number | string)=} port port
179
+ * @property {string=} protocol protocol
180
+ * @property {string=} username username
178
181
  */
179
182
 
180
183
  /**
@@ -182,13 +185,13 @@ const schema = require("./options.json");
182
185
  */
183
186
 
184
187
  /**
185
- * @typedef {Object} ClientConfiguration
186
- * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
187
- * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
188
- * @property {boolean} [progress]
189
- * @property {boolean | number} [reconnect]
190
- * @property {"ws" | "sockjs" | string} [webSocketTransport]
191
- * @property {string | WebSocketURL} [webSocketURL]
188
+ * @typedef {object} ClientConfiguration
189
+ * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"=} logging logging
190
+ * @property {(boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions })=} overlay overlay
191
+ * @property {boolean=} progress progress
192
+ * @property {(boolean | number)=} reconnect reconnect
193
+ * @property {("ws" | "sockjs" | string)=} webSocketTransport web socket transport
194
+ * @property {(string | WebSocketURL)=} webSocketURL web socket URL
192
195
  */
193
196
 
194
197
  /**
@@ -213,29 +216,29 @@ const schema = require("./options.json");
213
216
  /**
214
217
  * @template {BasicApplication} [A=ExpressApplication]
215
218
  * @template {BasicServer} [S=import("http").Server]
216
- * @typedef {Object} Configuration
217
- * @property {boolean | string} [ipc]
218
- * @property {Host} [host]
219
- * @property {Port} [port]
220
- * @property {boolean | "only"} [hot]
221
- * @property {boolean} [liveReload]
222
- * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
223
- * @property {boolean} [compress]
224
- * @property {"auto" | "all" | string | string[]} [allowedHosts]
225
- * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
226
- * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
227
- * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
228
- * @property {boolean | string | Static | Array<string | Static>} [static]
229
- * @property {ServerType<A, S> | ServerConfiguration<A, S>} [server]
230
- * @property {() => Promise<A>} [app]
231
- * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
232
- * @property {ProxyConfigArray} [proxy]
233
- * @property {boolean | string | Open | Array<string | Open>} [open]
234
- * @property {boolean} [setupExitSignals]
235
- * @property {boolean | ClientConfiguration} [client]
236
- * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response> | undefined) => Headers)} [headers]
237
- * @property {(devServer: Server<A, S>) => void} [onListening]
238
- * @property {(middlewares: Middleware[], devServer: Server<A, S>) => Middleware[]} [setupMiddlewares]
219
+ * @typedef {object} Configuration
220
+ * @property {(boolean | string)=} ipc
221
+ * @property {Host=} host
222
+ * @property {Port=} port
223
+ * @property {(boolean | "only")=} hot
224
+ * @property {boolean=} liveReload
225
+ * @property {DevMiddlewareOptions<Request, Response>=} devMiddleware
226
+ * @property {boolean=} compress
227
+ * @property {("auto" | "all" | string | string[])=} allowedHosts
228
+ * @property {(boolean | ConnectHistoryApiFallbackOptions)=} historyApiFallback
229
+ * @property {(boolean | Record<string, never> | BonjourOptions)=} bonjour
230
+ * @property {(string | string[] | WatchFiles | Array<string | WatchFiles>)=} watchFiles
231
+ * @property {(boolean | string | Static | Array<string | Static>)=} static
232
+ * @property {(ServerType<A, S> | ServerConfiguration<A, S>)=} server
233
+ * @property {(() => Promise<A>)=} app
234
+ * @property {(boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration)=} webSocketServer
235
+ * @property {ProxyConfigArray=} proxy
236
+ * @property {(boolean | string | Open | Array<string | Open>)=} open
237
+ * @property {boolean=} setupExitSignals
238
+ * @property {(boolean | ClientConfiguration)=} client
239
+ * @property {(Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response> | undefined) => Headers))=} headers
240
+ * @property {((devServer: Server<A, S>) => void)=} onListening
241
+ * @property {((middlewares: Middleware[], devServer: Server<A, S>) => Middleware[])=} setupMiddlewares
239
242
  */
240
243
 
241
244
  if (!process.env.WEBPACK_SERVE) {
@@ -244,36 +247,38 @@ if (!process.env.WEBPACK_SERVE) {
244
247
 
245
248
  /**
246
249
  * @template T
247
- * @param fn {(function(): any) | undefined}
248
- * @returns {function(): T}
250
+ * @typedef {() => T} FunctionReturning
251
+ */
252
+
253
+ /**
254
+ * @template T
255
+ * @param {FunctionReturning<T>} fn memorized function
256
+ * @returns {FunctionReturning<T>} new function
249
257
  */
250
258
  const memoize = (fn) => {
251
259
  let cache = false;
252
- /** @type {T} */
260
+ /** @type {T | undefined} */
253
261
  let result;
254
-
255
262
  return () => {
256
263
  if (cache) {
257
- return result;
264
+ return /** @type {T} */ (result);
258
265
  }
259
266
 
260
- result = /** @type {function(): any} */ (fn)();
267
+ result = fn();
261
268
  cache = true;
262
269
  // Allow to clean up memory for fn
263
270
  // and all dependent resources
264
- // eslint-disable-next-line no-undefined
265
- fn = undefined;
266
-
267
- return result;
271
+ /** @type {FunctionReturning<T> | undefined} */
272
+ (fn) = undefined;
273
+ return /** @type {T} */ (result);
268
274
  };
269
275
  };
270
276
 
271
277
  const getExpress = memoize(() => require("express"));
272
278
 
273
279
  /**
274
- *
275
- * @param {OverlayMessageOptions} [setting]
276
- * @returns
280
+ * @param {OverlayMessageOptions=} setting overlay settings
281
+ * @returns {undefined | string | boolean} encoded overlay settings
277
282
  */
278
283
  const encodeOverlaySettings = (setting) =>
279
284
  typeof setting === "function"
@@ -283,24 +288,24 @@ const encodeOverlaySettings = (setting) =>
283
288
  // Working for overload, because typescript doesn't support this yes
284
289
  /**
285
290
  * @overload
286
- * @param {NextHandleFunction} fn
287
- * @returns {BasicApplication}
291
+ * @param {NextHandleFunction} fn function
292
+ * @returns {BasicApplication} application
288
293
  */
289
294
  /**
290
295
  * @overload
291
- * @param {HandleFunction} fn
292
- * @returns {BasicApplication}
296
+ * @param {HandleFunction} fn function
297
+ * @returns {BasicApplication} application
293
298
  */
294
299
  /**
295
300
  * @overload
296
- * @param {string} route
297
- * @param {NextHandleFunction} fn
298
- * @returns {BasicApplication}
301
+ * @param {string} route route
302
+ * @param {NextHandleFunction} fn function
303
+ * @returns {BasicApplication} application
299
304
  */
300
305
  /**
301
- * @param {string} route
302
- * @param {HandleFunction} fn
303
- * @returns {BasicApplication}
306
+ * @param {string} route route
307
+ * @param {HandleFunction} fn function
308
+ * @returns {BasicApplication} application
304
309
  */
305
310
  // eslint-disable-next-line no-unused-vars
306
311
  function useFn(route, fn) {
@@ -310,7 +315,7 @@ function useFn(route, fn) {
310
315
  const DEFAULT_ALLOWED_PROTOCOLS = /^(file|.+-extension):/i;
311
316
 
312
317
  /**
313
- * @typedef {Object} BasicApplication
318
+ * @typedef {object} BasicApplication
314
319
  * @property {typeof useFn} use
315
320
  */
316
321
 
@@ -320,10 +325,10 @@ const DEFAULT_ALLOWED_PROTOCOLS = /^(file|.+-extension):/i;
320
325
  */
321
326
  class Server {
322
327
  /**
323
- * @param {Configuration<A, S>} options
324
- * @param {Compiler | MultiCompiler} compiler
328
+ * @param {Configuration<A, S>} options options
329
+ * @param {Compiler | MultiCompiler} compiler compiler
325
330
  */
326
- constructor(options = {}, compiler) {
331
+ constructor(options, compiler) {
327
332
  validate(/** @type {Schema} */ (schema), options, {
328
333
  name: "Dev Server",
329
334
  baseDataPath: "options",
@@ -332,7 +337,7 @@ class Server {
332
337
  this.compiler = compiler;
333
338
  /**
334
339
  * @type {ReturnType<Compiler["getInfrastructureLogger"]>}
335
- * */
340
+ */
336
341
  this.logger = this.compiler.getInfrastructureLogger("webpack-dev-server");
337
342
  this.options = options;
338
343
  /**
@@ -341,7 +346,7 @@ class Server {
341
346
  this.staticWatchers = [];
342
347
  /**
343
348
  * @private
344
- * @type {{ name: string | symbol, listener: (...args: any[]) => void}[] }}
349
+ * @type {{ name: string | symbol, listener: (...args: EXPECTED_ANY[]) => void}[] }}
345
350
  */
346
351
  this.listeners = [];
347
352
  // Keep track of websocket proxies for external websocket upgrade.
@@ -358,7 +363,7 @@ class Server {
358
363
  * @private
359
364
  * @type {string | undefined}
360
365
  */
361
- // eslint-disable-next-line no-undefined
366
+
362
367
  this.currentHash = undefined;
363
368
  }
364
369
 
@@ -368,8 +373,7 @@ class Server {
368
373
 
369
374
  /**
370
375
  * @private
371
- * @returns {StatsOptions}
372
- * @constructor
376
+ * @returns {StatsOptions} default stats options
373
377
  */
374
378
  static get DEFAULT_STATS() {
375
379
  return {
@@ -382,8 +386,8 @@ class Server {
382
386
  }
383
387
 
384
388
  /**
385
- * @param {string} URL
386
- * @returns {boolean}
389
+ * @param {string} URL url
390
+ * @returns {boolean} true when URL is absolute, otherwise false
387
391
  */
388
392
  static isAbsoluteURL(URL) {
389
393
  // Don't match Windows paths `c:\`
@@ -397,16 +401,15 @@ class Server {
397
401
  }
398
402
 
399
403
  /**
400
- * @param {string} gatewayOrFamily or family
401
- * @param {boolean} [isInternal] ip should be internal
402
- * @returns {string | undefined}
404
+ * @param {string} gatewayOrFamily gateway or family
405
+ * @param {boolean=} isInternal ip should be internal
406
+ * @returns {string | undefined} resolved IP
403
407
  */
404
408
  static findIp(gatewayOrFamily, isInternal) {
405
409
  if (gatewayOrFamily === "v4" || gatewayOrFamily === "v6") {
406
410
  let host;
407
411
 
408
412
  const networks = Object.values(os.networkInterfaces())
409
- // eslint-disable-next-line no-shadow
410
413
  .flatMap((networks) => networks ?? [])
411
414
  .filter((network) => {
412
415
  if (!network || !network.address) {
@@ -463,6 +466,7 @@ class Server {
463
466
  if (
464
467
  net[0] &&
465
468
  net[0].kind() === gatewayIp.kind() &&
469
+ // eslint-disable-next-line unicorn/prefer-regexp-test
466
470
  gatewayIp.match(net)
467
471
  ) {
468
472
  return net[0].toString();
@@ -473,8 +477,8 @@ class Server {
473
477
 
474
478
  // TODO remove me in the next major release, we have `findIp`
475
479
  /**
476
- * @param {"v4" | "v6"} family
477
- * @returns {Promise<string | undefined>}
480
+ * @param {"v4" | "v6"} family family
481
+ * @returns {Promise<string | undefined>} internal API
478
482
  */
479
483
  static async internalIP(family) {
480
484
  return Server.findIp(family, false);
@@ -482,16 +486,16 @@ class Server {
482
486
 
483
487
  // TODO remove me in the next major release, we have `findIp`
484
488
  /**
485
- * @param {"v4" | "v6"} family
486
- * @returns {string | undefined}
489
+ * @param {"v4" | "v6"} family family
490
+ * @returns {string | undefined} internal IP
487
491
  */
488
492
  static internalIPSync(family) {
489
493
  return Server.findIp(family, false);
490
494
  }
491
495
 
492
496
  /**
493
- * @param {Host} hostname
494
- * @returns {Promise<string>}
497
+ * @param {Host} hostname hostname
498
+ * @returns {Promise<string>} resolved hostname
495
499
  */
496
500
  static async getHostname(hostname) {
497
501
  if (hostname === "local-ip") {
@@ -508,9 +512,9 @@ class Server {
508
512
  }
509
513
 
510
514
  /**
511
- * @param {Port} port
512
- * @param {string} host
513
- * @returns {Promise<number | string>}
515
+ * @param {Port} port port
516
+ * @param {string} host host
517
+ * @returns {Promise<number | string>} free port
514
518
  */
515
519
  static async getFreePort(port, host) {
516
520
  if (typeof port !== "undefined" && port !== null && port !== "auto") {
@@ -518,17 +522,19 @@ class Server {
518
522
  }
519
523
 
520
524
  const pRetry = (await import("p-retry")).default;
525
+
521
526
  const getPort = require("./getPort");
527
+
522
528
  const basePort =
523
529
  typeof process.env.WEBPACK_DEV_SERVER_BASE_PORT !== "undefined"
524
- ? parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
530
+ ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
525
531
  : 8080;
526
532
 
527
533
  // Try to find unused port and listen on it for 3 times,
528
534
  // if port is not specified in options.
529
535
  const defaultPortRetry =
530
536
  typeof process.env.WEBPACK_DEV_SERVER_PORT_RETRY !== "undefined"
531
- ? parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
537
+ ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
532
538
  : 3;
533
539
 
534
540
  return pRetry(() => getPort(basePort, host), {
@@ -537,7 +543,7 @@ class Server {
537
543
  }
538
544
 
539
545
  /**
540
- * @returns {string}
546
+ * @returns {string} path to cache dir
541
547
  */
542
548
  static findCacheDir() {
543
549
  const cwd = process.cwd();
@@ -551,12 +557,11 @@ class Server {
551
557
  try {
552
558
  if (fs.statSync(path.join(dir, "package.json")).isFile()) break;
553
559
  // eslint-disable-next-line no-empty
554
- } catch (e) {}
560
+ } catch {}
555
561
 
556
562
  const parent = path.dirname(dir);
557
563
 
558
564
  if (dir === parent) {
559
- // eslint-disable-next-line no-undefined
560
565
  dir = undefined;
561
566
  break;
562
567
  }
@@ -577,8 +582,8 @@ class Server {
577
582
 
578
583
  /**
579
584
  * @private
580
- * @param {Compiler} compiler
581
- * @returns bool
585
+ * @param {Compiler} compiler compiler
586
+ * @returns {boolean} true when target is `web`, otherwise false
582
587
  */
583
588
  static isWebTarget(compiler) {
584
589
  if (compiler.platform && compiler.platform.web) {
@@ -607,7 +612,7 @@ class Server {
607
612
  "electron-renderer",
608
613
  "nwjs",
609
614
  "node-webkit",
610
- // eslint-disable-next-line no-undefined
615
+
611
616
  undefined,
612
617
  null,
613
618
  ];
@@ -621,7 +626,7 @@ class Server {
621
626
 
622
627
  /**
623
628
  * @private
624
- * @param {Compiler} compiler
629
+ * @param {Compiler} compiler compiler
625
630
  */
626
631
  addAdditionalEntries(compiler) {
627
632
  /**
@@ -810,7 +815,6 @@ class Server {
810
815
  // use a hook to add entries if available
811
816
  for (const additionalEntry of additionalEntries) {
812
817
  new webpack.EntryPlugin(compiler.context, additionalEntry, {
813
- // eslint-disable-next-line no-undefined
814
818
  name: undefined,
815
819
  }).apply(compiler);
816
820
  }
@@ -818,7 +822,7 @@ class Server {
818
822
 
819
823
  /**
820
824
  * @private
821
- * @returns {Compiler["options"]}
825
+ * @returns {Compiler["options"]} compiler options
822
826
  */
823
827
  getCompilerOptions() {
824
828
  if (
@@ -854,7 +858,7 @@ class Server {
854
858
  "electron-preload",
855
859
  "electron-renderer",
856
860
  "node-webkit",
857
- // eslint-disable-next-line no-undefined
861
+
858
862
  undefined,
859
863
  null,
860
864
  ].includes(/** @type {string} */ (config.options.target)),
@@ -880,8 +884,8 @@ class Server {
880
884
  const compilerOptions = this.getCompilerOptions();
881
885
  const compilerWatchOptions = compilerOptions.watchOptions;
882
886
  /**
883
- * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions
884
- * @returns {WatchOptions}
887
+ * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions watch options
888
+ * @returns {WatchOptions} normalized watch options
885
889
  */
886
890
  const getWatchOptions = (watchOptions = {}) => {
887
891
  const getPolling = () => {
@@ -933,19 +937,17 @@ class Server {
933
937
  };
934
938
  };
935
939
  /**
936
- * @param {string | Static | undefined} [optionsForStatic]
937
- * @returns {NormalizedStatic}
940
+ * @param {(string | Static | undefined)=} optionsForStatic for static
941
+ * @returns {NormalizedStatic} normalized options for static
938
942
  */
939
943
  const getStaticItem = (optionsForStatic) => {
940
- const getDefaultStaticOptions = () => {
941
- return {
942
- directory: path.join(process.cwd(), "public"),
943
- staticOptions: {},
944
- publicPath: ["/"],
945
- serveIndex: { icons: true },
946
- watch: getWatchOptions(),
947
- };
948
- };
944
+ const getDefaultStaticOptions = () => ({
945
+ directory: path.join(process.cwd(), "public"),
946
+ staticOptions: {},
947
+ publicPath: ["/"],
948
+ serveIndex: { icons: true },
949
+ watch: getWatchOptions(),
950
+ });
949
951
 
950
952
  /** @type {NormalizedStatic} */
951
953
  let item;
@@ -970,7 +972,6 @@ class Server {
970
972
  ? { ...def.staticOptions, ...optionsForStatic.staticOptions }
971
973
  : def.staticOptions,
972
974
  publicPath:
973
- // eslint-disable-next-line no-nested-ternary
974
975
  typeof optionsForStatic.publicPath !== "undefined"
975
976
  ? Array.isArray(optionsForStatic.publicPath)
976
977
  ? optionsForStatic.publicPath
@@ -982,10 +983,8 @@ class Server {
982
983
  // If 'serveIndex' is an object, merge its properties with default 'serveIndex'
983
984
  // If 'serveIndex' is neither a boolean true nor an object, use it as-is
984
985
  // If 'serveIndex' is not defined in 'optionsForStatic', use default 'serveIndex'
985
- // eslint-disable-next-line no-nested-ternary
986
986
  typeof optionsForStatic.serveIndex !== "undefined"
987
- ? // eslint-disable-next-line no-nested-ternary
988
- typeof optionsForStatic.serveIndex === "boolean" &&
987
+ ? typeof optionsForStatic.serveIndex === "boolean" &&
989
988
  optionsForStatic.serveIndex
990
989
  ? def.serveIndex
991
990
  : typeof optionsForStatic.serveIndex === "object"
@@ -993,10 +992,8 @@ class Server {
993
992
  : optionsForStatic.serveIndex
994
993
  : def.serveIndex,
995
994
  watch:
996
- // eslint-disable-next-line no-nested-ternary
997
995
  typeof optionsForStatic.watch !== "undefined"
998
- ? // eslint-disable-next-line no-nested-ternary
999
- typeof optionsForStatic.watch === "boolean"
996
+ ? typeof optionsForStatic.watch === "boolean"
1000
997
  ? optionsForStatic.watch
1001
998
  ? def.watch
1002
999
  : false
@@ -1159,17 +1156,17 @@ class Server {
1159
1156
  /** @type {Array<keyof ServerOptions>} */
1160
1157
  (["ca", "cert", "crl", "key", "pfx"]);
1161
1158
 
1162
- for (const property of httpsProperties) {
1159
+ for (const property_ of httpsProperties) {
1160
+ const property = /** @type {keyof ServerOptions} */ (property_);
1161
+
1163
1162
  if (typeof serverOptions[property] === "undefined") {
1164
- // eslint-disable-next-line no-continue
1165
1163
  continue;
1166
1164
  }
1167
1165
 
1168
- /** @type {any} */
1169
1166
  const value = serverOptions[property];
1170
1167
  /**
1171
- * @param {string | Buffer | undefined} item
1172
- * @returns {string | Buffer | undefined}
1168
+ * @param {string | Buffer | undefined} item file to read
1169
+ * @returns {string | Buffer | undefined} content of file
1173
1170
  */
1174
1171
  const readFile = (item) => {
1175
1172
  if (
@@ -1184,7 +1181,7 @@ class Server {
1184
1181
 
1185
1182
  try {
1186
1183
  stats = fs.lstatSync(fs.realpathSync(item)).isFile();
1187
- } catch (error) {
1184
+ } catch {
1188
1185
  // Ignore error
1189
1186
  }
1190
1187
 
@@ -1193,10 +1190,18 @@ class Server {
1193
1190
  }
1194
1191
  };
1195
1192
 
1196
- /** @type {any} */
1193
+ /** @type {EXPECTED_ANY} */
1197
1194
  (serverOptions)[property] = Array.isArray(value)
1198
- ? value.map((item) => readFile(item))
1199
- : readFile(value);
1195
+ ? value.map((item) =>
1196
+ readFile(
1197
+ /** @type {string | Buffer | undefined} */
1198
+ (item),
1199
+ ),
1200
+ )
1201
+ : readFile(
1202
+ /** @type {string | Buffer | undefined} */
1203
+ (value),
1204
+ );
1200
1205
  }
1201
1206
 
1202
1207
  let fakeCert;
@@ -1216,7 +1221,7 @@ class Server {
1216
1221
  if (certificateExists) {
1217
1222
  const certificateTtl = 1000 * 60 * 60 * 24;
1218
1223
  const certificateStat = await fs.promises.stat(certificatePath);
1219
- const now = Number(new Date());
1224
+ const now = Date.now();
1220
1225
 
1221
1226
  // cert is more than 30 days old, kill it with fire
1222
1227
  if ((now - Number(certificateStat.ctime)) / certificateTtl > 30) {
@@ -1234,11 +1239,16 @@ class Server {
1234
1239
  this.logger.info("Generating SSL certificate...");
1235
1240
 
1236
1241
  const selfsigned = require("selfsigned");
1242
+
1237
1243
  const attributes = [{ name: "commonName", value: "localhost" }];
1238
- const pems = selfsigned.generate(attributes, {
1244
+ const notBeforeDate = new Date();
1245
+ const notAfterDate = new Date();
1246
+ notAfterDate.setDate(notAfterDate.getDate() + 30);
1247
+ const pems = await selfsigned.generate(attributes, {
1239
1248
  algorithm: "sha256",
1240
- days: 30,
1241
1249
  keySize: 2048,
1250
+ notBeforeDate,
1251
+ notAfterDate,
1242
1252
  extensions: [
1243
1253
  {
1244
1254
  name: "basicConstraints",
@@ -1313,8 +1323,8 @@ class Server {
1313
1323
  this.logger.info(`SSL certificate: ${certificatePath}`);
1314
1324
  }
1315
1325
 
1316
- serverOptions.key = serverOptions.key || fakeCert;
1317
- serverOptions.cert = serverOptions.cert || fakeCert;
1326
+ serverOptions.key ||= fakeCert;
1327
+ serverOptions.cert ||= fakeCert;
1318
1328
  }
1319
1329
 
1320
1330
  if (typeof options.ipc === "boolean") {
@@ -1331,8 +1341,8 @@ class Server {
1331
1341
  // https://github.com/webpack/webpack-dev-server/issues/1990
1332
1342
  const defaultOpenOptions = { wait: false };
1333
1343
  /**
1334
- * @param {any} target
1335
- * @returns {NormalizedOpen[]}
1344
+ * @param {import("open").Options & { target?: string | string[] } & EXPECTED_ANY} target target
1345
+ * @returns {NormalizedOpen[]} normalized open options
1336
1346
  */
1337
1347
  const getOpenItemsFromObject = ({ target, ...rest }) => {
1338
1348
  const normalizedOptions = { ...defaultOpenOptions, ...rest };
@@ -1346,9 +1356,10 @@ class Server {
1346
1356
  const normalizedTarget = typeof target === "undefined" ? "<url>" : target;
1347
1357
 
1348
1358
  if (Array.isArray(normalizedTarget)) {
1349
- return normalizedTarget.map((singleTarget) => {
1350
- return { target: singleTarget, options: normalizedOptions };
1351
- });
1359
+ return normalizedTarget.map((singleTarget) => ({
1360
+ target: singleTarget,
1361
+ options: normalizedOptions,
1362
+ }));
1352
1363
  }
1353
1364
 
1354
1365
  return [{ target: normalizedTarget, options: normalizedOptions }];
@@ -1379,7 +1390,7 @@ class Server {
1379
1390
  for (const item of options.open) {
1380
1391
  if (typeof item === "string") {
1381
1392
  result.push({ target: item, options: defaultOpenOptions });
1382
- // eslint-disable-next-line no-continue
1393
+
1383
1394
  continue;
1384
1395
  }
1385
1396
 
@@ -1399,13 +1410,9 @@ class Server {
1399
1410
 
1400
1411
  /**
1401
1412
  * Assume a proxy configuration specified as:
1402
- * proxy: {
1403
- * 'context': { options }
1404
- * }
1413
+ * proxy: { 'context': { options } }
1405
1414
  * OR
1406
- * proxy: {
1407
- * 'context': 'target'
1408
- * }
1415
+ * proxy: { 'context': 'target' }
1409
1416
  */
1410
1417
  if (typeof options.proxy !== "undefined") {
1411
1418
  options.proxy = options.proxy.map((item) => {
@@ -1414,8 +1421,8 @@ class Server {
1414
1421
  }
1415
1422
 
1416
1423
  /**
1417
- * @param {"info" | "warn" | "error" | "debug" | "silent" | undefined | "none" | "log" | "verbose"} level
1418
- * @returns {"info" | "warn" | "error" | "debug" | "silent" | undefined}
1424
+ * @param {"info" | "warn" | "error" | "debug" | "silent" | undefined | "none" | "log" | "verbose"} level level
1425
+ * @returns {"info" | "warn" | "error" | "debug" | "silent" | undefined} log level for proxy
1419
1426
  */
1420
1427
  const getLogLevelForProxy = (level) => {
1421
1428
  if (level === "none") {
@@ -1540,7 +1547,7 @@ class Server {
1540
1547
 
1541
1548
  /**
1542
1549
  * @private
1543
- * @returns {string}
1550
+ * @returns {string} client transport
1544
1551
  */
1545
1552
  getClientTransport() {
1546
1553
  let clientImplementation;
@@ -1552,7 +1559,7 @@ class Server {
1552
1559
  /** @type {WebSocketServerConfiguration} */
1553
1560
  (this.options.webSocketServer).type
1554
1561
  ) === "string" &&
1555
- // @ts-ignore
1562
+ // @ts-expect-error
1556
1563
  (this.options.webSocketServer.type === "ws" ||
1557
1564
  /** @type {WebSocketServerConfiguration} */
1558
1565
  (this.options.webSocketServer).type === "sockjs");
@@ -1594,7 +1601,7 @@ class Server {
1594
1601
  } else {
1595
1602
  try {
1596
1603
  clientImplementation = require.resolve(clientTransport);
1597
- } catch (e) {
1604
+ } catch {
1598
1605
  clientImplementationFound = false;
1599
1606
  }
1600
1607
  }
@@ -1619,7 +1626,7 @@ class Server {
1619
1626
  /**
1620
1627
  * @template T
1621
1628
  * @private
1622
- * @returns {T}
1629
+ * @returns {T} server transport
1623
1630
  */
1624
1631
  getServerTransport() {
1625
1632
  let implementation;
@@ -1647,12 +1654,11 @@ class Server {
1647
1654
  implementation = require("./servers/WebsocketServer");
1648
1655
  } else {
1649
1656
  try {
1650
- // eslint-disable-next-line import/no-dynamic-require
1651
1657
  implementation = require(
1652
1658
  /** @type {WebSocketServerConfiguration} */
1653
1659
  (this.options.webSocketServer).type,
1654
1660
  );
1655
- } catch (error) {
1661
+ } catch {
1656
1662
  implementationFound = false;
1657
1663
  }
1658
1664
  }
@@ -1680,13 +1686,13 @@ class Server {
1680
1686
  /**
1681
1687
  * @returns {string}
1682
1688
  */
1683
- // eslint-disable-next-line class-methods-use-this
1689
+
1684
1690
  getClientEntry() {
1685
1691
  return require.resolve("../client/index.js");
1686
1692
  }
1687
1693
 
1688
1694
  /**
1689
- * @returns {string | void}
1695
+ * @returns {string | void} client hot entry
1690
1696
  */
1691
1697
  getClientHotEntry() {
1692
1698
  if (this.options.hot === "only") {
@@ -1702,17 +1708,17 @@ class Server {
1702
1708
  */
1703
1709
  setupProgressPlugin() {
1704
1710
  const { ProgressPlugin } =
1705
- /** @type {MultiCompiler}*/
1711
+ /** @type {MultiCompiler} */
1706
1712
  (this.compiler).compilers
1707
- ? /** @type {MultiCompiler}*/ (this.compiler).compilers[0].webpack
1708
- : /** @type {Compiler}*/ (this.compiler).webpack;
1713
+ ? /** @type {MultiCompiler} */ (this.compiler).compilers[0].webpack
1714
+ : /** @type {Compiler} */ (this.compiler).webpack;
1709
1715
 
1710
1716
  new ProgressPlugin(
1711
1717
  /**
1712
- * @param {number} percent
1713
- * @param {string} msg
1714
- * @param {string} addInfo
1715
- * @param {string} pluginName
1718
+ * @param {number} percent percent
1719
+ * @param {string} msg message
1720
+ * @param {string} addInfo extra information
1721
+ * @param {string} pluginName plugin name
1716
1722
  */
1717
1723
  (percent, msg, addInfo, pluginName) => {
1718
1724
  percent = Math.floor(percent * 100);
@@ -1757,7 +1763,6 @@ class Server {
1757
1763
 
1758
1764
  for (const compiler of compilers) {
1759
1765
  if (compiler.options.devServer === false) {
1760
- // eslint-disable-next-line no-continue
1761
1766
  continue;
1762
1767
  }
1763
1768
 
@@ -1771,12 +1776,14 @@ class Server {
1771
1776
 
1772
1777
  if (this.options.hot) {
1773
1778
  const HMRPluginExists = compiler.options.plugins.find(
1774
- (p) => p && p.constructor === webpack.HotModuleReplacementPlugin,
1779
+ (plugin) =>
1780
+ plugin &&
1781
+ plugin.constructor === webpack.HotModuleReplacementPlugin,
1775
1782
  );
1776
1783
 
1777
1784
  if (HMRPluginExists) {
1778
1785
  this.logger.warn(
1779
- `"hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.`,
1786
+ '"hot: true" automatically applies HMR plugin, you don\'t have to add it manually to your webpack configuration.',
1780
1787
  );
1781
1788
  } else {
1782
1789
  // Apply the HMR plugin
@@ -1804,9 +1811,11 @@ class Server {
1804
1811
 
1805
1812
  let needForceShutdown = false;
1806
1813
 
1807
- signals.forEach((signal) => {
1814
+ for (const signal of signals) {
1815
+ // eslint-disable-next-line no-loop-func
1808
1816
  const listener = () => {
1809
1817
  if (needForceShutdown) {
1818
+ // eslint-disable-next-line n/no-process-exit
1810
1819
  process.exit();
1811
1820
  }
1812
1821
 
@@ -1819,9 +1828,11 @@ class Server {
1819
1828
  this.stopCallback(() => {
1820
1829
  if (typeof this.compiler.close === "function") {
1821
1830
  this.compiler.close(() => {
1831
+ // eslint-disable-next-line n/no-process-exit
1822
1832
  process.exit();
1823
1833
  });
1824
1834
  } else {
1835
+ // eslint-disable-next-line n/no-process-exit
1825
1836
  process.exit();
1826
1837
  }
1827
1838
  });
@@ -1830,7 +1841,7 @@ class Server {
1830
1841
  this.listeners.push({ name: signal, listener });
1831
1842
 
1832
1843
  process.on(signal, listener);
1833
- });
1844
+ }
1834
1845
  }
1835
1846
 
1836
1847
  // Proxy WebSocket without the initial http request
@@ -1854,26 +1865,32 @@ class Server {
1854
1865
  * @returns {Promise<void>}
1855
1866
  */
1856
1867
  async setupApp() {
1857
- /** @type {A | undefined}*/
1868
+ /** @type {A | undefined} */
1858
1869
  this.app =
1859
- typeof this.options.app === "function"
1860
- ? await this.options.app()
1861
- : getExpress()();
1870
+ /** @type {A} */
1871
+ (
1872
+ typeof this.options.app === "function"
1873
+ ? await this.options.app()
1874
+ : getExpress()()
1875
+ );
1862
1876
  }
1863
1877
 
1864
1878
  /**
1865
1879
  * @private
1866
- * @param {Stats | MultiStats} statsObj
1867
- * @returns {StatsCompilation}
1880
+ * @param {Stats | MultiStats} statsObj stats
1881
+ * @returns {StatsCompilation} stats of compilation
1868
1882
  */
1869
1883
  getStats(statsObj) {
1870
1884
  const stats = Server.DEFAULT_STATS;
1871
1885
  const compilerOptions = this.getCompilerOptions();
1872
1886
 
1873
- // @ts-ignore
1874
- if (compilerOptions.stats && compilerOptions.stats.warningsFilter) {
1875
- // @ts-ignore
1876
- stats.warningsFilter = compilerOptions.stats.warningsFilter;
1887
+ if (
1888
+ compilerOptions.stats &&
1889
+ /** @type {StatsOptions} */ (compilerOptions.stats).warningsFilter
1890
+ ) {
1891
+ stats.warningsFilter =
1892
+ /** @type {StatsOptions} */
1893
+ (compilerOptions.stats).warningsFilter;
1877
1894
  }
1878
1895
 
1879
1896
  return statsObj.toJson(stats);
@@ -1892,7 +1909,7 @@ class Server {
1892
1909
  this.compiler.hooks.done.tap(
1893
1910
  "webpack-dev-server",
1894
1911
  /**
1895
- * @param {Stats | MultiStats} stats
1912
+ * @param {Stats | MultiStats} stats stats
1896
1913
  */
1897
1914
  (stats) => {
1898
1915
  if (this.webSocketServer) {
@@ -1952,9 +1969,9 @@ class Server {
1952
1969
  middlewares.push({
1953
1970
  name: "host-header-check",
1954
1971
  /**
1955
- * @param {Request} req
1956
- * @param {Response} res
1957
- * @param {NextFunction} next
1972
+ * @param {Request} req request
1973
+ * @param {Response} res response
1974
+ * @param {NextFunction} next next function
1958
1975
  * @returns {void}
1959
1976
  */
1960
1977
  middleware: (req, res, next) => {
@@ -1977,9 +1994,9 @@ class Server {
1977
1994
  middlewares.push({
1978
1995
  name: "cross-origin-header-check",
1979
1996
  /**
1980
- * @param {Request} req
1981
- * @param {Response} res
1982
- * @param {NextFunction} next
1997
+ * @param {Request} req request
1998
+ * @param {Response} res response
1999
+ * @param {NextFunction} next next function
1983
2000
  * @returns {void}
1984
2001
  */
1985
2002
  middleware: (req, res, next) => {
@@ -2053,9 +2070,9 @@ class Server {
2053
2070
  name: "webpack-dev-server-sockjs-bundle",
2054
2071
  path: "/__webpack_dev_server__/sockjs.bundle.js",
2055
2072
  /**
2056
- * @param {Request} req
2057
- * @param {Response} res
2058
- * @param {NextFunction} next
2073
+ * @param {Request} req request
2074
+ * @param {Response} res response
2075
+ * @param {NextFunction} next next function
2059
2076
  * @returns {void}
2060
2077
  */
2061
2078
  middleware: (req, res, next) => {
@@ -2081,7 +2098,7 @@ class Server {
2081
2098
  try {
2082
2099
  // TODO implement `inputFileSystem.createReadStream` in webpack
2083
2100
  stats = fs.statSync(clientPath);
2084
- } catch (err) {
2101
+ } catch {
2085
2102
  next();
2086
2103
  return;
2087
2104
  }
@@ -2102,9 +2119,9 @@ class Server {
2102
2119
  name: "webpack-dev-server-invalidate",
2103
2120
  path: "/webpack-dev-server/invalidate",
2104
2121
  /**
2105
- * @param {Request} req
2106
- * @param {Response} res
2107
- * @param {NextFunction} next
2122
+ * @param {Request} req request
2123
+ * @param {Response} res response
2124
+ * @param {NextFunction} next next function
2108
2125
  * @returns {void}
2109
2126
  */
2110
2127
  middleware: (req, res, next) => {
@@ -2123,9 +2140,9 @@ class Server {
2123
2140
  name: "webpack-dev-server-open-editor",
2124
2141
  path: "/webpack-dev-server/open-editor",
2125
2142
  /**
2126
- * @param {Request} req
2127
- * @param {Response} res
2128
- * @param {NextFunction} next
2143
+ * @param {Request} req request
2144
+ * @param {Response} res response
2145
+ * @param {NextFunction} next next function
2129
2146
  * @returns {void}
2130
2147
  */
2131
2148
  middleware: (req, res, next) => {
@@ -2144,7 +2161,6 @@ class Server {
2144
2161
  const fileName = params.get("fileName");
2145
2162
 
2146
2163
  if (typeof fileName === "string") {
2147
- // @ts-ignore
2148
2164
  const launchEditor = require("launch-editor");
2149
2165
 
2150
2166
  launchEditor(fileName);
@@ -2158,9 +2174,9 @@ class Server {
2158
2174
  name: "webpack-dev-server-assets",
2159
2175
  path: "/webpack-dev-server",
2160
2176
  /**
2161
- * @param {Request} req
2162
- * @param {Response} res
2163
- * @param {NextFunction} next
2177
+ * @param {Request} req request
2178
+ * @param {Response} res response
2179
+ * @param {NextFunction} next next function
2164
2180
  * @returns {void}
2165
2181
  */
2166
2182
  middleware: (req, res, next) => {
@@ -2196,13 +2212,12 @@ class Server {
2196
2212
  (/** @type {MultiStats} */ (stats).toJson().children)
2197
2213
  : [/** @type {Stats} */ (stats).toJson()];
2198
2214
 
2199
- res.write(`<h1>Assets Report:</h1>`);
2215
+ res.write("<h1>Assets Report:</h1>");
2200
2216
 
2201
2217
  for (const [index, item] of statsForPrint.entries()) {
2202
2218
  res.write("<div>");
2203
2219
 
2204
2220
  const name =
2205
- // eslint-disable-next-line no-nested-ternary
2206
2221
  typeof item.name !== "undefined"
2207
2222
  ? item.name
2208
2223
  : /** @type {MultiStats} */ (stats).stats
@@ -2242,8 +2257,8 @@ class Server {
2242
2257
  const { createProxyMiddleware } = require("http-proxy-middleware");
2243
2258
 
2244
2259
  /**
2245
- * @param {ProxyConfigArrayItem} proxyConfig
2246
- * @returns {RequestHandler | undefined}
2260
+ * @param {ProxyConfigArrayItem} proxyConfig proxy config
2261
+ * @returns {RequestHandler | undefined} request handler
2247
2262
  */
2248
2263
  const getProxyMiddleware = (proxyConfig) => {
2249
2264
  // It is possible to use the `bypass` method without a `target` or `router`.
@@ -2272,6 +2287,7 @@ class Server {
2272
2287
  };
2273
2288
 
2274
2289
  /**
2290
+ * @example
2275
2291
  * Assume a proxy configuration specified as:
2276
2292
  * proxy: [
2277
2293
  * {
@@ -2287,7 +2303,7 @@ class Server {
2287
2303
  * }
2288
2304
  * ]
2289
2305
  */
2290
- this.options.proxy.forEach((proxyConfigOrCallback) => {
2306
+ for (const proxyConfigOrCallback of this.options.proxy) {
2291
2307
  /**
2292
2308
  * @type {RequestHandler}
2293
2309
  */
@@ -2307,9 +2323,9 @@ class Server {
2307
2323
  }
2308
2324
 
2309
2325
  /**
2310
- * @param {Request} req
2311
- * @param {Response} res
2312
- * @param {NextFunction} next
2326
+ * @param {Request} req request
2327
+ * @param {Response} res response
2328
+ * @param {NextFunction} next next function
2313
2329
  * @returns {Promise<void>}
2314
2330
  */
2315
2331
  const handler = async (req, res, next) => {
@@ -2319,9 +2335,9 @@ class Server {
2319
2335
  if (newProxyConfig !== proxyConfig) {
2320
2336
  proxyConfig = newProxyConfig;
2321
2337
 
2322
- const socket = req.socket != null ? req.socket : req.connection;
2323
- // @ts-ignore
2324
- const server = socket != null ? socket.server : null;
2338
+ const socket = req.socket || req.connection;
2339
+ // @ts-expect-error
2340
+ const server = socket ? socket.server : null;
2325
2341
 
2326
2342
  if (server) {
2327
2343
  server.removeAllListeners("close");
@@ -2379,15 +2395,15 @@ class Server {
2379
2395
  name: "http-proxy-middleware-error-handler",
2380
2396
  middleware:
2381
2397
  /**
2382
- * @param {Error} error
2383
- * @param {Request} req
2384
- * @param {Response} res
2385
- * @param {NextFunction} next
2386
- * @returns {any}
2398
+ * @param {Error} error error
2399
+ * @param {Request} req request
2400
+ * @param {Response} res response
2401
+ * @param {NextFunction} next next function
2402
+ * @returns {Promise<void>} nothing
2387
2403
  */
2388
2404
  (error, req, res, next) => handler(req, res, next),
2389
2405
  });
2390
- });
2406
+ }
2391
2407
 
2392
2408
  middlewares.push({
2393
2409
  name: "webpack-dev-middleware",
@@ -2416,6 +2432,7 @@ class Server {
2416
2432
 
2417
2433
  if (this.options.historyApiFallback) {
2418
2434
  const connectHistoryApiFallback = require("connect-history-api-fallback");
2435
+
2419
2436
  const { historyApiFallback } = this.options;
2420
2437
 
2421
2438
  if (
@@ -2428,7 +2445,7 @@ class Server {
2428
2445
  (historyApiFallback).verbose
2429
2446
  )
2430
2447
  ) {
2431
- // @ts-ignore
2448
+ // @ts-expect-error
2432
2449
  historyApiFallback.logger = this.logger.log.bind(
2433
2450
  this.logger,
2434
2451
  "[connect-history-api-fallback]",
@@ -2477,9 +2494,9 @@ class Server {
2477
2494
  name: "serve-index",
2478
2495
  path: publicPath,
2479
2496
  /**
2480
- * @param {Request} req
2481
- * @param {Response} res
2482
- * @param {NextFunction} next
2497
+ * @param {Request} req request
2498
+ * @param {Response} res response
2499
+ * @param {NextFunction} next next function
2483
2500
  * @returns {void}
2484
2501
  */
2485
2502
  middleware: (req, res, next) => {
@@ -2505,9 +2522,9 @@ class Server {
2505
2522
  middlewares.push({
2506
2523
  name: "options-middleware",
2507
2524
  /**
2508
- * @param {Request} req
2509
- * @param {Response} res
2510
- * @param {NextFunction} next
2525
+ * @param {Request} req request
2526
+ * @param {Response} res response
2527
+ * @param {NextFunction} next next function
2511
2528
  * @returns {void}
2512
2529
  */
2513
2530
  middleware: (req, res, next) => {
@@ -2585,7 +2602,7 @@ class Server {
2585
2602
  (this.options.server);
2586
2603
 
2587
2604
  if (typeof type === "function") {
2588
- /** @type {S | undefined}*/
2605
+ /** @type {S | undefined} */
2589
2606
  this.server = await type(
2590
2607
  /** @type {ServerOptions} */
2591
2608
  (options),
@@ -2593,10 +2610,9 @@ class Server {
2593
2610
  (this.app),
2594
2611
  );
2595
2612
  } else {
2596
- // eslint-disable-next-line import/no-dynamic-require
2597
2613
  const serverType = require(/** @type {string} */ (type));
2598
2614
 
2599
- /** @type {S | undefined}*/
2615
+ /** @type {S | undefined} */
2600
2616
  this.server =
2601
2617
  type === "http2"
2602
2618
  ? serverType.createSecureServer(
@@ -2615,7 +2631,7 @@ class Server {
2615
2631
  (this.server).on(
2616
2632
  "connection",
2617
2633
  /**
2618
- * @param {Socket} socket
2634
+ * @param {Socket} socket connected socket
2619
2635
  */
2620
2636
  (socket) => {
2621
2637
  // Add socket to list
@@ -2632,7 +2648,7 @@ class Server {
2632
2648
  (this.server).on(
2633
2649
  "error",
2634
2650
  /**
2635
- * @param {Error} error
2651
+ * @param {Error} error error
2636
2652
  */
2637
2653
  (error) => {
2638
2654
  throw error;
@@ -2652,13 +2668,12 @@ class Server {
2652
2668
  (this.webSocketServer).implementation.on(
2653
2669
  "connection",
2654
2670
  /**
2655
- * @param {ClientConnection} client
2656
- * @param {IncomingMessage} request
2671
+ * @param {ClientConnection} client client
2672
+ * @param {IncomingMessage} request request
2657
2673
  */
2658
2674
  (client, request) => {
2659
2675
  /** @type {{ [key: string]: string | undefined } | undefined} */
2660
2676
  const headers =
2661
- // eslint-disable-next-line no-nested-ternary
2662
2677
  typeof request !== "undefined"
2663
2678
  ? /** @type {{ [key: string]: string | undefined }} */
2664
2679
  (request.headers)
@@ -2666,8 +2681,7 @@ class Server {
2666
2681
  /** @type {import("sockjs").Connection} */ (client).headers
2667
2682
  ) !== "undefined"
2668
2683
  ? /** @type {import("sockjs").Connection} */ (client).headers
2669
- : // eslint-disable-next-line no-undefined
2670
- undefined;
2684
+ : undefined;
2671
2685
 
2672
2686
  if (!headers) {
2673
2687
  this.logger.warn(
@@ -2764,7 +2778,7 @@ class Server {
2764
2778
 
2765
2779
  /**
2766
2780
  * @private
2767
- * @param {string} defaultOpenTarget
2781
+ * @param {string} defaultOpenTarget default open target
2768
2782
  * @returns {Promise<void>}
2769
2783
  */
2770
2784
  async openBrowser(defaultOpenTarget) {
@@ -2816,6 +2830,7 @@ class Server {
2816
2830
  */
2817
2831
  runBonjour() {
2818
2832
  const { Bonjour } = require("bonjour-service");
2833
+
2819
2834
  const type = this.isTlsServer ? "https" : "http";
2820
2835
 
2821
2836
  /**
@@ -2834,6 +2849,7 @@ class Server {
2834
2849
 
2835
2850
  /**
2836
2851
  * @private
2852
+ * @param {() => void} callback callback
2837
2853
  * @returns {void}
2838
2854
  */
2839
2855
  stopBonjour(callback = () => {}) {
@@ -2853,11 +2869,11 @@ class Server {
2853
2869
  * @returns {Promise<void>}
2854
2870
  */
2855
2871
  async logStatus() {
2856
- const { isColorSupported, cyan, red } = require("colorette");
2872
+ const { cyan, isColorSupported, red } = require("colorette");
2857
2873
 
2858
2874
  /**
2859
- * @param {Compiler["options"]} compilerOptions
2860
- * @returns {boolean}
2875
+ * @param {Compiler["options"]} compilerOptions compiler options
2876
+ * @returns {boolean} value of the color option
2861
2877
  */
2862
2878
  const getColorsOption = (compilerOptions) => {
2863
2879
  /**
@@ -2882,9 +2898,9 @@ class Server {
2882
2898
 
2883
2899
  const colors = {
2884
2900
  /**
2885
- * @param {boolean} useColor
2886
- * @param {string} msg
2887
- * @returns {string}
2901
+ * @param {boolean} useColor need to use color?
2902
+ * @param {string} msg message
2903
+ * @returns {string} message with color
2888
2904
  */
2889
2905
  info(useColor, msg) {
2890
2906
  if (useColor) {
@@ -2894,9 +2910,9 @@ class Server {
2894
2910
  return msg;
2895
2911
  },
2896
2912
  /**
2897
- * @param {boolean} useColor
2898
- * @param {string} msg
2899
- * @returns {string}
2913
+ * @param {boolean} useColor need to use color?
2914
+ * @param {string} msg message
2915
+ * @returns {string} message with colors
2900
2916
  */
2901
2917
  error(useColor, msg) {
2902
2918
  if (useColor) {
@@ -2918,8 +2934,8 @@ class Server {
2918
2934
  /** @type {import("net").AddressInfo} */
2919
2935
  (server.address());
2920
2936
  /**
2921
- * @param {string} newHostname
2922
- * @returns {string}
2937
+ * @param {string} newHostname new hostname
2938
+ * @returns {string} prettified URL
2923
2939
  */
2924
2940
  const prettyPrintURL = (newHostname) =>
2925
2941
  url.format({ protocol, hostname: newHostname, port, pathname: "/" });
@@ -2939,7 +2955,7 @@ class Server {
2939
2955
 
2940
2956
  try {
2941
2957
  isIP = ipaddr.parse(this.options.host);
2942
- } catch (error) {
2958
+ } catch {
2943
2959
  // Ignore
2944
2960
  }
2945
2961
 
@@ -3073,9 +3089,9 @@ class Server {
3073
3089
 
3074
3090
  /**
3075
3091
  * @private
3076
- * @param {Request} req
3077
- * @param {Response} res
3078
- * @param {NextFunction} next
3092
+ * @param {Request} req request
3093
+ * @param {Response} res response
3094
+ * @param {NextFunction} next next function
3079
3095
  */
3080
3096
  setHeaders(req, res, next) {
3081
3097
  let { headers } = this.options;
@@ -3085,21 +3101,22 @@ class Server {
3085
3101
  headers = headers(
3086
3102
  req,
3087
3103
  res,
3088
- // eslint-disable-next-line no-undefined
3104
+
3089
3105
  this.middleware ? this.middleware.context : undefined,
3090
3106
  );
3091
3107
  }
3092
3108
 
3093
3109
  /**
3094
- * @type {{key: string, value: string}[]}
3110
+ * @type {{ key: string, value: string }[]}
3095
3111
  */
3096
3112
  const allHeaders = [];
3097
3113
 
3098
3114
  if (!Array.isArray(headers)) {
3099
- // eslint-disable-next-line guard-for-in
3100
3115
  for (const name in headers) {
3101
- // @ts-ignore
3102
- allHeaders.push({ key: name, value: headers[name] });
3116
+ allHeaders.push({
3117
+ key: name,
3118
+ value: /** @type {string} */ (headers[name]),
3119
+ });
3103
3120
  }
3104
3121
 
3105
3122
  headers = allHeaders;
@@ -3115,8 +3132,8 @@ class Server {
3115
3132
 
3116
3133
  /**
3117
3134
  * @private
3118
- * @param {string} value
3119
- * @returns {boolean}
3135
+ * @param {string} value value
3136
+ * @returns {boolean} true when host allowed, otherwise false
3120
3137
  */
3121
3138
  isHostAllowed(value) {
3122
3139
  const { allowedHosts } = this.options;
@@ -3137,16 +3154,14 @@ class Server {
3137
3154
 
3138
3155
  // support "." as a subdomain wildcard
3139
3156
  // e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
3140
- if (allowedHost.startsWith(".")) {
3141
- // "example.com" (value === allowedHost.substring(1))
3157
+ if (
3158
+ allowedHost.startsWith(".") && // "example.com" (value === allowedHost.substring(1))
3142
3159
  // "*.example.com" (value.endsWith(allowedHost))
3143
- if (
3144
- value === allowedHost.substring(1) ||
3160
+ (value === allowedHost.slice(1) ||
3145
3161
  /** @type {string} */
3146
- (value).endsWith(allowedHost)
3147
- ) {
3148
- return true;
3149
- }
3162
+ (value).endsWith(allowedHost))
3163
+ ) {
3164
+ return true;
3150
3165
  }
3151
3166
  }
3152
3167
  }
@@ -3171,10 +3186,10 @@ class Server {
3171
3186
 
3172
3187
  /**
3173
3188
  * @private
3174
- * @param {{ [key: string]: string | undefined }} headers
3175
- * @param {string} headerToCheck
3176
- * @param {boolean} validateHost
3177
- * @returns {boolean}
3189
+ * @param {{ [key: string]: string | undefined }} headers headers
3190
+ * @param {string} headerToCheck header to check
3191
+ * @param {boolean} validateHost need to validate host
3192
+ * @returns {boolean} true when host is valid, otherwise false
3178
3193
  */
3179
3194
  isValidHost(headers, headerToCheck, validateHost = true) {
3180
3195
  if (this.options.allowedHosts === "all") {
@@ -3194,12 +3209,14 @@ class Server {
3194
3209
  }
3195
3210
 
3196
3211
  // use the node url-parser to retrieve the hostname from the host-header.
3197
- const hostname = url.parse(
3212
+ // TODO resolve me in the next major release
3213
+ // eslint-disable-next-line n/no-deprecated-api
3214
+ const { hostname } = url.parse(
3198
3215
  // if header doesn't have scheme, add // for parsing.
3199
3216
  /^(.+:)?\/\//.test(header) ? header : `//${header}`,
3200
3217
  false,
3201
3218
  true,
3202
- ).hostname;
3219
+ );
3203
3220
 
3204
3221
  if (hostname === null) {
3205
3222
  return false;
@@ -3231,8 +3248,8 @@ class Server {
3231
3248
 
3232
3249
  /**
3233
3250
  * @private
3234
- * @param {{ [key: string]: string | undefined }} headers
3235
- * @returns {boolean}
3251
+ * @param {{ [key: string]: string | undefined }} headers headers
3252
+ * @returns {boolean} true when is same origin, otherwise false
3236
3253
  */
3237
3254
  isSameOrigin(headers) {
3238
3255
  if (this.options.allowedHosts === "all") {
@@ -3249,6 +3266,8 @@ class Server {
3249
3266
  return true;
3250
3267
  }
3251
3268
 
3269
+ // TODO resolve me in the next major release
3270
+ // eslint-disable-next-line n/no-deprecated-api
3252
3271
  const origin = url.parse(originHeader, false, true).hostname;
3253
3272
 
3254
3273
  if (origin === null) {
@@ -3269,6 +3288,7 @@ class Server {
3269
3288
  return true;
3270
3289
  }
3271
3290
 
3291
+ // eslint-disable-next-line n/no-deprecated-api
3272
3292
  const host = url.parse(
3273
3293
  // if hostHeader doesn't have scheme, add // for parsing.
3274
3294
  /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`,
@@ -3288,12 +3308,11 @@ class Server {
3288
3308
  }
3289
3309
 
3290
3310
  /**
3291
- * @param {ClientConnection[]} clients
3292
- * @param {string} type
3293
- * @param {any} [data]
3294
- * @param {any} [params]
3311
+ * @param {ClientConnection[]} clients clients
3312
+ * @param {string} type type
3313
+ * @param {EXPECTED_ANY=} data data
3314
+ * @param {EXPECTED_ANY=} params params
3295
3315
  */
3296
- // eslint-disable-next-line class-methods-use-this
3297
3316
  sendMessage(clients, type, data, params) {
3298
3317
  for (const client of clients) {
3299
3318
  // `sockjs` uses `1` to indicate client is ready to accept data
@@ -3307,9 +3326,9 @@ class Server {
3307
3326
  // Send stats to a socket or multiple sockets
3308
3327
  /**
3309
3328
  * @private
3310
- * @param {ClientConnection[]} clients
3311
- * @param {StatsCompilation} stats
3312
- * @param {boolean} [force]
3329
+ * @param {ClientConnection[]} clients clients
3330
+ * @param {StatsCompilation} stats stats
3331
+ * @param {boolean=} force force
3313
3332
  */
3314
3333
  sendStats(clients, stats, force) {
3315
3334
  const shouldEmit =
@@ -3363,11 +3382,12 @@ class Server {
3363
3382
  }
3364
3383
 
3365
3384
  /**
3366
- * @param {string | string[]} watchPath
3367
- * @param {WatchOptions} [watchOptions]
3385
+ * @param {string | string[]} watchPath watch path
3386
+ * @param {WatchOptions=} watchOptions watch options
3368
3387
  */
3369
3388
  watchFiles(watchPath, watchOptions) {
3370
3389
  const chokidar = require("chokidar");
3390
+
3371
3391
  const watcher = chokidar.watch(watchPath, watchOptions);
3372
3392
 
3373
3393
  // disabling refreshing on changing the content
@@ -3387,7 +3407,7 @@ class Server {
3387
3407
  }
3388
3408
 
3389
3409
  /**
3390
- * @param {import("webpack-dev-middleware").Callback} [callback]
3410
+ * @param {import("webpack-dev-middleware").Callback=} callback callback
3391
3411
  */
3392
3412
  invalidate(callback = () => {}) {
3393
3413
  if (this.middleware) {
@@ -3404,13 +3424,14 @@ class Server {
3404
3424
  if (this.options.ipc) {
3405
3425
  await /** @type {Promise<void>} */ (
3406
3426
  new Promise((resolve, reject) => {
3407
- const net = require("net");
3427
+ const net = require("node:net");
3428
+
3408
3429
  const socket = new net.Socket();
3409
3430
 
3410
3431
  socket.on(
3411
3432
  "error",
3412
3433
  /**
3413
- * @param {Error & { code?: string }} error
3434
+ * @param {Error & { code?: string }} error error
3414
3435
  */
3415
3436
  (error) => {
3416
3437
  if (error.code === "ECONNREFUSED") {
@@ -3489,7 +3510,7 @@ class Server {
3489
3510
  }
3490
3511
 
3491
3512
  /**
3492
- * @param {(err?: Error) => void} [callback]
3513
+ * @param {((err?: Error) => void)=} callback callback
3493
3514
  */
3494
3515
  startCallback(callback = () => {}) {
3495
3516
  this.start()
@@ -3544,7 +3565,6 @@ class Server {
3544
3565
  new Promise((resolve) => {
3545
3566
  /** @type {S} */
3546
3567
  (this.server).close(() => {
3547
- // eslint-disable-next-line no-undefined
3548
3568
  this.server = undefined;
3549
3569
  resolve();
3550
3570
  });
@@ -3560,7 +3580,7 @@ class Server {
3560
3580
  if (this.middleware) {
3561
3581
  await /** @type {Promise<void>} */ (
3562
3582
  new Promise((resolve, reject) => {
3563
- /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
3583
+ /** @type {import("webpack-dev-middleware").API<Request, Response>} */
3564
3584
  (this.middleware).close((error) => {
3565
3585
  if (error) {
3566
3586
  reject(error);
@@ -3572,7 +3592,6 @@ class Server {
3572
3592
  })
3573
3593
  );
3574
3594
 
3575
- // eslint-disable-next-line no-undefined
3576
3595
  this.middleware = undefined;
3577
3596
  }
3578
3597
  }
@@ -3585,7 +3604,7 @@ class Server {
3585
3604
  }
3586
3605
 
3587
3606
  /**
3588
- * @param {(err?: Error) => void} [callback]
3607
+ * @param {((err?: Error) => void)=} callback callback
3589
3608
  */
3590
3609
  stopCallback(callback = () => {}) {
3591
3610
  this.stop()