webpack-dev-server 5.0.4 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/client/clients/SockJSClient.js +3 -3
- package/client/clients/WebSocketClient.js +3 -3
- package/client/index.js +296 -17
- package/client/modules/logger/index.js +213 -122
- package/client/modules/sockjs-client/index.js +2 -2
- package/client/overlay.js +357 -16
- package/client/progress.js +124 -0
- package/client/utils/log.js +1 -17
- package/lib/Server.js +624 -376
- package/lib/options.json +23 -5
- package/package.json +36 -36
- package/types/bin/cli-flags.d.ts +15 -0
- package/types/lib/Server.d.ts +199 -291
- package/types/lib/servers/WebsocketServer.d.ts +0 -1
- package/client/overlay/fsm.js +0 -64
- package/client/overlay/runtime-error.js +0 -47
- package/client/overlay/state-machine.js +0 -100
- package/client/overlay/styles.js +0 -74
- package/client/utils/createSocketURL.js +0 -121
- package/client/utils/getCurrentScriptSource.js +0 -24
- package/client/utils/parseURL.js +0 -36
- package/client/utils/reloadApp.js +0 -63
- package/client/utils/stripAnsi.js +0 -18
package/lib/Server.js
CHANGED
|
@@ -18,9 +18,6 @@ const schema = require("./options.json");
|
|
|
18
18
|
/** @typedef {import("webpack").Stats} Stats */
|
|
19
19
|
/** @typedef {import("webpack").MultiStats} MultiStats */
|
|
20
20
|
/** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */
|
|
21
|
-
/** @typedef {import("express").NextFunction} NextFunction */
|
|
22
|
-
/** @typedef {import("express").RequestHandler} ExpressRequestHandler */
|
|
23
|
-
/** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
|
|
24
21
|
/** @typedef {import("chokidar").WatchOptions} WatchOptions */
|
|
25
22
|
/** @typedef {import("chokidar").FSWatcher} FSWatcher */
|
|
26
23
|
/** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
|
|
@@ -34,14 +31,32 @@ const schema = require("./options.json");
|
|
|
34
31
|
/** @typedef {import("ipaddr.js").IPv4} IPv4 */
|
|
35
32
|
/** @typedef {import("ipaddr.js").IPv6} IPv6 */
|
|
36
33
|
/** @typedef {import("net").Socket} Socket */
|
|
34
|
+
/** @typedef {import("http").Server} HTTPServer*/
|
|
37
35
|
/** @typedef {import("http").IncomingMessage} IncomingMessage */
|
|
38
36
|
/** @typedef {import("http").ServerResponse} ServerResponse */
|
|
39
37
|
/** @typedef {import("open").Options} OpenOptions */
|
|
38
|
+
/** @typedef {import("express").Application} ExpressApplication */
|
|
39
|
+
/** @typedef {import("express").RequestHandler} ExpressRequestHandler */
|
|
40
|
+
/** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
|
|
41
|
+
/** @typedef {import("express").Request} ExpressRequest */
|
|
42
|
+
/** @typedef {import("express").Response} ExpressResponse */
|
|
43
|
+
|
|
44
|
+
/** @typedef {(err?: any) => void} NextFunction */
|
|
45
|
+
/** @typedef {(req: IncomingMessage, res: ServerResponse) => void} SimpleHandleFunction */
|
|
46
|
+
/** @typedef {(req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} NextHandleFunction */
|
|
47
|
+
/** @typedef {(err: any, req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} ErrorHandleFunction */
|
|
48
|
+
/** @typedef {SimpleHandleFunction | NextHandleFunction | ErrorHandleFunction} HandleFunction */
|
|
40
49
|
|
|
41
50
|
/** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
|
|
42
51
|
|
|
43
|
-
/**
|
|
44
|
-
|
|
52
|
+
/**
|
|
53
|
+
* @template {BasicApplication} [T=ExpressApplication]
|
|
54
|
+
* @typedef {T extends ExpressApplication ? ExpressRequest : IncomingMessage} Request
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* @template {BasicApplication} [T=ExpressApplication]
|
|
58
|
+
* @typedef {T extends ExpressApplication ? ExpressResponse : ServerResponse} Response
|
|
59
|
+
*/
|
|
45
60
|
|
|
46
61
|
/**
|
|
47
62
|
* @template {Request} T
|
|
@@ -88,8 +103,16 @@ const schema = require("./options.json");
|
|
|
88
103
|
*/
|
|
89
104
|
|
|
90
105
|
/**
|
|
106
|
+
* @template {BasicApplication} [A=ExpressApplication]
|
|
107
|
+
* @template {BasicServer} [S=import("http").Server]
|
|
108
|
+
* @typedef {"http" | "https" | "spdy" | "http2" | string | function(ServerOptions, A): S} ServerType
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @template {BasicApplication} [A=ExpressApplication]
|
|
113
|
+
* @template {BasicServer} [S=import("http").Server]
|
|
91
114
|
* @typedef {Object} ServerConfiguration
|
|
92
|
-
* @property {
|
|
115
|
+
* @property {ServerType<A, S>} [type]
|
|
93
116
|
* @property {ServerOptions} [options]
|
|
94
117
|
*/
|
|
95
118
|
|
|
@@ -173,10 +196,23 @@ const schema = require("./options.json");
|
|
|
173
196
|
*/
|
|
174
197
|
|
|
175
198
|
/**
|
|
176
|
-
* @
|
|
199
|
+
* @template {BasicApplication} [T=ExpressApplication]
|
|
200
|
+
* @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
|
|
177
201
|
*/
|
|
178
202
|
|
|
179
203
|
/**
|
|
204
|
+
* @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler }} MiddlewareObject
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @typedef {MiddlewareObject | MiddlewareHandler } Middleware
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
/** @typedef {import("net").Server | import("tls").Server} BasicServer */
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @template {BasicApplication} [A=ExpressApplication]
|
|
215
|
+
* @template {BasicServer} [S=import("http").Server]
|
|
180
216
|
* @typedef {Object} Configuration
|
|
181
217
|
* @property {boolean | string} [ipc]
|
|
182
218
|
* @property {Host} [host]
|
|
@@ -190,17 +226,16 @@ const schema = require("./options.json");
|
|
|
190
226
|
* @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
|
|
191
227
|
* @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
|
|
192
228
|
* @property {boolean | string | Static | Array<string | Static>} [static]
|
|
193
|
-
* @property {
|
|
194
|
-
* @property {
|
|
195
|
-
* @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
|
|
229
|
+
* @property {ServerType<A, S> | ServerConfiguration<A, S>} [server]
|
|
230
|
+
* @property {() => Promise<A>} [app]
|
|
196
231
|
* @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
|
|
197
232
|
* @property {ProxyConfigArray} [proxy]
|
|
198
233
|
* @property {boolean | string | Open | Array<string | Open>} [open]
|
|
199
234
|
* @property {boolean} [setupExitSignals]
|
|
200
235
|
* @property {boolean | ClientConfiguration} [client]
|
|
201
|
-
* @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
|
|
202
|
-
* @property {(devServer: Server) => void} [onListening]
|
|
203
|
-
* @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
|
|
236
|
+
* @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response> | undefined) => Headers)} [headers]
|
|
237
|
+
* @property {(devServer: Server<A, S>) => void} [onListening]
|
|
238
|
+
* @property {(middlewares: Middleware[], devServer: Server<A, S>) => Middleware[]} [setupMiddlewares]
|
|
204
239
|
*/
|
|
205
240
|
|
|
206
241
|
if (!process.env.WEBPACK_SERVE) {
|
|
@@ -245,10 +280,46 @@ const encodeOverlaySettings = (setting) =>
|
|
|
245
280
|
? encodeURIComponent(setting.toString())
|
|
246
281
|
: setting;
|
|
247
282
|
|
|
283
|
+
// Working for overload, because typescript doesn't support this yes
|
|
284
|
+
/**
|
|
285
|
+
* @overload
|
|
286
|
+
* @param {NextHandleFunction} fn
|
|
287
|
+
* @returns {BasicApplication}
|
|
288
|
+
*/
|
|
289
|
+
/**
|
|
290
|
+
* @overload
|
|
291
|
+
* @param {HandleFunction} fn
|
|
292
|
+
* @returns {BasicApplication}
|
|
293
|
+
*/
|
|
294
|
+
/**
|
|
295
|
+
* @overload
|
|
296
|
+
* @param {string} route
|
|
297
|
+
* @param {NextHandleFunction} fn
|
|
298
|
+
* @returns {BasicApplication}
|
|
299
|
+
*/
|
|
300
|
+
/**
|
|
301
|
+
* @param {string} route
|
|
302
|
+
* @param {HandleFunction} fn
|
|
303
|
+
* @returns {BasicApplication}
|
|
304
|
+
*/
|
|
305
|
+
// eslint-disable-next-line no-unused-vars
|
|
306
|
+
function useFn(route, fn) {
|
|
307
|
+
return /** @type {BasicApplication} */ ({});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @typedef {Object} BasicApplication
|
|
312
|
+
* @property {typeof useFn} use
|
|
313
|
+
*/
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @template {BasicApplication} [A=ExpressApplication]
|
|
317
|
+
* @template {BasicServer} [S=HTTPServer]
|
|
318
|
+
*/
|
|
248
319
|
class Server {
|
|
249
320
|
/**
|
|
250
|
-
* @param {Configuration
|
|
251
|
-
* @param {Compiler | MultiCompiler
|
|
321
|
+
* @param {Configuration<A, S>} options
|
|
322
|
+
* @param {Compiler | MultiCompiler} compiler
|
|
252
323
|
*/
|
|
253
324
|
constructor(options = {}, compiler) {
|
|
254
325
|
validate(/** @type {Schema} */ (schema), options, {
|
|
@@ -256,12 +327,12 @@ class Server {
|
|
|
256
327
|
baseDataPath: "options",
|
|
257
328
|
});
|
|
258
329
|
|
|
259
|
-
this.compiler =
|
|
330
|
+
this.compiler = compiler;
|
|
260
331
|
/**
|
|
261
332
|
* @type {ReturnType<Compiler["getInfrastructureLogger"]>}
|
|
262
333
|
* */
|
|
263
334
|
this.logger = this.compiler.getInfrastructureLogger("webpack-dev-server");
|
|
264
|
-
this.options =
|
|
335
|
+
this.options = options;
|
|
265
336
|
/**
|
|
266
337
|
* @type {FSWatcher[]}
|
|
267
338
|
*/
|
|
@@ -324,11 +395,60 @@ class Server {
|
|
|
324
395
|
}
|
|
325
396
|
|
|
326
397
|
/**
|
|
327
|
-
* @param {string}
|
|
398
|
+
* @param {string} gatewayOrFamily or family
|
|
399
|
+
* @param {boolean} [isInternal] ip should be internal
|
|
328
400
|
* @returns {string | undefined}
|
|
329
401
|
*/
|
|
330
|
-
static findIp(
|
|
331
|
-
|
|
402
|
+
static findIp(gatewayOrFamily, isInternal) {
|
|
403
|
+
if (gatewayOrFamily === "v4" || gatewayOrFamily === "v6") {
|
|
404
|
+
let host;
|
|
405
|
+
|
|
406
|
+
const networks = Object.values(os.networkInterfaces())
|
|
407
|
+
// eslint-disable-next-line no-shadow
|
|
408
|
+
.flatMap((networks) => networks ?? [])
|
|
409
|
+
.filter((network) => {
|
|
410
|
+
if (!network || !network.address) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (network.family !== `IP${gatewayOrFamily}`) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (
|
|
419
|
+
typeof isInternal !== "undefined" &&
|
|
420
|
+
network.internal !== isInternal
|
|
421
|
+
) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (gatewayOrFamily === "v6") {
|
|
426
|
+
const range = ipaddr.parse(network.address).range();
|
|
427
|
+
|
|
428
|
+
if (
|
|
429
|
+
range !== "ipv4Mapped" &&
|
|
430
|
+
range !== "uniqueLocal" &&
|
|
431
|
+
range !== "loopback"
|
|
432
|
+
) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return network.address;
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
for (const network of networks) {
|
|
441
|
+
host = network.address;
|
|
442
|
+
|
|
443
|
+
if (host.includes(":")) {
|
|
444
|
+
host = `[${host}]`;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return host;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const gatewayIp = ipaddr.parse(gatewayOrFamily);
|
|
332
452
|
|
|
333
453
|
// Look for the matching interface in all local interfaces.
|
|
334
454
|
for (const addresses of Object.values(os.networkInterfaces())) {
|
|
@@ -348,32 +468,22 @@ class Server {
|
|
|
348
468
|
}
|
|
349
469
|
}
|
|
350
470
|
|
|
471
|
+
// TODO remove me in the next major release, we have `findIp`
|
|
351
472
|
/**
|
|
352
473
|
* @param {"v4" | "v6"} family
|
|
353
474
|
* @returns {Promise<string | undefined>}
|
|
354
475
|
*/
|
|
355
476
|
static async internalIP(family) {
|
|
356
|
-
|
|
357
|
-
const { gateway } = await require("default-gateway")[family]();
|
|
358
|
-
|
|
359
|
-
return Server.findIp(gateway);
|
|
360
|
-
} catch {
|
|
361
|
-
// ignore
|
|
362
|
-
}
|
|
477
|
+
return Server.findIp(family, false);
|
|
363
478
|
}
|
|
364
479
|
|
|
480
|
+
// TODO remove me in the next major release, we have `findIp`
|
|
365
481
|
/**
|
|
366
482
|
* @param {"v4" | "v6"} family
|
|
367
483
|
* @returns {string | undefined}
|
|
368
484
|
*/
|
|
369
485
|
static internalIPSync(family) {
|
|
370
|
-
|
|
371
|
-
const { gateway } = require("default-gateway")[family].sync();
|
|
372
|
-
|
|
373
|
-
return Server.findIp(gateway);
|
|
374
|
-
} catch {
|
|
375
|
-
// ignore
|
|
376
|
-
}
|
|
486
|
+
return Server.findIp(family, false);
|
|
377
487
|
}
|
|
378
488
|
|
|
379
489
|
/**
|
|
@@ -383,14 +493,12 @@ class Server {
|
|
|
383
493
|
static async getHostname(hostname) {
|
|
384
494
|
if (hostname === "local-ip") {
|
|
385
495
|
return (
|
|
386
|
-
(
|
|
387
|
-
(await Server.internalIP("v6")) ||
|
|
388
|
-
"0.0.0.0"
|
|
496
|
+
Server.findIp("v4", false) || Server.findIp("v6", false) || "0.0.0.0"
|
|
389
497
|
);
|
|
390
498
|
} else if (hostname === "local-ipv4") {
|
|
391
|
-
return
|
|
499
|
+
return Server.findIp("v4", false) || "0.0.0.0";
|
|
392
500
|
} else if (hostname === "local-ipv6") {
|
|
393
|
-
return
|
|
501
|
+
return Server.findIp("v6", false) || "::";
|
|
394
502
|
}
|
|
395
503
|
|
|
396
504
|
return hostname;
|
|
@@ -470,7 +578,11 @@ class Server {
|
|
|
470
578
|
* @returns bool
|
|
471
579
|
*/
|
|
472
580
|
static isWebTarget(compiler) {
|
|
473
|
-
|
|
581
|
+
if (compiler.platform && compiler.platform.web) {
|
|
582
|
+
return compiler.platform.web;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// TODO improve for the next major version and keep only `webTargets` to fallback for old versions
|
|
474
586
|
if (
|
|
475
587
|
compiler.options.externalsPresets &&
|
|
476
588
|
compiler.options.externalsPresets.web
|
|
@@ -490,6 +602,7 @@ class Server {
|
|
|
490
602
|
"webworker",
|
|
491
603
|
"electron-preload",
|
|
492
604
|
"electron-renderer",
|
|
605
|
+
"nwjs",
|
|
493
606
|
"node-webkit",
|
|
494
607
|
// eslint-disable-next-line no-undefined
|
|
495
608
|
undefined,
|
|
@@ -537,9 +650,7 @@ class Server {
|
|
|
537
650
|
if (typeof webSocketURL.protocol !== "undefined") {
|
|
538
651
|
protocol = webSocketURL.protocol;
|
|
539
652
|
} else {
|
|
540
|
-
protocol =
|
|
541
|
-
/** @type {ServerConfiguration} */
|
|
542
|
-
(this.options.server).type === "http" ? "ws:" : "wss:";
|
|
653
|
+
protocol = this.isTlsServer ? "wss:" : "ws:";
|
|
543
654
|
}
|
|
544
655
|
|
|
545
656
|
searchParams.set("protocol", protocol);
|
|
@@ -683,15 +794,12 @@ class Server {
|
|
|
683
794
|
webSocketURLStr = searchParams.toString();
|
|
684
795
|
}
|
|
685
796
|
|
|
686
|
-
additionalEntries.push(
|
|
687
|
-
`${require.resolve("../client/index.js")}?${webSocketURLStr}`,
|
|
688
|
-
);
|
|
797
|
+
additionalEntries.push(`${this.getClientEntry()}?${webSocketURLStr}`);
|
|
689
798
|
}
|
|
690
799
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
additionalEntries.push(require.resolve("webpack/hot/dev-server"));
|
|
800
|
+
const clientHotEntry = this.getClientHotEntry();
|
|
801
|
+
if (clientHotEntry) {
|
|
802
|
+
additionalEntries.push(clientHotEntry);
|
|
695
803
|
}
|
|
696
804
|
|
|
697
805
|
const webpack = compiler.webpack || require("webpack");
|
|
@@ -1007,39 +1115,41 @@ class Server {
|
|
|
1007
1115
|
? options.hot
|
|
1008
1116
|
: true;
|
|
1009
1117
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1118
|
+
if (
|
|
1119
|
+
typeof options.server === "function" ||
|
|
1120
|
+
typeof options.server === "string"
|
|
1121
|
+
) {
|
|
1122
|
+
options.server = {
|
|
1123
|
+
type: options.server,
|
|
1124
|
+
options: {},
|
|
1125
|
+
};
|
|
1126
|
+
} else {
|
|
1127
|
+
const serverOptions =
|
|
1128
|
+
/** @type {ServerConfiguration<A, S>} */
|
|
1129
|
+
(options.server || {});
|
|
1130
|
+
|
|
1131
|
+
options.server = {
|
|
1132
|
+
type: serverOptions.type || "http",
|
|
1133
|
+
options: { ...serverOptions.options },
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
const serverOptions = /** @type {ServerOptions} */ (options.server.options);
|
|
1023
1138
|
|
|
1024
1139
|
if (
|
|
1025
1140
|
options.server.type === "spdy" &&
|
|
1026
|
-
typeof
|
|
1027
|
-
"undefined"
|
|
1141
|
+
typeof serverOptions.spdy === "undefined"
|
|
1028
1142
|
) {
|
|
1029
|
-
|
|
1030
|
-
(options.server.options).spdy = {
|
|
1031
|
-
protocols: ["h2", "http/1.1"],
|
|
1032
|
-
};
|
|
1143
|
+
serverOptions.spdy = { protocols: ["h2", "http/1.1"] };
|
|
1033
1144
|
}
|
|
1034
1145
|
|
|
1035
|
-
if (
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
) {
|
|
1041
|
-
|
|
1042
|
-
(options.server.options).requestCert = false;
|
|
1146
|
+
if (
|
|
1147
|
+
options.server.type === "https" ||
|
|
1148
|
+
options.server.type === "http2" ||
|
|
1149
|
+
options.server.type === "spdy"
|
|
1150
|
+
) {
|
|
1151
|
+
if (typeof serverOptions.requestCert === "undefined") {
|
|
1152
|
+
serverOptions.requestCert = false;
|
|
1043
1153
|
}
|
|
1044
1154
|
|
|
1045
1155
|
const httpsProperties =
|
|
@@ -1047,19 +1157,13 @@ class Server {
|
|
|
1047
1157
|
(["ca", "cert", "crl", "key", "pfx"]);
|
|
1048
1158
|
|
|
1049
1159
|
for (const property of httpsProperties) {
|
|
1050
|
-
if (
|
|
1051
|
-
typeof (
|
|
1052
|
-
/** @type {ServerOptions} */ (options.server.options)[property]
|
|
1053
|
-
) === "undefined"
|
|
1054
|
-
) {
|
|
1160
|
+
if (typeof serverOptions[property] === "undefined") {
|
|
1055
1161
|
// eslint-disable-next-line no-continue
|
|
1056
1162
|
continue;
|
|
1057
1163
|
}
|
|
1058
1164
|
|
|
1059
1165
|
/** @type {any} */
|
|
1060
|
-
const value =
|
|
1061
|
-
/** @type {ServerOptions} */
|
|
1062
|
-
(options.server.options)[property];
|
|
1166
|
+
const value = serverOptions[property];
|
|
1063
1167
|
/**
|
|
1064
1168
|
* @param {string | Buffer | undefined} item
|
|
1065
1169
|
* @returns {string | Buffer | undefined}
|
|
@@ -1087,17 +1191,14 @@ class Server {
|
|
|
1087
1191
|
};
|
|
1088
1192
|
|
|
1089
1193
|
/** @type {any} */
|
|
1090
|
-
(
|
|
1194
|
+
(serverOptions)[property] = Array.isArray(value)
|
|
1091
1195
|
? value.map((item) => readFile(item))
|
|
1092
1196
|
: readFile(value);
|
|
1093
1197
|
}
|
|
1094
1198
|
|
|
1095
1199
|
let fakeCert;
|
|
1096
1200
|
|
|
1097
|
-
if (
|
|
1098
|
-
!(/** @type {ServerOptions} */ (options.server.options).key) ||
|
|
1099
|
-
!(/** @type {ServerOptions} */ (options.server.options).cert)
|
|
1100
|
-
) {
|
|
1201
|
+
if (!serverOptions.key || !serverOptions.cert) {
|
|
1101
1202
|
const certificateDir = Server.findCacheDir();
|
|
1102
1203
|
const certificatePath = path.join(certificateDir, "server.pem");
|
|
1103
1204
|
let certificateExists;
|
|
@@ -1116,13 +1217,11 @@ class Server {
|
|
|
1116
1217
|
|
|
1117
1218
|
// cert is more than 30 days old, kill it with fire
|
|
1118
1219
|
if ((now - Number(certificateStat.ctime)) / certificateTtl > 30) {
|
|
1119
|
-
const { rimraf } = require("rimraf");
|
|
1120
|
-
|
|
1121
1220
|
this.logger.info(
|
|
1122
1221
|
"SSL certificate is more than 30 days old. Removing...",
|
|
1123
1222
|
);
|
|
1124
1223
|
|
|
1125
|
-
await
|
|
1224
|
+
await fs.promises.rm(certificatePath, { recursive: true });
|
|
1126
1225
|
|
|
1127
1226
|
certificateExists = false;
|
|
1128
1227
|
}
|
|
@@ -1131,7 +1230,6 @@ class Server {
|
|
|
1131
1230
|
if (!certificateExists) {
|
|
1132
1231
|
this.logger.info("Generating SSL certificate...");
|
|
1133
1232
|
|
|
1134
|
-
// @ts-ignore
|
|
1135
1233
|
const selfsigned = require("selfsigned");
|
|
1136
1234
|
const attributes = [{ name: "commonName", value: "localhost" }];
|
|
1137
1235
|
const pems = selfsigned.generate(attributes, {
|
|
@@ -1212,14 +1310,8 @@ class Server {
|
|
|
1212
1310
|
this.logger.info(`SSL certificate: ${certificatePath}`);
|
|
1213
1311
|
}
|
|
1214
1312
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
/** @type {ServerOptions} */
|
|
1218
|
-
(options.server.options).key || fakeCert;
|
|
1219
|
-
/** @type {ServerOptions} */
|
|
1220
|
-
(options.server.options).cert =
|
|
1221
|
-
/** @type {ServerOptions} */
|
|
1222
|
-
(options.server.options).cert || fakeCert;
|
|
1313
|
+
serverOptions.key = serverOptions.key || fakeCert;
|
|
1314
|
+
serverOptions.cert = serverOptions.cert || fakeCert;
|
|
1223
1315
|
}
|
|
1224
1316
|
|
|
1225
1317
|
if (typeof options.ipc === "boolean") {
|
|
@@ -1281,15 +1373,15 @@ class Server {
|
|
|
1281
1373
|
*/
|
|
1282
1374
|
const result = [];
|
|
1283
1375
|
|
|
1284
|
-
options.open
|
|
1376
|
+
for (const item of options.open) {
|
|
1285
1377
|
if (typeof item === "string") {
|
|
1286
1378
|
result.push({ target: item, options: defaultOpenOptions });
|
|
1287
|
-
|
|
1288
|
-
|
|
1379
|
+
// eslint-disable-next-line no-continue
|
|
1380
|
+
continue;
|
|
1289
1381
|
}
|
|
1290
1382
|
|
|
1291
1383
|
result.push(...getOpenItemsFromObject(item));
|
|
1292
|
-
}
|
|
1384
|
+
}
|
|
1293
1385
|
|
|
1294
1386
|
/** @type {NormalizedOpen[]} */
|
|
1295
1387
|
(options.open) = result;
|
|
@@ -1522,8 +1614,9 @@ class Server {
|
|
|
1522
1614
|
}
|
|
1523
1615
|
|
|
1524
1616
|
/**
|
|
1617
|
+
* @template T
|
|
1525
1618
|
* @private
|
|
1526
|
-
* @returns {
|
|
1619
|
+
* @returns {T}
|
|
1527
1620
|
*/
|
|
1528
1621
|
getServerTransport() {
|
|
1529
1622
|
let implementation;
|
|
@@ -1553,9 +1646,8 @@ class Server {
|
|
|
1553
1646
|
try {
|
|
1554
1647
|
// eslint-disable-next-line import/no-dynamic-require
|
|
1555
1648
|
implementation = require(
|
|
1556
|
-
/** @type {WebSocketServerConfiguration} */
|
|
1557
|
-
|
|
1558
|
-
).type,
|
|
1649
|
+
/** @type {WebSocketServerConfiguration} */
|
|
1650
|
+
(this.options.webSocketServer).type,
|
|
1559
1651
|
);
|
|
1560
1652
|
} catch (error) {
|
|
1561
1653
|
implementationFound = false;
|
|
@@ -1563,9 +1655,9 @@ class Server {
|
|
|
1563
1655
|
}
|
|
1564
1656
|
break;
|
|
1565
1657
|
case "function":
|
|
1566
|
-
implementation =
|
|
1567
|
-
|
|
1568
|
-
|
|
1658
|
+
implementation =
|
|
1659
|
+
/** @type {WebSocketServerConfiguration} */
|
|
1660
|
+
(this.options.webSocketServer).type;
|
|
1569
1661
|
break;
|
|
1570
1662
|
default:
|
|
1571
1663
|
implementationFound = false;
|
|
@@ -1582,6 +1674,25 @@ class Server {
|
|
|
1582
1674
|
return implementation;
|
|
1583
1675
|
}
|
|
1584
1676
|
|
|
1677
|
+
/**
|
|
1678
|
+
* @returns {string}
|
|
1679
|
+
*/
|
|
1680
|
+
// eslint-disable-next-line class-methods-use-this
|
|
1681
|
+
getClientEntry() {
|
|
1682
|
+
return require.resolve("../client/index.js");
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* @returns {string | void}
|
|
1687
|
+
*/
|
|
1688
|
+
getClientHotEntry() {
|
|
1689
|
+
if (this.options.hot === "only") {
|
|
1690
|
+
return require.resolve("webpack/hot/only-dev-server");
|
|
1691
|
+
} else if (this.options.hot) {
|
|
1692
|
+
return require.resolve("webpack/hot/dev-server");
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1585
1696
|
/**
|
|
1586
1697
|
* @private
|
|
1587
1698
|
* @returns {void}
|
|
@@ -1631,12 +1742,22 @@ class Server {
|
|
|
1631
1742
|
* @returns {Promise<void>}
|
|
1632
1743
|
*/
|
|
1633
1744
|
async initialize() {
|
|
1745
|
+
this.setupHooks();
|
|
1746
|
+
|
|
1747
|
+
await this.setupApp();
|
|
1748
|
+
await this.createServer();
|
|
1749
|
+
|
|
1634
1750
|
if (this.options.webSocketServer) {
|
|
1635
1751
|
const compilers =
|
|
1636
1752
|
/** @type {MultiCompiler} */
|
|
1637
1753
|
(this.compiler).compilers || [this.compiler];
|
|
1638
1754
|
|
|
1639
|
-
|
|
1755
|
+
for (const compiler of compilers) {
|
|
1756
|
+
if (compiler.options.devServer === false) {
|
|
1757
|
+
// eslint-disable-next-line no-continue
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1640
1761
|
this.addAdditionalEntries(compiler);
|
|
1641
1762
|
|
|
1642
1763
|
const webpack = compiler.webpack || require("webpack");
|
|
@@ -1661,7 +1782,7 @@ class Server {
|
|
|
1661
1782
|
plugin.apply(compiler);
|
|
1662
1783
|
}
|
|
1663
1784
|
}
|
|
1664
|
-
}
|
|
1785
|
+
}
|
|
1665
1786
|
|
|
1666
1787
|
if (
|
|
1667
1788
|
this.options.client &&
|
|
@@ -1671,16 +1792,9 @@ class Server {
|
|
|
1671
1792
|
}
|
|
1672
1793
|
}
|
|
1673
1794
|
|
|
1674
|
-
this.setupHooks();
|
|
1675
|
-
this.setupApp();
|
|
1676
|
-
this.setupHostHeaderCheck();
|
|
1677
|
-
this.setupDevMiddleware();
|
|
1678
|
-
// Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
|
|
1679
|
-
this.setupBuiltInRoutes();
|
|
1680
1795
|
this.setupWatchFiles();
|
|
1681
1796
|
this.setupWatchStaticFiles();
|
|
1682
1797
|
this.setupMiddlewares();
|
|
1683
|
-
this.createServer();
|
|
1684
1798
|
|
|
1685
1799
|
if (this.options.setupExitSignals) {
|
|
1686
1800
|
const signals = ["SIGINT", "SIGTERM"];
|
|
@@ -1718,24 +1832,30 @@ class Server {
|
|
|
1718
1832
|
|
|
1719
1833
|
// Proxy WebSocket without the initial http request
|
|
1720
1834
|
// https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1835
|
+
const webSocketProxies =
|
|
1836
|
+
/** @type {RequestHandler[]} */
|
|
1837
|
+
(this.webSocketProxies);
|
|
1838
|
+
|
|
1839
|
+
for (const webSocketProxy of webSocketProxies) {
|
|
1840
|
+
/** @type {S} */
|
|
1724
1841
|
(this.server).on(
|
|
1725
1842
|
"upgrade",
|
|
1726
1843
|
/** @type {RequestHandler & { upgrade: NonNullable<RequestHandler["upgrade"]> }} */
|
|
1727
1844
|
(webSocketProxy).upgrade,
|
|
1728
1845
|
);
|
|
1729
|
-
}
|
|
1846
|
+
}
|
|
1730
1847
|
}
|
|
1731
1848
|
|
|
1732
1849
|
/**
|
|
1733
1850
|
* @private
|
|
1734
|
-
* @returns {void}
|
|
1851
|
+
* @returns {Promise<void>}
|
|
1735
1852
|
*/
|
|
1736
|
-
setupApp() {
|
|
1737
|
-
/** @type {
|
|
1738
|
-
this.app =
|
|
1853
|
+
async setupApp() {
|
|
1854
|
+
/** @type {A | undefined}*/
|
|
1855
|
+
this.app =
|
|
1856
|
+
typeof this.options.app === "function"
|
|
1857
|
+
? await this.options.app()
|
|
1858
|
+
: getExpress()();
|
|
1739
1859
|
}
|
|
1740
1860
|
|
|
1741
1861
|
/**
|
|
@@ -1789,204 +1909,297 @@ class Server {
|
|
|
1789
1909
|
* @private
|
|
1790
1910
|
* @returns {void}
|
|
1791
1911
|
*/
|
|
1792
|
-
|
|
1793
|
-
/** @type {
|
|
1794
|
-
(this.app).all(
|
|
1795
|
-
"*",
|
|
1796
|
-
/**
|
|
1797
|
-
* @param {Request} req
|
|
1798
|
-
* @param {Response} res
|
|
1799
|
-
* @param {NextFunction} next
|
|
1800
|
-
* @returns {void}
|
|
1801
|
-
*/
|
|
1802
|
-
(req, res, next) => {
|
|
1803
|
-
if (
|
|
1804
|
-
this.checkHeader(
|
|
1805
|
-
/** @type {{ [key: string]: string | undefined }} */
|
|
1806
|
-
(req.headers),
|
|
1807
|
-
"host",
|
|
1808
|
-
)
|
|
1809
|
-
) {
|
|
1810
|
-
return next();
|
|
1811
|
-
}
|
|
1912
|
+
setupWatchStaticFiles() {
|
|
1913
|
+
const watchFiles = /** @type {NormalizedStatic[]} */ (this.options.static);
|
|
1812
1914
|
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1915
|
+
if (watchFiles.length > 0) {
|
|
1916
|
+
for (const item of watchFiles) {
|
|
1917
|
+
if (item.watch) {
|
|
1918
|
+
this.watchFiles(item.directory, item.watch);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1816
1922
|
}
|
|
1817
1923
|
|
|
1818
1924
|
/**
|
|
1819
1925
|
* @private
|
|
1820
1926
|
* @returns {void}
|
|
1821
1927
|
*/
|
|
1822
|
-
|
|
1823
|
-
const
|
|
1928
|
+
setupWatchFiles() {
|
|
1929
|
+
const watchFiles = /** @type {WatchFiles[]} */ (this.options.watchFiles);
|
|
1824
1930
|
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1931
|
+
if (watchFiles.length > 0) {
|
|
1932
|
+
for (const item of watchFiles) {
|
|
1933
|
+
this.watchFiles(item.paths, item.options);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1830
1936
|
}
|
|
1831
1937
|
|
|
1832
1938
|
/**
|
|
1833
1939
|
* @private
|
|
1834
1940
|
* @returns {void}
|
|
1835
1941
|
*/
|
|
1836
|
-
|
|
1837
|
-
|
|
1942
|
+
setupMiddlewares() {
|
|
1943
|
+
/**
|
|
1944
|
+
* @type {Array<Middleware>}
|
|
1945
|
+
*/
|
|
1946
|
+
let middlewares = [];
|
|
1838
1947
|
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1948
|
+
// Register setup host header check for security
|
|
1949
|
+
middlewares.push({
|
|
1950
|
+
name: "host-header-check",
|
|
1951
|
+
/**
|
|
1952
|
+
* @param {Request} req
|
|
1953
|
+
* @param {Response} res
|
|
1954
|
+
* @param {NextFunction} next
|
|
1955
|
+
* @returns {void}
|
|
1956
|
+
*/
|
|
1957
|
+
middleware: (req, res, next) => {
|
|
1958
|
+
const headers =
|
|
1959
|
+
/** @type {{ [key: string]: string | undefined }} */
|
|
1960
|
+
(req.headers);
|
|
1961
|
+
const headerName = headers[":authority"] ? ":authority" : "host";
|
|
1842
1962
|
|
|
1843
|
-
|
|
1963
|
+
if (this.checkHeader(headers, headerName)) {
|
|
1964
|
+
next();
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1844
1967
|
|
|
1845
|
-
|
|
1968
|
+
res.statusCode = 403;
|
|
1969
|
+
res.end("Invalid Host header");
|
|
1970
|
+
},
|
|
1846
1971
|
});
|
|
1847
1972
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1973
|
+
const isHTTP2 =
|
|
1974
|
+
/** @type {ServerConfiguration<A, S>} */ (this.options.server).type ===
|
|
1975
|
+
"http2";
|
|
1851
1976
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1977
|
+
if (isHTTP2) {
|
|
1978
|
+
// TODO patch for https://github.com/pillarjs/finalhandler/pull/45, need remove then will be resolved
|
|
1979
|
+
middlewares.push({
|
|
1980
|
+
name: "http2-status-message-patch",
|
|
1981
|
+
middleware:
|
|
1982
|
+
/** @type {NextHandleFunction} */
|
|
1983
|
+
(_req, res, next) => {
|
|
1984
|
+
Object.defineProperty(res, "statusMessage", {
|
|
1985
|
+
get() {
|
|
1986
|
+
return "";
|
|
1987
|
+
},
|
|
1988
|
+
set() {},
|
|
1989
|
+
});
|
|
1854
1990
|
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1991
|
+
next();
|
|
1992
|
+
},
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1858
1995
|
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
launchEditor(fileName);
|
|
1863
|
-
}
|
|
1996
|
+
// compress is placed last and uses unshift so that it will be the first middleware used
|
|
1997
|
+
if (this.options.compress && !isHTTP2) {
|
|
1998
|
+
const compression = require("compression");
|
|
1864
1999
|
|
|
1865
|
-
|
|
2000
|
+
middlewares.push({ name: "compression", middleware: compression() });
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
if (typeof this.options.headers !== "undefined") {
|
|
2004
|
+
middlewares.push({
|
|
2005
|
+
name: "set-headers",
|
|
2006
|
+
middleware: this.setHeaders.bind(this),
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
middlewares.push({
|
|
2011
|
+
name: "webpack-dev-middleware",
|
|
2012
|
+
middleware: /** @type {MiddlewareHandler} */ (this.middleware),
|
|
1866
2013
|
});
|
|
1867
2014
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2015
|
+
// Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
|
|
2016
|
+
middlewares.push({
|
|
2017
|
+
name: "webpack-dev-server-sockjs-bundle",
|
|
2018
|
+
path: "/__webpack_dev_server__/sockjs.bundle.js",
|
|
2019
|
+
/**
|
|
2020
|
+
* @param {Request} req
|
|
2021
|
+
* @param {Response} res
|
|
2022
|
+
* @param {NextFunction} next
|
|
2023
|
+
* @returns {void}
|
|
2024
|
+
*/
|
|
2025
|
+
middleware: (req, res, next) => {
|
|
2026
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
2027
|
+
next();
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
const clientPath = path.join(
|
|
2032
|
+
__dirname,
|
|
2033
|
+
"..",
|
|
2034
|
+
"client/modules/sockjs-client/index.js",
|
|
2035
|
+
);
|
|
2036
|
+
|
|
2037
|
+
// Express send Etag and other headers by default, so let's keep them for compatibility reasons
|
|
2038
|
+
if (typeof res.sendFile === "function") {
|
|
2039
|
+
res.sendFile(clientPath);
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
let stats;
|
|
2044
|
+
|
|
2045
|
+
try {
|
|
2046
|
+
// TODO implement `inputFileSystem.createReadStream` in webpack
|
|
2047
|
+
stats = fs.statSync(clientPath);
|
|
2048
|
+
} catch (err) {
|
|
2049
|
+
next();
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
res.setHeader("Content-Type", "application/javascript; charset=UTF-8");
|
|
2054
|
+
res.setHeader("Content-Length", stats.size);
|
|
2055
|
+
|
|
1874
2056
|
if (req.method === "HEAD") {
|
|
1875
2057
|
res.end();
|
|
1876
2058
|
return;
|
|
1877
2059
|
}
|
|
1878
|
-
res.write(
|
|
1879
|
-
'<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>',
|
|
1880
|
-
);
|
|
1881
2060
|
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
: [/** @type {Stats} */ (stats).toJson()];
|
|
2061
|
+
fs.createReadStream(clientPath).pipe(res);
|
|
2062
|
+
},
|
|
2063
|
+
});
|
|
1886
2064
|
|
|
1887
|
-
|
|
2065
|
+
middlewares.push({
|
|
2066
|
+
name: "webpack-dev-server-invalidate",
|
|
2067
|
+
path: "/webpack-dev-server/invalidate",
|
|
2068
|
+
/**
|
|
2069
|
+
* @param {Request} req
|
|
2070
|
+
* @param {Response} res
|
|
2071
|
+
* @param {NextFunction} next
|
|
2072
|
+
* @returns {void}
|
|
2073
|
+
*/
|
|
2074
|
+
middleware: (req, res, next) => {
|
|
2075
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
2076
|
+
next();
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
1888
2079
|
|
|
1889
|
-
|
|
1890
|
-
* @type {StatsCompilation[]}
|
|
1891
|
-
*/
|
|
1892
|
-
(statsForPrint).forEach((item, index) => {
|
|
1893
|
-
res.write("<div>");
|
|
2080
|
+
this.invalidate();
|
|
1894
2081
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
? item.name
|
|
1899
|
-
: /** @type {MultiStats} */ (stats).stats
|
|
1900
|
-
? `unnamed[${index}]`
|
|
1901
|
-
: "unnamed";
|
|
2082
|
+
res.end();
|
|
2083
|
+
},
|
|
2084
|
+
});
|
|
1902
2085
|
|
|
1903
|
-
|
|
1904
|
-
|
|
2086
|
+
middlewares.push({
|
|
2087
|
+
name: "webpack-dev-server-open-editor",
|
|
2088
|
+
path: "/webpack-dev-server/open-editor",
|
|
2089
|
+
/**
|
|
2090
|
+
* @param {Request} req
|
|
2091
|
+
* @param {Response} res
|
|
2092
|
+
* @param {NextFunction} next
|
|
2093
|
+
* @returns {void}
|
|
2094
|
+
*/
|
|
2095
|
+
middleware: (req, res, next) => {
|
|
2096
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
2097
|
+
next();
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
1905
2100
|
|
|
1906
|
-
|
|
2101
|
+
if (!req.url) {
|
|
2102
|
+
next();
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
1907
2105
|
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
const assetName = asset.name;
|
|
1912
|
-
const assetURL = `${publicPath}${assetName}`;
|
|
2106
|
+
const resolveUrl = new URL(req.url, `http://${req.headers.host}`);
|
|
2107
|
+
const params = new URLSearchParams(resolveUrl.search);
|
|
2108
|
+
const fileName = params.get("fileName");
|
|
1913
2109
|
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
</li>`,
|
|
1918
|
-
);
|
|
1919
|
-
}
|
|
2110
|
+
if (typeof fileName === "string") {
|
|
2111
|
+
// @ts-ignore
|
|
2112
|
+
const launchEditor = require("launch-editor");
|
|
1920
2113
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
});
|
|
2114
|
+
launchEditor(fileName);
|
|
2115
|
+
}
|
|
1924
2116
|
|
|
1925
|
-
res.end(
|
|
1926
|
-
}
|
|
2117
|
+
res.end();
|
|
2118
|
+
},
|
|
1927
2119
|
});
|
|
1928
|
-
}
|
|
1929
2120
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2121
|
+
middlewares.push({
|
|
2122
|
+
name: "webpack-dev-server-assets",
|
|
2123
|
+
path: "/webpack-dev-server",
|
|
2124
|
+
/**
|
|
2125
|
+
* @param {Request} req
|
|
2126
|
+
* @param {Response} res
|
|
2127
|
+
* @param {NextFunction} next
|
|
2128
|
+
* @returns {void}
|
|
2129
|
+
*/
|
|
2130
|
+
middleware: (req, res, next) => {
|
|
2131
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
2132
|
+
next();
|
|
2133
|
+
return;
|
|
1940
2134
|
}
|
|
1941
|
-
});
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
2135
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
setupWatchFiles() {
|
|
1950
|
-
const { watchFiles } = this.options;
|
|
2136
|
+
if (!this.middleware) {
|
|
2137
|
+
next();
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
1951
2140
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
(watchFiles).forEach((item) => {
|
|
1955
|
-
this.watchFiles(item.paths, item.options);
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
2141
|
+
this.middleware.waitUntilValid((stats) => {
|
|
2142
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1959
2143
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
/**
|
|
1966
|
-
* @type {Array<Middleware>}
|
|
1967
|
-
*/
|
|
1968
|
-
let middlewares = [];
|
|
2144
|
+
// HEAD requests should not return body content
|
|
2145
|
+
if (req.method === "HEAD") {
|
|
2146
|
+
res.end();
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
1969
2149
|
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
2150
|
+
res.write(
|
|
2151
|
+
'<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>',
|
|
2152
|
+
);
|
|
1973
2153
|
|
|
1974
|
-
|
|
1975
|
-
|
|
2154
|
+
/**
|
|
2155
|
+
* @type {StatsCompilation[]}
|
|
2156
|
+
*/
|
|
2157
|
+
const statsForPrint =
|
|
2158
|
+
typeof (/** @type {MultiStats} */ (stats).stats) !== "undefined"
|
|
2159
|
+
? /** @type {NonNullable<StatsCompilation["children"]>} */
|
|
2160
|
+
(/** @type {MultiStats} */ (stats).toJson().children)
|
|
2161
|
+
: [/** @type {Stats} */ (stats).toJson()];
|
|
2162
|
+
|
|
2163
|
+
res.write(`<h1>Assets Report:</h1>`);
|
|
2164
|
+
|
|
2165
|
+
for (const [index, item] of statsForPrint.entries()) {
|
|
2166
|
+
res.write("<div>");
|
|
2167
|
+
|
|
2168
|
+
const name =
|
|
2169
|
+
// eslint-disable-next-line no-nested-ternary
|
|
2170
|
+
typeof item.name !== "undefined"
|
|
2171
|
+
? item.name
|
|
2172
|
+
: /** @type {MultiStats} */ (stats).stats
|
|
2173
|
+
? `unnamed[${index}]`
|
|
2174
|
+
: "unnamed";
|
|
2175
|
+
|
|
2176
|
+
res.write(`<h2>Compilation: ${name}</h2>`);
|
|
2177
|
+
res.write("<ul>");
|
|
2178
|
+
|
|
2179
|
+
const publicPath =
|
|
2180
|
+
item.publicPath === "auto" ? "" : item.publicPath;
|
|
2181
|
+
const assets =
|
|
2182
|
+
/** @type {NonNullable<StatsCompilation["assets"]>} */
|
|
2183
|
+
(item.assets);
|
|
2184
|
+
|
|
2185
|
+
for (const asset of assets) {
|
|
2186
|
+
const assetName = asset.name;
|
|
2187
|
+
const assetURL = `${publicPath}${assetName}`;
|
|
2188
|
+
|
|
2189
|
+
res.write(
|
|
2190
|
+
`<li>
|
|
2191
|
+
<strong><a href="${assetURL}" target="_blank">${assetName}</a></strong>
|
|
2192
|
+
</li>`,
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
1976
2195
|
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
path: "*",
|
|
1981
|
-
middleware: this.setHeaders.bind(this),
|
|
1982
|
-
});
|
|
1983
|
-
}
|
|
2196
|
+
res.write("</ul>");
|
|
2197
|
+
res.write("</div>");
|
|
2198
|
+
}
|
|
1984
2199
|
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
/** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
|
|
1989
|
-
(this.middleware),
|
|
2200
|
+
res.end("</body></html>");
|
|
2201
|
+
});
|
|
2202
|
+
},
|
|
1990
2203
|
});
|
|
1991
2204
|
|
|
1992
2205
|
if (this.options.proxy) {
|
|
@@ -2106,8 +2319,8 @@ class Server {
|
|
|
2106
2319
|
|
|
2107
2320
|
if (typeof bypassUrl === "boolean") {
|
|
2108
2321
|
// skip the proxy
|
|
2109
|
-
|
|
2110
|
-
req.url =
|
|
2322
|
+
res.statusCode = 404;
|
|
2323
|
+
req.url = "";
|
|
2111
2324
|
next();
|
|
2112
2325
|
} else if (typeof bypassUrl === "string") {
|
|
2113
2326
|
// byPass to that url
|
|
@@ -2124,6 +2337,7 @@ class Server {
|
|
|
2124
2337
|
name: "http-proxy-middleware",
|
|
2125
2338
|
middleware: handler,
|
|
2126
2339
|
});
|
|
2340
|
+
|
|
2127
2341
|
// Also forward error requests to the proxy so it can handle them.
|
|
2128
2342
|
middlewares.push({
|
|
2129
2343
|
name: "http-proxy-middleware-error-handler",
|
|
@@ -2141,16 +2355,17 @@ class Server {
|
|
|
2141
2355
|
|
|
2142
2356
|
middlewares.push({
|
|
2143
2357
|
name: "webpack-dev-middleware",
|
|
2144
|
-
middleware:
|
|
2145
|
-
/** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
|
|
2146
|
-
(this.middleware),
|
|
2358
|
+
middleware: /** @type {MiddlewareHandler} */ (this.middleware),
|
|
2147
2359
|
});
|
|
2148
2360
|
}
|
|
2149
2361
|
|
|
2150
|
-
|
|
2362
|
+
const staticOptions =
|
|
2151
2363
|
/** @type {NormalizedStatic[]} */
|
|
2152
|
-
(this.options.static)
|
|
2153
|
-
|
|
2364
|
+
(this.options.static);
|
|
2365
|
+
|
|
2366
|
+
if (staticOptions.length > 0) {
|
|
2367
|
+
for (const staticOption of staticOptions) {
|
|
2368
|
+
for (const publicPath of staticOption.publicPath) {
|
|
2154
2369
|
middlewares.push({
|
|
2155
2370
|
name: "express-static",
|
|
2156
2371
|
path: publicPath,
|
|
@@ -2159,8 +2374,8 @@ class Server {
|
|
|
2159
2374
|
staticOption.staticOptions,
|
|
2160
2375
|
),
|
|
2161
2376
|
});
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2164
2379
|
}
|
|
2165
2380
|
|
|
2166
2381
|
if (this.options.historyApiFallback) {
|
|
@@ -2197,15 +2412,12 @@ class Server {
|
|
|
2197
2412
|
// it is able to handle '/index.html' request after redirect
|
|
2198
2413
|
middlewares.push({
|
|
2199
2414
|
name: "webpack-dev-middleware",
|
|
2200
|
-
middleware:
|
|
2201
|
-
/** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
|
|
2202
|
-
(this.middleware),
|
|
2415
|
+
middleware: /** @type {MiddlewareHandler} */ (this.middleware),
|
|
2203
2416
|
});
|
|
2204
2417
|
|
|
2205
|
-
if (
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
staticOption.publicPath.forEach((publicPath) => {
|
|
2418
|
+
if (staticOptions.length > 0) {
|
|
2419
|
+
for (const staticOption of staticOptions) {
|
|
2420
|
+
for (const publicPath of staticOption.publicPath) {
|
|
2209
2421
|
middlewares.push({
|
|
2210
2422
|
name: "express-static",
|
|
2211
2423
|
path: publicPath,
|
|
@@ -2214,17 +2426,16 @@ class Server {
|
|
|
2214
2426
|
staticOption.staticOptions,
|
|
2215
2427
|
),
|
|
2216
2428
|
});
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2219
2431
|
}
|
|
2220
2432
|
}
|
|
2221
2433
|
|
|
2222
|
-
if (
|
|
2434
|
+
if (staticOptions.length > 0) {
|
|
2223
2435
|
const serveIndex = require("serve-index");
|
|
2224
2436
|
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
staticOption.publicPath.forEach((publicPath) => {
|
|
2437
|
+
for (const staticOption of staticOptions) {
|
|
2438
|
+
for (const publicPath of staticOption.publicPath) {
|
|
2228
2439
|
if (staticOption.serveIndex) {
|
|
2229
2440
|
middlewares.push({
|
|
2230
2441
|
name: "serve-index",
|
|
@@ -2249,15 +2460,14 @@ class Server {
|
|
|
2249
2460
|
},
|
|
2250
2461
|
});
|
|
2251
2462
|
}
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2254
2465
|
}
|
|
2255
2466
|
|
|
2256
2467
|
// Register this middleware always as the last one so that it's only used as a
|
|
2257
2468
|
// fallback when no other middleware responses.
|
|
2258
2469
|
middlewares.push({
|
|
2259
2470
|
name: "options-middleware",
|
|
2260
|
-
path: "*",
|
|
2261
2471
|
/**
|
|
2262
2472
|
* @param {Request} req
|
|
2263
2473
|
* @param {Response} res
|
|
@@ -2279,37 +2489,93 @@ class Server {
|
|
|
2279
2489
|
middlewares = this.options.setupMiddlewares(middlewares, this);
|
|
2280
2490
|
}
|
|
2281
2491
|
|
|
2282
|
-
|
|
2492
|
+
// Lazy init webpack dev middleware
|
|
2493
|
+
const lazyInitDevMiddleware = () => {
|
|
2494
|
+
if (!this.middleware) {
|
|
2495
|
+
const webpackDevMiddleware = require("webpack-dev-middleware");
|
|
2496
|
+
|
|
2497
|
+
// middleware for serving webpack bundle
|
|
2498
|
+
/** @type {import("webpack-dev-middleware").API<Request, Response>} */
|
|
2499
|
+
this.middleware = webpackDevMiddleware(
|
|
2500
|
+
this.compiler,
|
|
2501
|
+
this.options.devMiddleware,
|
|
2502
|
+
);
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
return this.middleware;
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2508
|
+
for (const i of middlewares) {
|
|
2509
|
+
if (i.name === "webpack-dev-middleware") {
|
|
2510
|
+
const item = /** @type {MiddlewareObject} */ (i);
|
|
2511
|
+
|
|
2512
|
+
if (typeof item.middleware === "undefined") {
|
|
2513
|
+
item.middleware = lazyInitDevMiddleware();
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
for (const middleware of middlewares) {
|
|
2283
2519
|
if (typeof middleware === "function") {
|
|
2284
|
-
/** @type {
|
|
2285
|
-
(this.app).use(
|
|
2520
|
+
/** @type {A} */
|
|
2521
|
+
(this.app).use(
|
|
2522
|
+
/** @type {NextHandleFunction | HandleFunction} */
|
|
2523
|
+
(middleware),
|
|
2524
|
+
);
|
|
2286
2525
|
} else if (typeof middleware.path !== "undefined") {
|
|
2287
|
-
/** @type {
|
|
2288
|
-
(this.app).use(
|
|
2526
|
+
/** @type {A} */
|
|
2527
|
+
(this.app).use(
|
|
2528
|
+
middleware.path,
|
|
2529
|
+
/** @type {SimpleHandleFunction | NextHandleFunction} */
|
|
2530
|
+
(middleware.middleware),
|
|
2531
|
+
);
|
|
2289
2532
|
} else {
|
|
2290
|
-
/** @type {
|
|
2291
|
-
(this.app).use(
|
|
2533
|
+
/** @type {A} */
|
|
2534
|
+
(this.app).use(
|
|
2535
|
+
/** @type {NextHandleFunction | HandleFunction} */
|
|
2536
|
+
(middleware.middleware),
|
|
2537
|
+
);
|
|
2292
2538
|
}
|
|
2293
|
-
}
|
|
2539
|
+
}
|
|
2294
2540
|
}
|
|
2295
2541
|
|
|
2296
2542
|
/**
|
|
2297
2543
|
* @private
|
|
2298
|
-
* @returns {void}
|
|
2544
|
+
* @returns {Promise<void>}
|
|
2299
2545
|
*/
|
|
2300
|
-
createServer() {
|
|
2301
|
-
const { type, options } =
|
|
2302
|
-
|
|
2303
|
-
|
|
2546
|
+
async createServer() {
|
|
2547
|
+
const { type, options } =
|
|
2548
|
+
/** @type {ServerConfiguration<A, S>} */
|
|
2549
|
+
(this.options.server);
|
|
2550
|
+
|
|
2551
|
+
if (typeof type === "function") {
|
|
2552
|
+
/** @type {S | undefined}*/
|
|
2553
|
+
this.server = await type(
|
|
2554
|
+
/** @type {ServerOptions} */
|
|
2555
|
+
(options),
|
|
2556
|
+
/** @type {A} */
|
|
2557
|
+
(this.app),
|
|
2558
|
+
);
|
|
2559
|
+
} else {
|
|
2560
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
2561
|
+
const serverType = require(/** @type {string} */ (type));
|
|
2304
2562
|
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2563
|
+
/** @type {S | undefined}*/
|
|
2564
|
+
this.server =
|
|
2565
|
+
type === "http2"
|
|
2566
|
+
? serverType.createSecureServer(
|
|
2567
|
+
{ ...options, allowHTTP1: true },
|
|
2568
|
+
this.app,
|
|
2569
|
+
)
|
|
2570
|
+
: serverType.createServer(options, this.app);
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
this.isTlsServer =
|
|
2574
|
+
typeof (
|
|
2575
|
+
/** @type {import("tls").Server} */ (this.server).setSecureContext
|
|
2576
|
+
) !== "undefined";
|
|
2311
2577
|
|
|
2312
|
-
/** @type {
|
|
2578
|
+
/** @type {S} */
|
|
2313
2579
|
(this.server).on(
|
|
2314
2580
|
"connection",
|
|
2315
2581
|
/**
|
|
@@ -2326,7 +2592,7 @@ class Server {
|
|
|
2326
2592
|
},
|
|
2327
2593
|
);
|
|
2328
2594
|
|
|
2329
|
-
/** @type {
|
|
2595
|
+
/** @type {S} */
|
|
2330
2596
|
(this.server).on(
|
|
2331
2597
|
"error",
|
|
2332
2598
|
/**
|
|
@@ -2344,9 +2610,8 @@ class Server {
|
|
|
2344
2610
|
*/
|
|
2345
2611
|
createWebSocketServer() {
|
|
2346
2612
|
/** @type {WebSocketServerImplementation | undefined | null} */
|
|
2347
|
-
this.webSocketServer = new
|
|
2348
|
-
|
|
2349
|
-
);
|
|
2613
|
+
this.webSocketServer = new (this.getServerTransport())(this);
|
|
2614
|
+
|
|
2350
2615
|
/** @type {WebSocketServerImplementation} */
|
|
2351
2616
|
(this.webSocketServer).implementation.on(
|
|
2352
2617
|
"connection",
|
|
@@ -2513,22 +2778,19 @@ class Server {
|
|
|
2513
2778
|
*/
|
|
2514
2779
|
runBonjour() {
|
|
2515
2780
|
const { Bonjour } = require("bonjour-service");
|
|
2781
|
+
const type = this.isTlsServer ? "https" : "http";
|
|
2782
|
+
|
|
2516
2783
|
/**
|
|
2517
2784
|
* @private
|
|
2518
2785
|
* @type {Bonjour | undefined}
|
|
2519
2786
|
*/
|
|
2520
2787
|
this.bonjour = new Bonjour();
|
|
2521
2788
|
this.bonjour.publish({
|
|
2522
|
-
// @ts-expect-error
|
|
2523
2789
|
name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
|
|
2524
|
-
// @ts-expect-error
|
|
2525
2790
|
port: /** @type {number} */ (this.options.port),
|
|
2526
|
-
|
|
2527
|
-
type:
|
|
2528
|
-
/** @type {ServerConfiguration} */
|
|
2529
|
-
(this.options.server).type === "http" ? "http" : "https",
|
|
2791
|
+
type,
|
|
2530
2792
|
subtypes: ["webpack"],
|
|
2531
|
-
.../** @type {BonjourOptions} */ (this.options.bonjour),
|
|
2793
|
+
.../** @type {Partial<BonjourOptions>} */ (this.options.bonjour),
|
|
2532
2794
|
});
|
|
2533
2795
|
}
|
|
2534
2796
|
|
|
@@ -2608,23 +2870,15 @@ class Server {
|
|
|
2608
2870
|
};
|
|
2609
2871
|
const useColor = getColorsOption(this.getCompilerOptions());
|
|
2610
2872
|
|
|
2873
|
+
const server = /** @type {S} */ (this.server);
|
|
2874
|
+
|
|
2611
2875
|
if (this.options.ipc) {
|
|
2612
|
-
this.logger.info(
|
|
2613
|
-
`Project is running at: "${
|
|
2614
|
-
/** @type {import("http").Server} */
|
|
2615
|
-
(this.server).address()
|
|
2616
|
-
}"`,
|
|
2617
|
-
);
|
|
2876
|
+
this.logger.info(`Project is running at: "${server.address()}"`);
|
|
2618
2877
|
} else {
|
|
2619
|
-
const protocol =
|
|
2620
|
-
/** @type {ServerConfiguration} */
|
|
2621
|
-
(this.options.server).type === "http" ? "http" : "https";
|
|
2878
|
+
const protocol = this.isTlsServer ? "https" : "http";
|
|
2622
2879
|
const { address, port } =
|
|
2623
2880
|
/** @type {import("net").AddressInfo} */
|
|
2624
|
-
(
|
|
2625
|
-
/** @type {import("http").Server} */
|
|
2626
|
-
(this.server).address()
|
|
2627
|
-
);
|
|
2881
|
+
(server.address());
|
|
2628
2882
|
/**
|
|
2629
2883
|
* @param {string} newHostname
|
|
2630
2884
|
* @returns {string}
|
|
@@ -2632,7 +2886,7 @@ class Server {
|
|
|
2632
2886
|
const prettyPrintURL = (newHostname) =>
|
|
2633
2887
|
url.format({ protocol, hostname: newHostname, port, pathname: "/" });
|
|
2634
2888
|
|
|
2635
|
-
let
|
|
2889
|
+
let host;
|
|
2636
2890
|
let localhost;
|
|
2637
2891
|
let loopbackIPv4;
|
|
2638
2892
|
let loopbackIPv6;
|
|
@@ -2652,7 +2906,7 @@ class Server {
|
|
|
2652
2906
|
}
|
|
2653
2907
|
|
|
2654
2908
|
if (!isIP) {
|
|
2655
|
-
|
|
2909
|
+
host = prettyPrintURL(this.options.host);
|
|
2656
2910
|
}
|
|
2657
2911
|
}
|
|
2658
2912
|
}
|
|
@@ -2661,14 +2915,15 @@ class Server {
|
|
|
2661
2915
|
|
|
2662
2916
|
if (parsedIP.range() === "unspecified") {
|
|
2663
2917
|
localhost = prettyPrintURL("localhost");
|
|
2918
|
+
loopbackIPv6 = prettyPrintURL("::1");
|
|
2664
2919
|
|
|
2665
|
-
const networkIPv4 =
|
|
2920
|
+
const networkIPv4 = Server.findIp("v4", false);
|
|
2666
2921
|
|
|
2667
2922
|
if (networkIPv4) {
|
|
2668
2923
|
networkUrlIPv4 = prettyPrintURL(networkIPv4);
|
|
2669
2924
|
}
|
|
2670
2925
|
|
|
2671
|
-
const networkIPv6 =
|
|
2926
|
+
const networkIPv6 = Server.findIp("v6", false);
|
|
2672
2927
|
|
|
2673
2928
|
if (networkIPv6) {
|
|
2674
2929
|
networkUrlIPv6 = prettyPrintURL(networkIPv6);
|
|
@@ -2697,8 +2952,8 @@ class Server {
|
|
|
2697
2952
|
|
|
2698
2953
|
this.logger.info("Project is running at:");
|
|
2699
2954
|
|
|
2700
|
-
if (
|
|
2701
|
-
this.logger.info(`Server: ${colors.info(useColor,
|
|
2955
|
+
if (host) {
|
|
2956
|
+
this.logger.info(`Server: ${colors.info(useColor, host)}`);
|
|
2702
2957
|
}
|
|
2703
2958
|
|
|
2704
2959
|
if (localhost || loopbackIPv4 || loopbackIPv6) {
|
|
@@ -2770,11 +3025,7 @@ class Server {
|
|
|
2770
3025
|
if (this.options.bonjour) {
|
|
2771
3026
|
const bonjourProtocol =
|
|
2772
3027
|
/** @type {BonjourOptions} */
|
|
2773
|
-
(this.options.bonjour).type ||
|
|
2774
|
-
/** @type {ServerConfiguration} */
|
|
2775
|
-
(this.options.server).type === "http"
|
|
2776
|
-
? "http"
|
|
2777
|
-
: "https";
|
|
3028
|
+
(this.options.bonjour).type || this.isTlsServer ? "https" : "http";
|
|
2778
3029
|
|
|
2779
3030
|
this.logger.info(
|
|
2780
3031
|
`Broadcasting "${bonjourProtocol}" with subtype of "webpack" via ZeroConf DNS (Bonjour)`,
|
|
@@ -2796,8 +3047,8 @@ class Server {
|
|
|
2796
3047
|
headers = headers(
|
|
2797
3048
|
req,
|
|
2798
3049
|
res,
|
|
2799
|
-
|
|
2800
|
-
|
|
3050
|
+
// eslint-disable-next-line no-undefined
|
|
3051
|
+
this.middleware ? this.middleware.context : undefined,
|
|
2801
3052
|
);
|
|
2802
3053
|
}
|
|
2803
3054
|
|
|
@@ -2806,6 +3057,8 @@ class Server {
|
|
|
2806
3057
|
*/
|
|
2807
3058
|
const allHeaders = [];
|
|
2808
3059
|
|
|
3060
|
+
allHeaders.push({ key: "X_TEST", value: "TEST" });
|
|
3061
|
+
|
|
2809
3062
|
if (!Array.isArray(headers)) {
|
|
2810
3063
|
// eslint-disable-next-line guard-for-in
|
|
2811
3064
|
for (const name in headers) {
|
|
@@ -2816,14 +3069,9 @@ class Server {
|
|
|
2816
3069
|
headers = allHeaders;
|
|
2817
3070
|
}
|
|
2818
3071
|
|
|
2819
|
-
headers
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
*/
|
|
2823
|
-
(header) => {
|
|
2824
|
-
res.setHeader(header.key, header.value);
|
|
2825
|
-
},
|
|
2826
|
-
);
|
|
3072
|
+
for (const { key, value } of headers) {
|
|
3073
|
+
res.setHeader(key, value);
|
|
3074
|
+
}
|
|
2827
3075
|
}
|
|
2828
3076
|
|
|
2829
3077
|
next();
|
|
@@ -3097,7 +3345,7 @@ class Server {
|
|
|
3097
3345
|
|
|
3098
3346
|
await /** @type {Promise<void>} */ (
|
|
3099
3347
|
new Promise((resolve) => {
|
|
3100
|
-
/** @type {
|
|
3348
|
+
/** @type {S} */
|
|
3101
3349
|
(this.server).listen(listenOptions, () => {
|
|
3102
3350
|
resolve();
|
|
3103
3351
|
});
|
|
@@ -3183,10 +3431,10 @@ class Server {
|
|
|
3183
3431
|
if (this.server) {
|
|
3184
3432
|
await /** @type {Promise<void>} */ (
|
|
3185
3433
|
new Promise((resolve) => {
|
|
3186
|
-
/** @type {
|
|
3434
|
+
/** @type {S} */
|
|
3187
3435
|
(this.server).close(() => {
|
|
3188
|
-
|
|
3189
|
-
|
|
3436
|
+
// eslint-disable-next-line no-undefined
|
|
3437
|
+
this.server = undefined;
|
|
3190
3438
|
resolve();
|
|
3191
3439
|
});
|
|
3192
3440
|
|
|
@@ -3205,7 +3453,6 @@ class Server {
|
|
|
3205
3453
|
(this.middleware).close((error) => {
|
|
3206
3454
|
if (error) {
|
|
3207
3455
|
reject(error);
|
|
3208
|
-
|
|
3209
3456
|
return;
|
|
3210
3457
|
}
|
|
3211
3458
|
|
|
@@ -3214,7 +3461,8 @@ class Server {
|
|
|
3214
3461
|
})
|
|
3215
3462
|
);
|
|
3216
3463
|
|
|
3217
|
-
|
|
3464
|
+
// eslint-disable-next-line no-undefined
|
|
3465
|
+
this.middleware = undefined;
|
|
3218
3466
|
}
|
|
3219
3467
|
}
|
|
3220
3468
|
|