webpack-dev-server 5.2.1 → 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 +112 -73
- package/client/modules/logger/index.js +46 -40
- package/client/modules/sockjs-client/index.js +0 -1
- package/client/overlay.js +131 -80
- 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 +354 -336
- 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 +39 -34
- package/types/bin/webpack-dev-server.d.ts +1 -1
- package/types/lib/Server.d.ts +216 -148
- 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,15 +1994,22 @@ 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) => {
|
|
1986
2003
|
const headers =
|
|
1987
2004
|
/** @type {{ [key: string]: string | undefined }} */
|
|
1988
2005
|
(req.headers);
|
|
2006
|
+
const headerName = headers[":authority"] ? ":authority" : "host";
|
|
2007
|
+
|
|
2008
|
+
if (this.isValidHost(headers, headerName, false)) {
|
|
2009
|
+
next();
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1989
2013
|
if (
|
|
1990
2014
|
headers["sec-fetch-mode"] === "no-cors" &&
|
|
1991
2015
|
headers["sec-fetch-site"] === "cross-site"
|
|
@@ -2046,9 +2070,9 @@ class Server {
|
|
|
2046
2070
|
name: "webpack-dev-server-sockjs-bundle",
|
|
2047
2071
|
path: "/__webpack_dev_server__/sockjs.bundle.js",
|
|
2048
2072
|
/**
|
|
2049
|
-
* @param {Request} req
|
|
2050
|
-
* @param {Response} res
|
|
2051
|
-
* @param {NextFunction} next
|
|
2073
|
+
* @param {Request} req request
|
|
2074
|
+
* @param {Response} res response
|
|
2075
|
+
* @param {NextFunction} next next function
|
|
2052
2076
|
* @returns {void}
|
|
2053
2077
|
*/
|
|
2054
2078
|
middleware: (req, res, next) => {
|
|
@@ -2074,7 +2098,7 @@ class Server {
|
|
|
2074
2098
|
try {
|
|
2075
2099
|
// TODO implement `inputFileSystem.createReadStream` in webpack
|
|
2076
2100
|
stats = fs.statSync(clientPath);
|
|
2077
|
-
} catch
|
|
2101
|
+
} catch {
|
|
2078
2102
|
next();
|
|
2079
2103
|
return;
|
|
2080
2104
|
}
|
|
@@ -2095,9 +2119,9 @@ class Server {
|
|
|
2095
2119
|
name: "webpack-dev-server-invalidate",
|
|
2096
2120
|
path: "/webpack-dev-server/invalidate",
|
|
2097
2121
|
/**
|
|
2098
|
-
* @param {Request} req
|
|
2099
|
-
* @param {Response} res
|
|
2100
|
-
* @param {NextFunction} next
|
|
2122
|
+
* @param {Request} req request
|
|
2123
|
+
* @param {Response} res response
|
|
2124
|
+
* @param {NextFunction} next next function
|
|
2101
2125
|
* @returns {void}
|
|
2102
2126
|
*/
|
|
2103
2127
|
middleware: (req, res, next) => {
|
|
@@ -2116,9 +2140,9 @@ class Server {
|
|
|
2116
2140
|
name: "webpack-dev-server-open-editor",
|
|
2117
2141
|
path: "/webpack-dev-server/open-editor",
|
|
2118
2142
|
/**
|
|
2119
|
-
* @param {Request} req
|
|
2120
|
-
* @param {Response} res
|
|
2121
|
-
* @param {NextFunction} next
|
|
2143
|
+
* @param {Request} req request
|
|
2144
|
+
* @param {Response} res response
|
|
2145
|
+
* @param {NextFunction} next next function
|
|
2122
2146
|
* @returns {void}
|
|
2123
2147
|
*/
|
|
2124
2148
|
middleware: (req, res, next) => {
|
|
@@ -2137,7 +2161,6 @@ class Server {
|
|
|
2137
2161
|
const fileName = params.get("fileName");
|
|
2138
2162
|
|
|
2139
2163
|
if (typeof fileName === "string") {
|
|
2140
|
-
// @ts-ignore
|
|
2141
2164
|
const launchEditor = require("launch-editor");
|
|
2142
2165
|
|
|
2143
2166
|
launchEditor(fileName);
|
|
@@ -2151,9 +2174,9 @@ class Server {
|
|
|
2151
2174
|
name: "webpack-dev-server-assets",
|
|
2152
2175
|
path: "/webpack-dev-server",
|
|
2153
2176
|
/**
|
|
2154
|
-
* @param {Request} req
|
|
2155
|
-
* @param {Response} res
|
|
2156
|
-
* @param {NextFunction} next
|
|
2177
|
+
* @param {Request} req request
|
|
2178
|
+
* @param {Response} res response
|
|
2179
|
+
* @param {NextFunction} next next function
|
|
2157
2180
|
* @returns {void}
|
|
2158
2181
|
*/
|
|
2159
2182
|
middleware: (req, res, next) => {
|
|
@@ -2189,13 +2212,12 @@ class Server {
|
|
|
2189
2212
|
(/** @type {MultiStats} */ (stats).toJson().children)
|
|
2190
2213
|
: [/** @type {Stats} */ (stats).toJson()];
|
|
2191
2214
|
|
|
2192
|
-
res.write(
|
|
2215
|
+
res.write("<h1>Assets Report:</h1>");
|
|
2193
2216
|
|
|
2194
2217
|
for (const [index, item] of statsForPrint.entries()) {
|
|
2195
2218
|
res.write("<div>");
|
|
2196
2219
|
|
|
2197
2220
|
const name =
|
|
2198
|
-
// eslint-disable-next-line no-nested-ternary
|
|
2199
2221
|
typeof item.name !== "undefined"
|
|
2200
2222
|
? item.name
|
|
2201
2223
|
: /** @type {MultiStats} */ (stats).stats
|
|
@@ -2235,8 +2257,8 @@ class Server {
|
|
|
2235
2257
|
const { createProxyMiddleware } = require("http-proxy-middleware");
|
|
2236
2258
|
|
|
2237
2259
|
/**
|
|
2238
|
-
* @param {ProxyConfigArrayItem} proxyConfig
|
|
2239
|
-
* @returns {RequestHandler | undefined}
|
|
2260
|
+
* @param {ProxyConfigArrayItem} proxyConfig proxy config
|
|
2261
|
+
* @returns {RequestHandler | undefined} request handler
|
|
2240
2262
|
*/
|
|
2241
2263
|
const getProxyMiddleware = (proxyConfig) => {
|
|
2242
2264
|
// It is possible to use the `bypass` method without a `target` or `router`.
|
|
@@ -2265,6 +2287,7 @@ class Server {
|
|
|
2265
2287
|
};
|
|
2266
2288
|
|
|
2267
2289
|
/**
|
|
2290
|
+
* @example
|
|
2268
2291
|
* Assume a proxy configuration specified as:
|
|
2269
2292
|
* proxy: [
|
|
2270
2293
|
* {
|
|
@@ -2280,7 +2303,7 @@ class Server {
|
|
|
2280
2303
|
* }
|
|
2281
2304
|
* ]
|
|
2282
2305
|
*/
|
|
2283
|
-
this.options.proxy
|
|
2306
|
+
for (const proxyConfigOrCallback of this.options.proxy) {
|
|
2284
2307
|
/**
|
|
2285
2308
|
* @type {RequestHandler}
|
|
2286
2309
|
*/
|
|
@@ -2300,9 +2323,9 @@ class Server {
|
|
|
2300
2323
|
}
|
|
2301
2324
|
|
|
2302
2325
|
/**
|
|
2303
|
-
* @param {Request} req
|
|
2304
|
-
* @param {Response} res
|
|
2305
|
-
* @param {NextFunction} next
|
|
2326
|
+
* @param {Request} req request
|
|
2327
|
+
* @param {Response} res response
|
|
2328
|
+
* @param {NextFunction} next next function
|
|
2306
2329
|
* @returns {Promise<void>}
|
|
2307
2330
|
*/
|
|
2308
2331
|
const handler = async (req, res, next) => {
|
|
@@ -2312,9 +2335,9 @@ class Server {
|
|
|
2312
2335
|
if (newProxyConfig !== proxyConfig) {
|
|
2313
2336
|
proxyConfig = newProxyConfig;
|
|
2314
2337
|
|
|
2315
|
-
const socket = req.socket
|
|
2316
|
-
// @ts-
|
|
2317
|
-
const server = socket
|
|
2338
|
+
const socket = req.socket || req.connection;
|
|
2339
|
+
// @ts-expect-error
|
|
2340
|
+
const server = socket ? socket.server : null;
|
|
2318
2341
|
|
|
2319
2342
|
if (server) {
|
|
2320
2343
|
server.removeAllListeners("close");
|
|
@@ -2372,15 +2395,15 @@ class Server {
|
|
|
2372
2395
|
name: "http-proxy-middleware-error-handler",
|
|
2373
2396
|
middleware:
|
|
2374
2397
|
/**
|
|
2375
|
-
* @param {Error} error
|
|
2376
|
-
* @param {Request} req
|
|
2377
|
-
* @param {Response} res
|
|
2378
|
-
* @param {NextFunction} next
|
|
2379
|
-
* @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
|
|
2380
2403
|
*/
|
|
2381
2404
|
(error, req, res, next) => handler(req, res, next),
|
|
2382
2405
|
});
|
|
2383
|
-
}
|
|
2406
|
+
}
|
|
2384
2407
|
|
|
2385
2408
|
middlewares.push({
|
|
2386
2409
|
name: "webpack-dev-middleware",
|
|
@@ -2409,6 +2432,7 @@ class Server {
|
|
|
2409
2432
|
|
|
2410
2433
|
if (this.options.historyApiFallback) {
|
|
2411
2434
|
const connectHistoryApiFallback = require("connect-history-api-fallback");
|
|
2435
|
+
|
|
2412
2436
|
const { historyApiFallback } = this.options;
|
|
2413
2437
|
|
|
2414
2438
|
if (
|
|
@@ -2421,7 +2445,7 @@ class Server {
|
|
|
2421
2445
|
(historyApiFallback).verbose
|
|
2422
2446
|
)
|
|
2423
2447
|
) {
|
|
2424
|
-
// @ts-
|
|
2448
|
+
// @ts-expect-error
|
|
2425
2449
|
historyApiFallback.logger = this.logger.log.bind(
|
|
2426
2450
|
this.logger,
|
|
2427
2451
|
"[connect-history-api-fallback]",
|
|
@@ -2470,9 +2494,9 @@ class Server {
|
|
|
2470
2494
|
name: "serve-index",
|
|
2471
2495
|
path: publicPath,
|
|
2472
2496
|
/**
|
|
2473
|
-
* @param {Request} req
|
|
2474
|
-
* @param {Response} res
|
|
2475
|
-
* @param {NextFunction} next
|
|
2497
|
+
* @param {Request} req request
|
|
2498
|
+
* @param {Response} res response
|
|
2499
|
+
* @param {NextFunction} next next function
|
|
2476
2500
|
* @returns {void}
|
|
2477
2501
|
*/
|
|
2478
2502
|
middleware: (req, res, next) => {
|
|
@@ -2498,9 +2522,9 @@ class Server {
|
|
|
2498
2522
|
middlewares.push({
|
|
2499
2523
|
name: "options-middleware",
|
|
2500
2524
|
/**
|
|
2501
|
-
* @param {Request} req
|
|
2502
|
-
* @param {Response} res
|
|
2503
|
-
* @param {NextFunction} next
|
|
2525
|
+
* @param {Request} req request
|
|
2526
|
+
* @param {Response} res response
|
|
2527
|
+
* @param {NextFunction} next next function
|
|
2504
2528
|
* @returns {void}
|
|
2505
2529
|
*/
|
|
2506
2530
|
middleware: (req, res, next) => {
|
|
@@ -2578,7 +2602,7 @@ class Server {
|
|
|
2578
2602
|
(this.options.server);
|
|
2579
2603
|
|
|
2580
2604
|
if (typeof type === "function") {
|
|
2581
|
-
/** @type {S | undefined}*/
|
|
2605
|
+
/** @type {S | undefined} */
|
|
2582
2606
|
this.server = await type(
|
|
2583
2607
|
/** @type {ServerOptions} */
|
|
2584
2608
|
(options),
|
|
@@ -2586,10 +2610,9 @@ class Server {
|
|
|
2586
2610
|
(this.app),
|
|
2587
2611
|
);
|
|
2588
2612
|
} else {
|
|
2589
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
2590
2613
|
const serverType = require(/** @type {string} */ (type));
|
|
2591
2614
|
|
|
2592
|
-
/** @type {S | undefined}*/
|
|
2615
|
+
/** @type {S | undefined} */
|
|
2593
2616
|
this.server =
|
|
2594
2617
|
type === "http2"
|
|
2595
2618
|
? serverType.createSecureServer(
|
|
@@ -2608,7 +2631,7 @@ class Server {
|
|
|
2608
2631
|
(this.server).on(
|
|
2609
2632
|
"connection",
|
|
2610
2633
|
/**
|
|
2611
|
-
* @param {Socket} socket
|
|
2634
|
+
* @param {Socket} socket connected socket
|
|
2612
2635
|
*/
|
|
2613
2636
|
(socket) => {
|
|
2614
2637
|
// Add socket to list
|
|
@@ -2625,7 +2648,7 @@ class Server {
|
|
|
2625
2648
|
(this.server).on(
|
|
2626
2649
|
"error",
|
|
2627
2650
|
/**
|
|
2628
|
-
* @param {Error} error
|
|
2651
|
+
* @param {Error} error error
|
|
2629
2652
|
*/
|
|
2630
2653
|
(error) => {
|
|
2631
2654
|
throw error;
|
|
@@ -2645,13 +2668,12 @@ class Server {
|
|
|
2645
2668
|
(this.webSocketServer).implementation.on(
|
|
2646
2669
|
"connection",
|
|
2647
2670
|
/**
|
|
2648
|
-
* @param {ClientConnection} client
|
|
2649
|
-
* @param {IncomingMessage} request
|
|
2671
|
+
* @param {ClientConnection} client client
|
|
2672
|
+
* @param {IncomingMessage} request request
|
|
2650
2673
|
*/
|
|
2651
2674
|
(client, request) => {
|
|
2652
2675
|
/** @type {{ [key: string]: string | undefined } | undefined} */
|
|
2653
2676
|
const headers =
|
|
2654
|
-
// eslint-disable-next-line no-nested-ternary
|
|
2655
2677
|
typeof request !== "undefined"
|
|
2656
2678
|
? /** @type {{ [key: string]: string | undefined }} */
|
|
2657
2679
|
(request.headers)
|
|
@@ -2659,8 +2681,7 @@ class Server {
|
|
|
2659
2681
|
/** @type {import("sockjs").Connection} */ (client).headers
|
|
2660
2682
|
) !== "undefined"
|
|
2661
2683
|
? /** @type {import("sockjs").Connection} */ (client).headers
|
|
2662
|
-
:
|
|
2663
|
-
undefined;
|
|
2684
|
+
: undefined;
|
|
2664
2685
|
|
|
2665
2686
|
if (!headers) {
|
|
2666
2687
|
this.logger.warn(
|
|
@@ -2757,7 +2778,7 @@ class Server {
|
|
|
2757
2778
|
|
|
2758
2779
|
/**
|
|
2759
2780
|
* @private
|
|
2760
|
-
* @param {string} defaultOpenTarget
|
|
2781
|
+
* @param {string} defaultOpenTarget default open target
|
|
2761
2782
|
* @returns {Promise<void>}
|
|
2762
2783
|
*/
|
|
2763
2784
|
async openBrowser(defaultOpenTarget) {
|
|
@@ -2809,6 +2830,7 @@ class Server {
|
|
|
2809
2830
|
*/
|
|
2810
2831
|
runBonjour() {
|
|
2811
2832
|
const { Bonjour } = require("bonjour-service");
|
|
2833
|
+
|
|
2812
2834
|
const type = this.isTlsServer ? "https" : "http";
|
|
2813
2835
|
|
|
2814
2836
|
/**
|
|
@@ -2827,6 +2849,7 @@ class Server {
|
|
|
2827
2849
|
|
|
2828
2850
|
/**
|
|
2829
2851
|
* @private
|
|
2852
|
+
* @param {() => void} callback callback
|
|
2830
2853
|
* @returns {void}
|
|
2831
2854
|
*/
|
|
2832
2855
|
stopBonjour(callback = () => {}) {
|
|
@@ -2846,11 +2869,11 @@ class Server {
|
|
|
2846
2869
|
* @returns {Promise<void>}
|
|
2847
2870
|
*/
|
|
2848
2871
|
async logStatus() {
|
|
2849
|
-
const {
|
|
2872
|
+
const { cyan, isColorSupported, red } = require("colorette");
|
|
2850
2873
|
|
|
2851
2874
|
/**
|
|
2852
|
-
* @param {Compiler["options"]} compilerOptions
|
|
2853
|
-
* @returns {boolean}
|
|
2875
|
+
* @param {Compiler["options"]} compilerOptions compiler options
|
|
2876
|
+
* @returns {boolean} value of the color option
|
|
2854
2877
|
*/
|
|
2855
2878
|
const getColorsOption = (compilerOptions) => {
|
|
2856
2879
|
/**
|
|
@@ -2875,9 +2898,9 @@ class Server {
|
|
|
2875
2898
|
|
|
2876
2899
|
const colors = {
|
|
2877
2900
|
/**
|
|
2878
|
-
* @param {boolean} useColor
|
|
2879
|
-
* @param {string} msg
|
|
2880
|
-
* @returns {string}
|
|
2901
|
+
* @param {boolean} useColor need to use color?
|
|
2902
|
+
* @param {string} msg message
|
|
2903
|
+
* @returns {string} message with color
|
|
2881
2904
|
*/
|
|
2882
2905
|
info(useColor, msg) {
|
|
2883
2906
|
if (useColor) {
|
|
@@ -2887,9 +2910,9 @@ class Server {
|
|
|
2887
2910
|
return msg;
|
|
2888
2911
|
},
|
|
2889
2912
|
/**
|
|
2890
|
-
* @param {boolean} useColor
|
|
2891
|
-
* @param {string} msg
|
|
2892
|
-
* @returns {string}
|
|
2913
|
+
* @param {boolean} useColor need to use color?
|
|
2914
|
+
* @param {string} msg message
|
|
2915
|
+
* @returns {string} message with colors
|
|
2893
2916
|
*/
|
|
2894
2917
|
error(useColor, msg) {
|
|
2895
2918
|
if (useColor) {
|
|
@@ -2911,8 +2934,8 @@ class Server {
|
|
|
2911
2934
|
/** @type {import("net").AddressInfo} */
|
|
2912
2935
|
(server.address());
|
|
2913
2936
|
/**
|
|
2914
|
-
* @param {string} newHostname
|
|
2915
|
-
* @returns {string}
|
|
2937
|
+
* @param {string} newHostname new hostname
|
|
2938
|
+
* @returns {string} prettified URL
|
|
2916
2939
|
*/
|
|
2917
2940
|
const prettyPrintURL = (newHostname) =>
|
|
2918
2941
|
url.format({ protocol, hostname: newHostname, port, pathname: "/" });
|
|
@@ -2932,7 +2955,7 @@ class Server {
|
|
|
2932
2955
|
|
|
2933
2956
|
try {
|
|
2934
2957
|
isIP = ipaddr.parse(this.options.host);
|
|
2935
|
-
} catch
|
|
2958
|
+
} catch {
|
|
2936
2959
|
// Ignore
|
|
2937
2960
|
}
|
|
2938
2961
|
|
|
@@ -3066,9 +3089,9 @@ class Server {
|
|
|
3066
3089
|
|
|
3067
3090
|
/**
|
|
3068
3091
|
* @private
|
|
3069
|
-
* @param {Request} req
|
|
3070
|
-
* @param {Response} res
|
|
3071
|
-
* @param {NextFunction} next
|
|
3092
|
+
* @param {Request} req request
|
|
3093
|
+
* @param {Response} res response
|
|
3094
|
+
* @param {NextFunction} next next function
|
|
3072
3095
|
*/
|
|
3073
3096
|
setHeaders(req, res, next) {
|
|
3074
3097
|
let { headers } = this.options;
|
|
@@ -3078,23 +3101,22 @@ class Server {
|
|
|
3078
3101
|
headers = headers(
|
|
3079
3102
|
req,
|
|
3080
3103
|
res,
|
|
3081
|
-
|
|
3104
|
+
|
|
3082
3105
|
this.middleware ? this.middleware.context : undefined,
|
|
3083
3106
|
);
|
|
3084
3107
|
}
|
|
3085
3108
|
|
|
3086
3109
|
/**
|
|
3087
|
-
* @type {{key: string, value: string}[]}
|
|
3110
|
+
* @type {{ key: string, value: string }[]}
|
|
3088
3111
|
*/
|
|
3089
3112
|
const allHeaders = [];
|
|
3090
3113
|
|
|
3091
|
-
allHeaders.push({ key: "X_TEST", value: "TEST" });
|
|
3092
|
-
|
|
3093
3114
|
if (!Array.isArray(headers)) {
|
|
3094
|
-
// eslint-disable-next-line guard-for-in
|
|
3095
3115
|
for (const name in headers) {
|
|
3096
|
-
|
|
3097
|
-
|
|
3116
|
+
allHeaders.push({
|
|
3117
|
+
key: name,
|
|
3118
|
+
value: /** @type {string} */ (headers[name]),
|
|
3119
|
+
});
|
|
3098
3120
|
}
|
|
3099
3121
|
|
|
3100
3122
|
headers = allHeaders;
|
|
@@ -3110,8 +3132,8 @@ class Server {
|
|
|
3110
3132
|
|
|
3111
3133
|
/**
|
|
3112
3134
|
* @private
|
|
3113
|
-
* @param {string} value
|
|
3114
|
-
* @returns {boolean}
|
|
3135
|
+
* @param {string} value value
|
|
3136
|
+
* @returns {boolean} true when host allowed, otherwise false
|
|
3115
3137
|
*/
|
|
3116
3138
|
isHostAllowed(value) {
|
|
3117
3139
|
const { allowedHosts } = this.options;
|
|
@@ -3125,26 +3147,21 @@ class Server {
|
|
|
3125
3147
|
// always allow localhost host, for convenience
|
|
3126
3148
|
// allow if value is in allowedHosts
|
|
3127
3149
|
if (Array.isArray(allowedHosts) && allowedHosts.length > 0) {
|
|
3128
|
-
for (
|
|
3129
|
-
/** @type {string} */
|
|
3130
|
-
const allowedHost = allowedHosts[hostIdx];
|
|
3131
|
-
|
|
3150
|
+
for (const allowedHost of allowedHosts) {
|
|
3132
3151
|
if (allowedHost === value) {
|
|
3133
3152
|
return true;
|
|
3134
3153
|
}
|
|
3135
3154
|
|
|
3136
3155
|
// support "." as a subdomain wildcard
|
|
3137
3156
|
// e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
|
|
3138
|
-
if (
|
|
3139
|
-
// "example.com" (value === allowedHost.substring(1))
|
|
3157
|
+
if (
|
|
3158
|
+
allowedHost.startsWith(".") && // "example.com" (value === allowedHost.substring(1))
|
|
3140
3159
|
// "*.example.com" (value.endsWith(allowedHost))
|
|
3141
|
-
|
|
3142
|
-
value === allowedHost.substring(1) ||
|
|
3160
|
+
(value === allowedHost.slice(1) ||
|
|
3143
3161
|
/** @type {string} */
|
|
3144
|
-
(value).endsWith(allowedHost)
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
}
|
|
3162
|
+
(value).endsWith(allowedHost))
|
|
3163
|
+
) {
|
|
3164
|
+
return true;
|
|
3148
3165
|
}
|
|
3149
3166
|
}
|
|
3150
3167
|
}
|
|
@@ -3169,11 +3186,12 @@ class Server {
|
|
|
3169
3186
|
|
|
3170
3187
|
/**
|
|
3171
3188
|
* @private
|
|
3172
|
-
* @param {{ [key: string]: string | undefined }} headers
|
|
3173
|
-
* @param {string} headerToCheck
|
|
3174
|
-
* @
|
|
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
|
|
3175
3193
|
*/
|
|
3176
|
-
isValidHost(headers, headerToCheck) {
|
|
3194
|
+
isValidHost(headers, headerToCheck, validateHost = true) {
|
|
3177
3195
|
if (this.options.allowedHosts === "all") {
|
|
3178
3196
|
return true;
|
|
3179
3197
|
}
|
|
@@ -3191,12 +3209,14 @@ class Server {
|
|
|
3191
3209
|
}
|
|
3192
3210
|
|
|
3193
3211
|
// use the node url-parser to retrieve the hostname from the host-header.
|
|
3194
|
-
|
|
3212
|
+
// TODO resolve me in the next major release
|
|
3213
|
+
// eslint-disable-next-line n/no-deprecated-api
|
|
3214
|
+
const { hostname } = url.parse(
|
|
3195
3215
|
// if header doesn't have scheme, add // for parsing.
|
|
3196
3216
|
/^(.+:)?\/\//.test(header) ? header : `//${header}`,
|
|
3197
3217
|
false,
|
|
3198
3218
|
true,
|
|
3199
|
-
)
|
|
3219
|
+
);
|
|
3200
3220
|
|
|
3201
3221
|
if (hostname === null) {
|
|
3202
3222
|
return false;
|
|
@@ -3215,25 +3235,21 @@ class Server {
|
|
|
3215
3235
|
// For convenience, always allow localhost (hostname === 'localhost')
|
|
3216
3236
|
// and its subdomains (hostname.endsWith(".localhost")).
|
|
3217
3237
|
// allow hostname of listening address (hostname === this.options.host)
|
|
3218
|
-
const isValidHostname =
|
|
3219
|
-
ipaddr.IPv4.isValid(hostname) ||
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
// disallow
|
|
3230
|
-
return false;
|
|
3238
|
+
const isValidHostname = validateHost
|
|
3239
|
+
? ipaddr.IPv4.isValid(hostname) ||
|
|
3240
|
+
ipaddr.IPv6.isValid(hostname) ||
|
|
3241
|
+
hostname === "localhost" ||
|
|
3242
|
+
hostname.endsWith(".localhost") ||
|
|
3243
|
+
hostname === this.options.host
|
|
3244
|
+
: false;
|
|
3245
|
+
|
|
3246
|
+
return isValidHostname;
|
|
3231
3247
|
}
|
|
3232
3248
|
|
|
3233
3249
|
/**
|
|
3234
3250
|
* @private
|
|
3235
|
-
* @param {{ [key: string]: string | undefined }} headers
|
|
3236
|
-
* @returns {boolean}
|
|
3251
|
+
* @param {{ [key: string]: string | undefined }} headers headers
|
|
3252
|
+
* @returns {boolean} true when is same origin, otherwise false
|
|
3237
3253
|
*/
|
|
3238
3254
|
isSameOrigin(headers) {
|
|
3239
3255
|
if (this.options.allowedHosts === "all") {
|
|
@@ -3250,6 +3266,8 @@ class Server {
|
|
|
3250
3266
|
return true;
|
|
3251
3267
|
}
|
|
3252
3268
|
|
|
3269
|
+
// TODO resolve me in the next major release
|
|
3270
|
+
// eslint-disable-next-line n/no-deprecated-api
|
|
3253
3271
|
const origin = url.parse(originHeader, false, true).hostname;
|
|
3254
3272
|
|
|
3255
3273
|
if (origin === null) {
|
|
@@ -3270,6 +3288,7 @@ class Server {
|
|
|
3270
3288
|
return true;
|
|
3271
3289
|
}
|
|
3272
3290
|
|
|
3291
|
+
// eslint-disable-next-line n/no-deprecated-api
|
|
3273
3292
|
const host = url.parse(
|
|
3274
3293
|
// if hostHeader doesn't have scheme, add // for parsing.
|
|
3275
3294
|
/^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`,
|
|
@@ -3289,12 +3308,11 @@ class Server {
|
|
|
3289
3308
|
}
|
|
3290
3309
|
|
|
3291
3310
|
/**
|
|
3292
|
-
* @param {ClientConnection[]} clients
|
|
3293
|
-
* @param {string} type
|
|
3294
|
-
* @param {
|
|
3295
|
-
* @param {
|
|
3311
|
+
* @param {ClientConnection[]} clients clients
|
|
3312
|
+
* @param {string} type type
|
|
3313
|
+
* @param {EXPECTED_ANY=} data data
|
|
3314
|
+
* @param {EXPECTED_ANY=} params params
|
|
3296
3315
|
*/
|
|
3297
|
-
// eslint-disable-next-line class-methods-use-this
|
|
3298
3316
|
sendMessage(clients, type, data, params) {
|
|
3299
3317
|
for (const client of clients) {
|
|
3300
3318
|
// `sockjs` uses `1` to indicate client is ready to accept data
|
|
@@ -3308,9 +3326,9 @@ class Server {
|
|
|
3308
3326
|
// Send stats to a socket or multiple sockets
|
|
3309
3327
|
/**
|
|
3310
3328
|
* @private
|
|
3311
|
-
* @param {ClientConnection[]} clients
|
|
3312
|
-
* @param {StatsCompilation} stats
|
|
3313
|
-
* @param {boolean}
|
|
3329
|
+
* @param {ClientConnection[]} clients clients
|
|
3330
|
+
* @param {StatsCompilation} stats stats
|
|
3331
|
+
* @param {boolean=} force force
|
|
3314
3332
|
*/
|
|
3315
3333
|
sendStats(clients, stats, force) {
|
|
3316
3334
|
const shouldEmit =
|
|
@@ -3364,11 +3382,12 @@ class Server {
|
|
|
3364
3382
|
}
|
|
3365
3383
|
|
|
3366
3384
|
/**
|
|
3367
|
-
* @param {string | string[]} watchPath
|
|
3368
|
-
* @param {WatchOptions}
|
|
3385
|
+
* @param {string | string[]} watchPath watch path
|
|
3386
|
+
* @param {WatchOptions=} watchOptions watch options
|
|
3369
3387
|
*/
|
|
3370
3388
|
watchFiles(watchPath, watchOptions) {
|
|
3371
3389
|
const chokidar = require("chokidar");
|
|
3390
|
+
|
|
3372
3391
|
const watcher = chokidar.watch(watchPath, watchOptions);
|
|
3373
3392
|
|
|
3374
3393
|
// disabling refreshing on changing the content
|
|
@@ -3388,7 +3407,7 @@ class Server {
|
|
|
3388
3407
|
}
|
|
3389
3408
|
|
|
3390
3409
|
/**
|
|
3391
|
-
* @param {import("webpack-dev-middleware").Callback}
|
|
3410
|
+
* @param {import("webpack-dev-middleware").Callback=} callback callback
|
|
3392
3411
|
*/
|
|
3393
3412
|
invalidate(callback = () => {}) {
|
|
3394
3413
|
if (this.middleware) {
|
|
@@ -3405,13 +3424,14 @@ class Server {
|
|
|
3405
3424
|
if (this.options.ipc) {
|
|
3406
3425
|
await /** @type {Promise<void>} */ (
|
|
3407
3426
|
new Promise((resolve, reject) => {
|
|
3408
|
-
const net = require("net");
|
|
3427
|
+
const net = require("node:net");
|
|
3428
|
+
|
|
3409
3429
|
const socket = new net.Socket();
|
|
3410
3430
|
|
|
3411
3431
|
socket.on(
|
|
3412
3432
|
"error",
|
|
3413
3433
|
/**
|
|
3414
|
-
* @param {Error & { code?: string }} error
|
|
3434
|
+
* @param {Error & { code?: string }} error error
|
|
3415
3435
|
*/
|
|
3416
3436
|
(error) => {
|
|
3417
3437
|
if (error.code === "ECONNREFUSED") {
|
|
@@ -3490,7 +3510,7 @@ class Server {
|
|
|
3490
3510
|
}
|
|
3491
3511
|
|
|
3492
3512
|
/**
|
|
3493
|
-
* @param {(err?: Error) => void}
|
|
3513
|
+
* @param {((err?: Error) => void)=} callback callback
|
|
3494
3514
|
*/
|
|
3495
3515
|
startCallback(callback = () => {}) {
|
|
3496
3516
|
this.start()
|
|
@@ -3545,7 +3565,6 @@ class Server {
|
|
|
3545
3565
|
new Promise((resolve) => {
|
|
3546
3566
|
/** @type {S} */
|
|
3547
3567
|
(this.server).close(() => {
|
|
3548
|
-
// eslint-disable-next-line no-undefined
|
|
3549
3568
|
this.server = undefined;
|
|
3550
3569
|
resolve();
|
|
3551
3570
|
});
|
|
@@ -3561,7 +3580,7 @@ class Server {
|
|
|
3561
3580
|
if (this.middleware) {
|
|
3562
3581
|
await /** @type {Promise<void>} */ (
|
|
3563
3582
|
new Promise((resolve, reject) => {
|
|
3564
|
-
/** @type {import("webpack-dev-middleware").API<Request, Response>}*/
|
|
3583
|
+
/** @type {import("webpack-dev-middleware").API<Request, Response>} */
|
|
3565
3584
|
(this.middleware).close((error) => {
|
|
3566
3585
|
if (error) {
|
|
3567
3586
|
reject(error);
|
|
@@ -3573,7 +3592,6 @@ class Server {
|
|
|
3573
3592
|
})
|
|
3574
3593
|
);
|
|
3575
3594
|
|
|
3576
|
-
// eslint-disable-next-line no-undefined
|
|
3577
3595
|
this.middleware = undefined;
|
|
3578
3596
|
}
|
|
3579
3597
|
}
|
|
@@ -3586,7 +3604,7 @@ class Server {
|
|
|
3586
3604
|
}
|
|
3587
3605
|
|
|
3588
3606
|
/**
|
|
3589
|
-
* @param {(err?: Error) => void}
|
|
3607
|
+
* @param {((err?: Error) => void)=} callback callback
|
|
3590
3608
|
*/
|
|
3591
3609
|
stopCallback(callback = () => {}) {
|
|
3592
3610
|
this.stop()
|