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/README.md +4 -4
- package/bin/webpack-dev-server.js +17 -16
- package/client/clients/SockJSClient.js +18 -20
- package/client/clients/WebSocketClient.js +17 -11
- package/client/index.js +111 -72
- package/client/modules/logger/index.js +42 -35
- package/client/modules/sockjs-client/index.js +0 -1
- package/client/overlay.js +129 -79
- package/client/progress.js +40 -13
- package/client/socket.js +17 -13
- package/client/utils/log.js +1 -1
- package/client/utils/sendMessage.js +5 -3
- package/lib/Server.js +336 -317
- package/lib/getPort.js +21 -22
- package/lib/servers/BaseServer.js +1 -1
- package/lib/servers/SockJSServer.js +16 -14
- package/lib/servers/WebsocketServer.js +17 -22
- package/package.json +36 -31
- package/types/bin/webpack-dev-server.d.ts +1 -1
- package/types/lib/Server.d.ts +216 -149
- package/types/lib/getPort.d.ts +3 -3
- package/types/lib/servers/BaseServer.d.ts +1 -1
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
|
-
|
|
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:
|
|
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 {
|
|
83
|
-
* @property {string | string[]} paths
|
|
84
|
-
* @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }}
|
|
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 {
|
|
89
|
-
* @property {string}
|
|
90
|
-
* @property {string | string[]}
|
|
91
|
-
* @property {boolean | ServeIndexOptions}
|
|
92
|
-
* @property {ServeStaticOptions}
|
|
93
|
-
* @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }}
|
|
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 {
|
|
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 |
|
|
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 {
|
|
115
|
-
* @property {ServerType<A, S
|
|
116
|
-
* @property {ServerOptions}
|
|
117
|
+
* @typedef {object} ServerConfiguration
|
|
118
|
+
* @property {ServerType<A, S>=} type type
|
|
119
|
+
* @property {ServerOptions=} options options
|
|
117
120
|
*/
|
|
118
121
|
|
|
119
122
|
/**
|
|
120
|
-
* @typedef {
|
|
121
|
-
* @property {"sockjs" | "ws" | string |
|
|
122
|
-
* @property {Record<string,
|
|
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 {
|
|
154
|
-
* @property {string}
|
|
155
|
-
* @property {string[]}
|
|
156
|
+
* @typedef {object} OpenApp
|
|
157
|
+
* @property {string=} name
|
|
158
|
+
* @property {string[]=} arguments
|
|
156
159
|
*/
|
|
157
160
|
|
|
158
161
|
/**
|
|
159
|
-
* @typedef {
|
|
160
|
-
* @property {string | string[] | OpenApp}
|
|
161
|
-
* @property {string | string[]}
|
|
162
|
+
* @typedef {object} Open
|
|
163
|
+
* @property {(string | string[] | OpenApp)=} app
|
|
164
|
+
* @property {(string | string[])=} target target
|
|
162
165
|
*/
|
|
163
166
|
|
|
164
167
|
/**
|
|
165
|
-
* @typedef {
|
|
168
|
+
* @typedef {object} NormalizedOpen
|
|
166
169
|
* @property {string} target
|
|
167
170
|
* @property {import("open").Options} options
|
|
168
171
|
*/
|
|
169
172
|
|
|
170
173
|
/**
|
|
171
|
-
* @typedef {
|
|
172
|
-
* @property {string}
|
|
173
|
-
* @property {string}
|
|
174
|
-
* @property {string}
|
|
175
|
-
* @property {number | string}
|
|
176
|
-
* @property {string}
|
|
177
|
-
* @property {string}
|
|
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 {
|
|
186
|
-
* @property {"log" | "info" | "warn" | "error" | "none" | "verbose"}
|
|
187
|
-
* @property {boolean
|
|
188
|
-
* @property {boolean}
|
|
189
|
-
* @property {boolean | number}
|
|
190
|
-
* @property {"ws" | "sockjs" | string}
|
|
191
|
-
* @property {string | 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 {
|
|
217
|
-
* @property {boolean | string}
|
|
218
|
-
* @property {Host}
|
|
219
|
-
* @property {Port}
|
|
220
|
-
* @property {boolean | "only"}
|
|
221
|
-
* @property {boolean}
|
|
222
|
-
* @property {DevMiddlewareOptions<Request, Response
|
|
223
|
-
* @property {boolean}
|
|
224
|
-
* @property {"auto" | "all" | string | string[]}
|
|
225
|
-
* @property {boolean | ConnectHistoryApiFallbackOptions}
|
|
226
|
-
* @property {boolean | Record<string, never> | BonjourOptions}
|
|
227
|
-
* @property {string | string[] | WatchFiles | Array<string | WatchFiles>}
|
|
228
|
-
* @property {boolean | string | Static | Array<string | Static>}
|
|
229
|
-
* @property {ServerType<A, S> | ServerConfiguration<A, S>}
|
|
230
|
-
* @property {() => Promise<A>}
|
|
231
|
-
* @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration}
|
|
232
|
-
* @property {ProxyConfigArray}
|
|
233
|
-
* @property {boolean | string | Open | Array<string | Open>}
|
|
234
|
-
* @property {boolean}
|
|
235
|
-
* @property {boolean | ClientConfiguration}
|
|
236
|
-
* @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response> | undefined) => Headers)}
|
|
237
|
-
* @property {(devServer: Server<A, S>) => void}
|
|
238
|
-
* @property {(middlewares: Middleware[], devServer: Server<A, S>) => Middleware[]}
|
|
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
|
-
* @
|
|
248
|
-
|
|
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 =
|
|
267
|
+
result = fn();
|
|
261
268
|
cache = true;
|
|
262
269
|
// Allow to clean up memory for fn
|
|
263
270
|
// and all dependent resources
|
|
264
|
-
|
|
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
|
-
* @
|
|
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 {
|
|
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
|
|
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:
|
|
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
|
-
|
|
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}
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
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
|
-
?
|
|
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
|
-
?
|
|
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
|
|
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
|
|
1184
|
+
} catch {
|
|
1188
1185
|
// Ignore error
|
|
1189
1186
|
}
|
|
1190
1187
|
|
|
@@ -1193,10 +1190,18 @@ class Server {
|
|
|
1193
1190
|
}
|
|
1194
1191
|
};
|
|
1195
1192
|
|
|
1196
|
-
/** @type {
|
|
1193
|
+
/** @type {EXPECTED_ANY} */
|
|
1197
1194
|
(serverOptions)[property] = Array.isArray(value)
|
|
1198
|
-
? value.map((item) =>
|
|
1199
|
-
|
|
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 =
|
|
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
|
|
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
|
|
1317
|
-
serverOptions.cert
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
(
|
|
1779
|
+
(plugin) =>
|
|
1780
|
+
plugin &&
|
|
1781
|
+
plugin.constructor === webpack.HotModuleReplacementPlugin,
|
|
1775
1782
|
);
|
|
1776
1783
|
|
|
1777
1784
|
if (HMRPluginExists) {
|
|
1778
1785
|
this.logger.warn(
|
|
1779
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
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
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
2323
|
-
// @ts-
|
|
2324
|
-
const server = socket
|
|
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 {
|
|
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-
|
|
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
|
-
:
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
3102
|
-
|
|
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 (
|
|
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
|
-
|
|
3144
|
-
value === allowedHost.substring(1) ||
|
|
3160
|
+
(value === allowedHost.slice(1) ||
|
|
3145
3161
|
/** @type {string} */
|
|
3146
|
-
(value).endsWith(allowedHost)
|
|
3147
|
-
|
|
3148
|
-
|
|
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
|
-
|
|
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
|
-
)
|
|
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 {
|
|
3294
|
-
* @param {
|
|
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}
|
|
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}
|
|
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}
|
|
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}
|
|
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}
|
|
3607
|
+
* @param {((err?: Error) => void)=} callback callback
|
|
3589
3608
|
*/
|
|
3590
3609
|
stopCallback(callback = () => {}) {
|
|
3591
3610
|
this.stop()
|