@rspack/dev-server 2.0.0-beta.4 → 2.0.0-beta.6

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/dist/index.js CHANGED
@@ -1 +1,1469 @@
1
- export { RspackDevServer } from "./131.js";
1
+ import * as __rspack_external_zlib from "zlib";
2
+ import { __webpack_require__ } from "./rslib-runtime.js";
3
+ import { lstatSync, promises, readFileSync, realpathSync, statSync, unlinkSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { networkInterfaces, tmpdir } from "node:os";
6
+ import { dirname, join, resolve as external_node_path_resolve } from "node:path";
7
+ import { format } from "node:url";
8
+ import { deprecate, styleText } from "node:util";
9
+ import ipaddr from "ipaddr.js";
10
+ import { createServer } from "node:net";
11
+ import { WebSocketServer } from "ws";
12
+ __webpack_require__.add({
13
+ "./node_modules/.pnpm/http-compression@1.1.2/node_modules/http-compression/src/index.js" (module, __unused_rspack_exports, __webpack_require__) {
14
+ const zlib = __webpack_require__("zlib");
15
+ const MIMES = /text|javascript|\/json|xml/i;
16
+ const noop = ()=>{};
17
+ const getChunkSize = (chunk, enc)=>chunk ? Buffer.byteLength(chunk, enc) : 0;
18
+ module.exports = ({ threshold = 1024, level = {
19
+ brotli: 0,
20
+ gzip: 1
21
+ }, brotli = true, gzip = true, mimes = MIMES } = {})=>{
22
+ const brotliOpts = 'object' == typeof brotli && brotli || {};
23
+ const gzipOpts = 'object' == typeof gzip && gzip || {};
24
+ if (brotli && !zlib.createBrotliCompress) brotli = false;
25
+ return (req, res, next = noop)=>{
26
+ const accept = req.headers['accept-encoding'];
27
+ const encoding = accept && (brotli && accept.match(/\bbr\b/) || gzip && accept.match(/\bgzip\b/) || [])[0];
28
+ if ('HEAD' === req.method || !encoding) return next();
29
+ let compress;
30
+ let pendingStatus;
31
+ let pendingListeners = [];
32
+ let started = false;
33
+ let size = 0;
34
+ function start() {
35
+ started = true;
36
+ size = 0 | res.getHeader('Content-Length') || size;
37
+ const compressible = mimes.test(String(res.getHeader('Content-Type') || 'text/plain'));
38
+ const cleartext = !res.getHeader('Content-Encoding');
39
+ const listeners = pendingListeners || [];
40
+ if (compressible && cleartext && size >= threshold) {
41
+ res.setHeader('Content-Encoding', encoding);
42
+ res.removeHeader('Content-Length');
43
+ compress = 'br' === encoding ? zlib.createBrotliCompress({
44
+ params: Object.assign({
45
+ [zlib.constants.BROTLI_PARAM_QUALITY]: level.brotli,
46
+ [zlib.constants.BROTLI_PARAM_SIZE_HINT]: size
47
+ }, brotliOpts)
48
+ }) : zlib.createGzip(Object.assign({
49
+ level: level.gzip
50
+ }, gzipOpts));
51
+ compress.on('data', (chunk)=>false === write.call(res, chunk) && compress.pause());
52
+ on.call(res, 'drain', ()=>compress.resume());
53
+ compress.on('end', ()=>end.call(res));
54
+ listeners.forEach((p)=>compress.on.apply(compress, p));
55
+ } else {
56
+ pendingListeners = null;
57
+ listeners.forEach((p)=>on.apply(res, p));
58
+ }
59
+ writeHead.call(res, pendingStatus || res.statusCode);
60
+ }
61
+ const { end, write, on, writeHead } = res;
62
+ res.writeHead = function(status, reason, headers) {
63
+ if ('string' != typeof reason) [headers, reason] = [
64
+ reason,
65
+ headers
66
+ ];
67
+ if (headers) for(const i in headers)res.setHeader(i, headers[i]);
68
+ pendingStatus = status;
69
+ return this;
70
+ };
71
+ res.write = function(chunk, enc) {
72
+ size += getChunkSize(chunk, enc);
73
+ if (!started) start();
74
+ if (!compress) return write.apply(this, arguments);
75
+ return compress.write.apply(compress, arguments);
76
+ };
77
+ res.end = function(chunk, enc) {
78
+ if (arguments.length > 0 && 'function' != typeof chunk) size += getChunkSize(chunk, enc);
79
+ if (!started) start();
80
+ if (!compress) return end.apply(this, arguments);
81
+ return compress.end.apply(compress, arguments);
82
+ };
83
+ res.on = function(type, listener) {
84
+ if (pendingListeners && 'drain' === type) if (compress) compress.on(type, listener);
85
+ else pendingListeners.push([
86
+ type,
87
+ listener
88
+ ]);
89
+ else on.call(this, type, listener);
90
+ return this;
91
+ };
92
+ next();
93
+ };
94
+ };
95
+ },
96
+ zlib (module) {
97
+ module.exports = __rspack_external_zlib;
98
+ }
99
+ });
100
+ var external_node_util_namespaceObject = {};
101
+ __webpack_require__.r(external_node_util_namespaceObject);
102
+ __webpack_require__.d(external_node_util_namespaceObject, {
103
+ deprecate: ()=>deprecate,
104
+ styleText: ()=>styleText
105
+ });
106
+ const minPort = 1024;
107
+ const maxPort = 65535;
108
+ const getLocalHosts = ()=>{
109
+ const interfaces = networkInterfaces();
110
+ const results = new Set([
111
+ void 0,
112
+ '0.0.0.0'
113
+ ]);
114
+ for (const _interface of Object.values(interfaces))if (_interface) for (const config of _interface)results.add(config.address);
115
+ return results;
116
+ };
117
+ const checkAvailablePort = (basePort, host)=>new Promise((resolve, reject)=>{
118
+ const server = createServer();
119
+ server.unref();
120
+ server.on('error', reject);
121
+ server.listen(basePort, host, ()=>{
122
+ const { port } = server.address();
123
+ server.close(()=>{
124
+ resolve(port);
125
+ });
126
+ });
127
+ });
128
+ const getAvailablePort = async (port, hosts)=>{
129
+ const nonExistentInterfaceErrors = new Set([
130
+ 'EADDRNOTAVAIL',
131
+ 'EINVAL'
132
+ ]);
133
+ for (const host of hosts)try {
134
+ await checkAvailablePort(port, host);
135
+ } catch (error) {
136
+ if (!nonExistentInterfaceErrors.has(error.code || '')) throw error;
137
+ }
138
+ return port;
139
+ };
140
+ async function getPort(basePort, host) {
141
+ if (basePort < minPort || basePort > maxPort) throw new Error(`Port number must lie between ${minPort} and ${maxPort}`);
142
+ let port = basePort;
143
+ const localhosts = getLocalHosts();
144
+ const hosts = host && !localhosts.has(host) ? new Set([
145
+ host
146
+ ]) : localhosts;
147
+ const portUnavailableErrors = new Set([
148
+ 'EADDRINUSE',
149
+ 'EACCES'
150
+ ]);
151
+ while(port <= maxPort)try {
152
+ const availablePort = await getAvailablePort(port, hosts);
153
+ return availablePort;
154
+ } catch (error) {
155
+ if (!portUnavailableErrors.has(error.code || '')) throw error;
156
+ port += 1;
157
+ }
158
+ throw new Error('No available ports found');
159
+ }
160
+ class BaseServer {
161
+ server;
162
+ clients;
163
+ constructor(server){
164
+ this.server = server;
165
+ this.clients = [];
166
+ }
167
+ }
168
+ const servers_BaseServer = BaseServer;
169
+ class WebsocketServer extends servers_BaseServer {
170
+ static heartbeatInterval = 1000;
171
+ implementation;
172
+ constructor(server){
173
+ super(server);
174
+ const options = {
175
+ ...this.server.options.webSocketServer.options,
176
+ clientTracking: false
177
+ };
178
+ const isNoServerMode = void 0 === options.port && void 0 === options.server;
179
+ if (isNoServerMode) options.noServer = true;
180
+ this.implementation = new WebSocketServer(options);
181
+ this.server.server.on('upgrade', (req, sock, head)=>{
182
+ if (!this.implementation.shouldHandle(req)) return;
183
+ this.implementation.handleUpgrade(req, sock, head, (connection)=>{
184
+ this.implementation.emit('connection', connection, req);
185
+ });
186
+ });
187
+ this.implementation.on('error', (err)=>{
188
+ this.server.logger.error(err.message);
189
+ });
190
+ const interval = setInterval(()=>{
191
+ for (const client of this.clients){
192
+ if (false === client.isAlive) {
193
+ client.terminate();
194
+ continue;
195
+ }
196
+ client.isAlive = false;
197
+ client.ping(()=>{});
198
+ }
199
+ }, WebsocketServer.heartbeatInterval);
200
+ this.implementation.on('connection', (client)=>{
201
+ this.clients.push(client);
202
+ client.isAlive = true;
203
+ client.on('pong', ()=>{
204
+ client.isAlive = true;
205
+ });
206
+ client.on('close', ()=>{
207
+ this.clients.splice(this.clients.indexOf(client), 1);
208
+ });
209
+ client.on('error', (err)=>{
210
+ this.server.logger.error(err.message);
211
+ });
212
+ });
213
+ this.implementation.on('close', ()=>{
214
+ clearInterval(interval);
215
+ });
216
+ }
217
+ }
218
+ const src = __webpack_require__("./node_modules/.pnpm/http-compression@1.1.2/node_modules/http-compression/src/index.js");
219
+ var src_default = /*#__PURE__*/ __webpack_require__.n(src);
220
+ const { styleText: server_styleText } = external_node_util_namespaceObject;
221
+ const server_require = createRequire(import.meta.url);
222
+ if (!process.env.WEBPACK_SERVE) process.env.WEBPACK_SERVE = 'true';
223
+ const memoize = (fn)=>{
224
+ let cache = false;
225
+ let result;
226
+ let fnRef = fn;
227
+ return ()=>{
228
+ if (cache) return result;
229
+ result = fnRef();
230
+ cache = true;
231
+ fnRef = void 0;
232
+ return result;
233
+ };
234
+ };
235
+ const getConnect = async ()=>{
236
+ const { connect } = await import("connect-next");
237
+ return connect;
238
+ };
239
+ const getChokidar = memoize(()=>import("chokidar"));
240
+ const getServeStatic = memoize(()=>server_require('serve-static'));
241
+ const encodeOverlaySettings = (setting)=>'function' == typeof setting ? encodeURIComponent(setting.toString()) : setting;
242
+ const DEFAULT_ALLOWED_PROTOCOLS = /^(file|.+-extension):/i;
243
+ function parseHostnameFromHeader(header) {
244
+ try {
245
+ const parsedUrl = new URL(/^(.+:)?\/\//.test(header) ? header : `//${header}`, 'http://localhost/');
246
+ let { hostname } = parsedUrl;
247
+ if (hostname.startsWith('[') && hostname.endsWith(']')) hostname = hostname.slice(1, -1);
248
+ return hostname;
249
+ } catch {
250
+ return null;
251
+ }
252
+ }
253
+ function isMultiCompiler(compiler) {
254
+ return Array.isArray(compiler.compilers);
255
+ }
256
+ class Server {
257
+ compiler;
258
+ logger;
259
+ options;
260
+ staticWatchers;
261
+ listeners;
262
+ webSocketProxies;
263
+ sockets;
264
+ currentHash;
265
+ isTlsServer = false;
266
+ webSocketServer;
267
+ middleware;
268
+ server;
269
+ app;
270
+ stats;
271
+ constructor(options, compiler){
272
+ this.compiler = compiler;
273
+ this.logger = this.compiler.getInfrastructureLogger('rspack-dev-server');
274
+ this.options = options;
275
+ this.staticWatchers = [];
276
+ this.listeners = [];
277
+ this.webSocketProxies = [];
278
+ this.sockets = [];
279
+ this.currentHash = void 0;
280
+ }
281
+ static get DEFAULT_STATS() {
282
+ return {
283
+ all: false,
284
+ hash: true,
285
+ warnings: true,
286
+ errors: true,
287
+ errorDetails: false
288
+ };
289
+ }
290
+ static isAbsoluteURL(URL1) {
291
+ if (/^[a-zA-Z]:\\/.test(URL1)) return false;
292
+ return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(URL1);
293
+ }
294
+ static findIp(gatewayOrFamily, isInternal) {
295
+ if ('v4' === gatewayOrFamily || 'v6' === gatewayOrFamily) {
296
+ let host;
297
+ const networks = Object.values(networkInterfaces()).flatMap((networks)=>networks ?? []).filter((network)=>{
298
+ if (!network || !network.address) return false;
299
+ if (network.family !== `IP${gatewayOrFamily}`) return false;
300
+ if (void 0 !== isInternal && network.internal !== isInternal) return false;
301
+ if ('v6' === gatewayOrFamily) {
302
+ const range = ipaddr.parse(network.address).range();
303
+ if ('ipv4Mapped' !== range && 'uniqueLocal' !== range && 'loopback' !== range) return false;
304
+ }
305
+ return network.address;
306
+ });
307
+ if (networks.length > 0) {
308
+ host = networks[0].address;
309
+ if (host.includes(':')) host = `[${host}]`;
310
+ }
311
+ return host;
312
+ }
313
+ const gatewayIp = ipaddr.parse(gatewayOrFamily);
314
+ for (const addresses of Object.values(networkInterfaces()))for (const { cidr } of addresses){
315
+ const net = ipaddr.parseCIDR(cidr);
316
+ if (net[0] && net[0].kind() === gatewayIp.kind() && gatewayIp.match(net)) return net[0].toString();
317
+ }
318
+ }
319
+ static async getHostname(hostname) {
320
+ if ('local-ip' === hostname) return Server.findIp('v4', false) || Server.findIp('v6', false) || '0.0.0.0';
321
+ if ('local-ipv4' === hostname) return Server.findIp('v4', false) || '0.0.0.0';
322
+ if ('local-ipv6' === hostname) return Server.findIp('v6', false) || '::';
323
+ return hostname;
324
+ }
325
+ static async getFreePort(port, host) {
326
+ if (null != port && 'auto' !== port) return port;
327
+ const { default: pRetry } = await import("./0~p-retry.js");
328
+ const basePort = void 0 !== process.env.RSPACK_DEV_SERVER_BASE_PORT ? Number.parseInt(process.env.RSPACK_DEV_SERVER_BASE_PORT, 10) : 8080;
329
+ const defaultPortRetry = void 0 !== process.env.RSPACK_DEV_SERVER_PORT_RETRY ? Number.parseInt(process.env.RSPACK_DEV_SERVER_PORT_RETRY, 10) : 3;
330
+ return pRetry(()=>getPort(basePort, host), {
331
+ retries: defaultPortRetry
332
+ });
333
+ }
334
+ static findCacheDir() {
335
+ const cwd = process.cwd();
336
+ let dir = cwd;
337
+ for(;;){
338
+ try {
339
+ if (statSync(join(dir, 'package.json')).isFile()) break;
340
+ } catch {}
341
+ const parent = dirname(dir);
342
+ if (dir === parent) {
343
+ dir = void 0;
344
+ break;
345
+ }
346
+ dir = parent;
347
+ }
348
+ if (!dir) return external_node_path_resolve(cwd, '.cache/rspack-dev-server');
349
+ if ('1' === process.versions.pnp) return external_node_path_resolve(dir, '.pnp/.cache/rspack-dev-server');
350
+ if ('3' === process.versions.pnp) return external_node_path_resolve(dir, '.yarn/.cache/rspack-dev-server');
351
+ return external_node_path_resolve(dir, 'node_modules/.cache/rspack-dev-server');
352
+ }
353
+ #addAdditionalEntries(compiler) {
354
+ const additionalEntries = [];
355
+ const isWebTarget = Boolean(compiler.platform.web);
356
+ if (this.options.client && isWebTarget) {
357
+ let webSocketURLStr = '';
358
+ if (this.options.webSocketServer) {
359
+ const webSocketURL = this.options.client.webSocketURL;
360
+ const webSocketServer = this.options.webSocketServer;
361
+ const searchParams = new URLSearchParams();
362
+ let protocol;
363
+ protocol = void 0 !== webSocketURL.protocol ? webSocketURL.protocol : this.isTlsServer ? 'wss:' : 'ws:';
364
+ searchParams.set('protocol', protocol);
365
+ if (void 0 !== webSocketURL.username) searchParams.set('username', webSocketURL.username);
366
+ if (void 0 !== webSocketURL.password) searchParams.set('password', webSocketURL.password);
367
+ let hostname;
368
+ const isWebSocketServerHostDefined = void 0 !== webSocketServer.options.host;
369
+ const isWebSocketServerPortDefined = void 0 !== webSocketServer.options.port;
370
+ hostname = void 0 !== webSocketURL.hostname ? webSocketURL.hostname : isWebSocketServerHostDefined ? webSocketServer.options.host : void 0 !== this.options.host ? this.options.host : '0.0.0.0';
371
+ searchParams.set('hostname', hostname);
372
+ let port;
373
+ port = void 0 !== webSocketURL.port ? webSocketURL.port : isWebSocketServerPortDefined ? webSocketServer.options.port : 'number' == typeof this.options.port ? this.options.port : 'string' == typeof this.options.port && 'auto' !== this.options.port ? Number(this.options.port) : '0';
374
+ searchParams.set('port', String(port));
375
+ let pathname = '';
376
+ if (void 0 !== webSocketURL.pathname) pathname = webSocketURL.pathname;
377
+ else if (void 0 !== webSocketServer.options.path) pathname = webSocketServer.options.path;
378
+ searchParams.set('pathname', pathname);
379
+ const client = this.options.client;
380
+ if (void 0 !== client.logging) searchParams.set('logging', client.logging);
381
+ if (void 0 !== client.progress) searchParams.set('progress', String(client.progress));
382
+ if (void 0 !== client.overlay) {
383
+ const overlayString = 'boolean' == typeof client.overlay ? String(client.overlay) : JSON.stringify({
384
+ ...client.overlay,
385
+ errors: encodeOverlaySettings(client.overlay.errors),
386
+ warnings: encodeOverlaySettings(client.overlay.warnings),
387
+ runtimeErrors: encodeOverlaySettings(client.overlay.runtimeErrors)
388
+ });
389
+ searchParams.set('overlay', overlayString);
390
+ }
391
+ if (void 0 !== client.reconnect) searchParams.set('reconnect', 'number' == typeof client.reconnect ? String(client.reconnect) : '10');
392
+ if (void 0 !== this.options.hot) searchParams.set('hot', String(this.options.hot));
393
+ if (void 0 !== this.options.liveReload) searchParams.set('live-reload', String(this.options.liveReload));
394
+ webSocketURLStr = searchParams.toString();
395
+ }
396
+ additionalEntries.push(`${this.getClientEntry()}?${webSocketURLStr}`);
397
+ }
398
+ const clientHotEntry = this.getClientHotEntry();
399
+ if (clientHotEntry) additionalEntries.push(clientHotEntry);
400
+ for (const additionalEntry of additionalEntries)new compiler.rspack.EntryPlugin(compiler.context, additionalEntry, {
401
+ name: void 0
402
+ }).apply(compiler);
403
+ }
404
+ #getCompilerOptions() {
405
+ if (void 0 !== this.compiler.compilers) {
406
+ if (1 === this.compiler.compilers.length) return this.compiler.compilers[0].options;
407
+ const compilerWithDevServer = this.compiler.compilers.find((config)=>config.options.devServer);
408
+ if (compilerWithDevServer) return compilerWithDevServer.options;
409
+ const compilerWithWebTarget = this.compiler.compilers.find((compiler)=>Boolean(compiler.platform.web));
410
+ if (compilerWithWebTarget) return compilerWithWebTarget.options;
411
+ return this.compiler.compilers[0].options;
412
+ }
413
+ return this.compiler.options;
414
+ }
415
+ #shouldLogInfrastructureInfo() {
416
+ const compilerOptions = this.#getCompilerOptions();
417
+ const { level = 'info' } = compilerOptions.infrastructureLogging || {};
418
+ return 'info' === level || 'log' === level || 'verbose' === level;
419
+ }
420
+ async #normalizeOptions() {
421
+ const { options } = this;
422
+ const compilerOptions = this.#getCompilerOptions();
423
+ const compilerWatchOptions = compilerOptions.watchOptions;
424
+ const getWatchOptions = (watchOptions = {})=>{
425
+ const getPolling = ()=>{
426
+ if (void 0 !== watchOptions.usePolling) return watchOptions.usePolling;
427
+ if (void 0 !== watchOptions.poll) return Boolean(watchOptions.poll);
428
+ if (void 0 !== compilerWatchOptions.poll) return Boolean(compilerWatchOptions.poll);
429
+ return false;
430
+ };
431
+ const getInterval = ()=>{
432
+ if (void 0 !== watchOptions.interval) return watchOptions.interval;
433
+ if ('number' == typeof watchOptions.poll) return watchOptions.poll;
434
+ if ('number' == typeof compilerWatchOptions.poll) return compilerWatchOptions.poll;
435
+ };
436
+ const usePolling = getPolling();
437
+ const interval = getInterval();
438
+ const { poll: _poll, ...rest } = watchOptions;
439
+ return {
440
+ ignoreInitial: true,
441
+ persistent: true,
442
+ followSymlinks: false,
443
+ atomic: false,
444
+ alwaysStat: true,
445
+ ignorePermissionErrors: true,
446
+ usePolling,
447
+ ...void 0 !== interval ? {
448
+ interval
449
+ } : {},
450
+ ...rest
451
+ };
452
+ };
453
+ const getStaticItem = (optionsForStatic)=>{
454
+ const getDefaultStaticOptions = ()=>({
455
+ directory: join(process.cwd(), 'public'),
456
+ staticOptions: {},
457
+ publicPath: [
458
+ '/'
459
+ ],
460
+ watch: getWatchOptions()
461
+ });
462
+ let item;
463
+ if (void 0 === optionsForStatic) item = getDefaultStaticOptions();
464
+ else if ('string' == typeof optionsForStatic) item = {
465
+ ...getDefaultStaticOptions(),
466
+ directory: optionsForStatic
467
+ };
468
+ else {
469
+ const def = getDefaultStaticOptions();
470
+ item = {
471
+ directory: void 0 !== optionsForStatic.directory ? optionsForStatic.directory : def.directory,
472
+ staticOptions: void 0 !== optionsForStatic.staticOptions ? {
473
+ ...def.staticOptions,
474
+ ...optionsForStatic.staticOptions
475
+ } : def.staticOptions,
476
+ publicPath: void 0 !== optionsForStatic.publicPath ? Array.isArray(optionsForStatic.publicPath) ? optionsForStatic.publicPath : [
477
+ optionsForStatic.publicPath
478
+ ] : def.publicPath,
479
+ watch: void 0 !== optionsForStatic.watch ? 'boolean' == typeof optionsForStatic.watch ? optionsForStatic.watch ? def.watch : false : getWatchOptions(optionsForStatic.watch) : def.watch
480
+ };
481
+ }
482
+ if (Server.isAbsoluteURL(item.directory)) throw new Error('Using a URL as static.directory is not supported');
483
+ return item;
484
+ };
485
+ if (void 0 === options.allowedHosts) options.allowedHosts = 'auto';
486
+ else if ('string' == typeof options.allowedHosts && 'auto' !== options.allowedHosts && 'all' !== options.allowedHosts) options.allowedHosts = [
487
+ options.allowedHosts
488
+ ];
489
+ else if (Array.isArray(options.allowedHosts) && options.allowedHosts.includes('all')) options.allowedHosts = 'all';
490
+ if (void 0 === options.client || 'object' == typeof options.client && null !== options.client) {
491
+ if (!options.client) options.client = {};
492
+ if (void 0 === options.client.webSocketURL) options.client.webSocketURL = {};
493
+ else if ('string' == typeof options.client.webSocketURL) {
494
+ const parsedURL = new URL(options.client.webSocketURL);
495
+ options.client.webSocketURL = {
496
+ protocol: parsedURL.protocol,
497
+ hostname: parsedURL.hostname,
498
+ port: parsedURL.port.length > 0 ? Number(parsedURL.port) : '',
499
+ pathname: parsedURL.pathname,
500
+ username: parsedURL.username,
501
+ password: parsedURL.password
502
+ };
503
+ } else if ('string' == typeof options.client.webSocketURL.port) options.client.webSocketURL.port = Number(options.client.webSocketURL.port);
504
+ if (void 0 === options.client.overlay) options.client.overlay = true;
505
+ else if ('boolean' != typeof options.client.overlay) options.client.overlay = {
506
+ errors: true,
507
+ warnings: true,
508
+ ...options.client.overlay
509
+ };
510
+ if (void 0 === options.client.reconnect) options.client.reconnect = 10;
511
+ else if (true === options.client.reconnect) options.client.reconnect = 1 / 0;
512
+ else if (false === options.client.reconnect) options.client.reconnect = 0;
513
+ if (void 0 === options.client.logging) options.client.logging = compilerOptions.infrastructureLogging ? compilerOptions.infrastructureLogging.level : 'info';
514
+ }
515
+ if (void 0 === options.compress) options.compress = true;
516
+ if (void 0 === options.devMiddleware) options.devMiddleware = {};
517
+ if (void 0 === options.historyApiFallback) options.historyApiFallback = false;
518
+ else if ('boolean' == typeof options.historyApiFallback && options.historyApiFallback) options.historyApiFallback = {};
519
+ options.hot = 'boolean' == typeof options.hot || 'only' === options.hot ? options.hot : true;
520
+ if ('function' == typeof options.server || 'string' == typeof options.server) options.server = {
521
+ type: options.server,
522
+ options: {}
523
+ };
524
+ else {
525
+ const serverOptions = options.server || {};
526
+ options.server = {
527
+ type: serverOptions.type || 'http',
528
+ options: {
529
+ ...serverOptions.options
530
+ }
531
+ };
532
+ }
533
+ const serverOptions = options.server.options;
534
+ if ('https' === options.server.type || 'http2' === options.server.type) {
535
+ if (void 0 === serverOptions.requestCert) serverOptions.requestCert = false;
536
+ const httpsProperties = [
537
+ 'ca',
538
+ 'cert',
539
+ 'crl',
540
+ 'key',
541
+ 'pfx'
542
+ ];
543
+ for (const property of httpsProperties){
544
+ if (void 0 === serverOptions[property]) continue;
545
+ const value = serverOptions[property];
546
+ const readFile = (item)=>{
547
+ if (Buffer.isBuffer(item) || 'object' == typeof item && null !== item && !Array.isArray(item)) return item;
548
+ if (item) {
549
+ let stats = null;
550
+ try {
551
+ stats = lstatSync(realpathSync(item)).isFile();
552
+ } catch (error) {}
553
+ return stats ? readFileSync(item) : item;
554
+ }
555
+ };
556
+ serverOptions[property] = Array.isArray(value) ? value.map((item)=>readFile(item)) : readFile(value);
557
+ }
558
+ let fakeCert;
559
+ if (!serverOptions.key || !serverOptions.cert) {
560
+ const certificateDir = Server.findCacheDir();
561
+ const certificatePath = join(certificateDir, 'server.pem');
562
+ let certificateExists;
563
+ try {
564
+ const certificate = await promises.stat(certificatePath);
565
+ certificateExists = certificate.isFile();
566
+ } catch {
567
+ certificateExists = false;
568
+ }
569
+ if (certificateExists) {
570
+ const certificateTtl = 86400000;
571
+ const certificateStat = await promises.stat(certificatePath);
572
+ const now = Number(new Date());
573
+ if ((now - Number(certificateStat.ctime)) / certificateTtl > 30) {
574
+ this.logger.info('SSL certificate is more than 30 days old. Removing...');
575
+ await promises.rm(certificatePath, {
576
+ recursive: true
577
+ });
578
+ certificateExists = false;
579
+ }
580
+ }
581
+ if (!certificateExists) {
582
+ this.logger.info('Generating SSL certificate...');
583
+ let selfsigned;
584
+ try {
585
+ selfsigned = server_require('selfsigned');
586
+ } catch (error) {
587
+ if (error instanceof Error && 'MODULE_NOT_FOUND' === error.code) throw new Error('Cannot generate a self-signed certificate because optional peer dependency `selfsigned@^5.0.0` is not installed. Please install it and try again.');
588
+ throw error;
589
+ }
590
+ const attributes = [
591
+ {
592
+ name: 'commonName',
593
+ value: 'localhost'
594
+ }
595
+ ];
596
+ const notBeforeDate = new Date();
597
+ const notAfterDate = new Date(notBeforeDate);
598
+ notAfterDate.setDate(notAfterDate.getDate() + 30);
599
+ const pems = await selfsigned.generate(attributes, {
600
+ algorithm: 'sha256',
601
+ keySize: 2048,
602
+ notBeforeDate,
603
+ notAfterDate,
604
+ extensions: [
605
+ {
606
+ name: 'basicConstraints',
607
+ cA: true
608
+ },
609
+ {
610
+ name: 'keyUsage',
611
+ keyCertSign: true,
612
+ digitalSignature: true,
613
+ nonRepudiation: true,
614
+ keyEncipherment: true,
615
+ dataEncipherment: true
616
+ },
617
+ {
618
+ name: 'extKeyUsage',
619
+ serverAuth: true,
620
+ clientAuth: true,
621
+ codeSigning: true,
622
+ timeStamping: true
623
+ },
624
+ {
625
+ name: 'subjectAltName',
626
+ altNames: [
627
+ {
628
+ type: 2,
629
+ value: 'localhost'
630
+ },
631
+ {
632
+ type: 2,
633
+ value: 'localhost.localdomain'
634
+ },
635
+ {
636
+ type: 2,
637
+ value: 'lvh.me'
638
+ },
639
+ {
640
+ type: 2,
641
+ value: '*.lvh.me'
642
+ },
643
+ {
644
+ type: 2,
645
+ value: '[::1]'
646
+ },
647
+ {
648
+ type: 7,
649
+ ip: '127.0.0.1'
650
+ },
651
+ {
652
+ type: 7,
653
+ ip: 'fe80::1'
654
+ }
655
+ ]
656
+ }
657
+ ]
658
+ });
659
+ await promises.mkdir(certificateDir, {
660
+ recursive: true
661
+ });
662
+ await promises.writeFile(certificatePath, pems.private + pems.cert, {
663
+ encoding: 'utf8'
664
+ });
665
+ }
666
+ fakeCert = await promises.readFile(certificatePath);
667
+ this.logger.info(`SSL certificate: ${certificatePath}`);
668
+ }
669
+ serverOptions.key = serverOptions.key || fakeCert;
670
+ serverOptions.cert = serverOptions.cert || fakeCert;
671
+ }
672
+ if ('boolean' == typeof options.ipc) {
673
+ const isWindows = 'win32' === process.platform;
674
+ const pipePrefix = isWindows ? '\\\\.\\pipe\\' : tmpdir();
675
+ const pipeName = 'webpack-dev-server.sock';
676
+ options.ipc = join(pipePrefix, pipeName);
677
+ }
678
+ options.liveReload = void 0 !== options.liveReload ? options.liveReload : true;
679
+ const defaultOpenOptions = {
680
+ wait: false
681
+ };
682
+ const getOpenItemsFromObject = ({ target, ...rest })=>{
683
+ const normalizedOptions = {
684
+ ...defaultOpenOptions,
685
+ ...rest
686
+ };
687
+ if ('string' == typeof normalizedOptions.app) normalizedOptions.app = {
688
+ name: normalizedOptions.app
689
+ };
690
+ const normalizedTarget = void 0 === target ? '<url>' : target;
691
+ if (Array.isArray(normalizedTarget)) return normalizedTarget.map((singleTarget)=>({
692
+ target: singleTarget,
693
+ options: normalizedOptions
694
+ }));
695
+ return [
696
+ {
697
+ target: normalizedTarget,
698
+ options: normalizedOptions
699
+ }
700
+ ];
701
+ };
702
+ let normalizedOpens = [];
703
+ if (void 0 === options.open) ;
704
+ else if ('boolean' == typeof options.open) {
705
+ if (options.open) normalizedOpens = [
706
+ {
707
+ target: '<url>',
708
+ options: defaultOpenOptions
709
+ }
710
+ ];
711
+ } else if ('string' == typeof options.open) normalizedOpens = [
712
+ {
713
+ target: options.open,
714
+ options: defaultOpenOptions
715
+ }
716
+ ];
717
+ else if (Array.isArray(options.open)) for (const item of options.open){
718
+ if ('string' == typeof item) {
719
+ normalizedOpens.push({
720
+ target: item,
721
+ options: defaultOpenOptions
722
+ });
723
+ continue;
724
+ }
725
+ normalizedOpens.push(...getOpenItemsFromObject(item));
726
+ }
727
+ else normalizedOpens = [
728
+ ...getOpenItemsFromObject(options.open)
729
+ ];
730
+ options.open = normalizedOpens;
731
+ if ('string' == typeof options.port && 'auto' !== options.port) options.port = Number(options.port);
732
+ if (void 0 === options.setupExitSignals) options.setupExitSignals = true;
733
+ if (void 0 === options.static) options.static = [
734
+ getStaticItem()
735
+ ];
736
+ else if ('boolean' == typeof options.static) options.static = options.static ? [
737
+ getStaticItem()
738
+ ] : false;
739
+ else if ('string' == typeof options.static) options.static = [
740
+ getStaticItem(options.static)
741
+ ];
742
+ else if (Array.isArray(options.static)) options.static = options.static.map((item)=>getStaticItem(item));
743
+ else options.static = [
744
+ getStaticItem(options.static)
745
+ ];
746
+ if ('string' == typeof options.watchFiles) options.watchFiles = [
747
+ {
748
+ paths: options.watchFiles,
749
+ options: getWatchOptions()
750
+ }
751
+ ];
752
+ else if ('object' != typeof options.watchFiles || null === options.watchFiles || Array.isArray(options.watchFiles)) if (Array.isArray(options.watchFiles)) options.watchFiles = options.watchFiles.map((item)=>{
753
+ if ('string' == typeof item) return {
754
+ paths: item,
755
+ options: getWatchOptions()
756
+ };
757
+ return {
758
+ paths: item.paths,
759
+ options: getWatchOptions(item.options || {})
760
+ };
761
+ });
762
+ else options.watchFiles = [];
763
+ else options.watchFiles = [
764
+ {
765
+ paths: options.watchFiles.paths,
766
+ options: getWatchOptions(options.watchFiles.options || {})
767
+ }
768
+ ];
769
+ const defaultWebSocketServerType = 'ws';
770
+ const defaultWebSocketServerOptions = {
771
+ path: '/ws'
772
+ };
773
+ if (void 0 === options.webSocketServer) options.webSocketServer = {
774
+ type: defaultWebSocketServerType,
775
+ options: defaultWebSocketServerOptions
776
+ };
777
+ else if ('boolean' != typeof options.webSocketServer || options.webSocketServer) if ('string' == typeof options.webSocketServer || 'function' == typeof options.webSocketServer) options.webSocketServer = {
778
+ type: options.webSocketServer,
779
+ options: defaultWebSocketServerOptions
780
+ };
781
+ else {
782
+ options.webSocketServer = {
783
+ type: options.webSocketServer.type || defaultWebSocketServerType,
784
+ options: {
785
+ ...defaultWebSocketServerOptions,
786
+ ...options.webSocketServer.options
787
+ }
788
+ };
789
+ const webSocketServer = options.webSocketServer;
790
+ if ('string' == typeof webSocketServer.options.port) webSocketServer.options.port = Number(webSocketServer.options.port);
791
+ }
792
+ else options.webSocketServer = false;
793
+ }
794
+ #getClientTransport() {
795
+ let clientImplementation;
796
+ let clientImplementationFound = true;
797
+ const isKnownWebSocketServerImplementation = this.options.webSocketServer && 'string' == typeof this.options.webSocketServer.type && 'ws' === this.options.webSocketServer.type;
798
+ let clientTransport;
799
+ clientTransport = this.options.client ? void 0 !== this.options.client.webSocketTransport ? this.options.client.webSocketTransport : isKnownWebSocketServerImplementation ? this.options.webSocketServer.type : 'ws' : 'ws';
800
+ switch(typeof clientTransport){
801
+ case 'string':
802
+ if ('sockjs' === clientTransport) throw new Error("SockJS support has been removed. Please set client.webSocketTransport to 'ws' or provide a custom transport implementation path.");
803
+ if ('ws' === clientTransport) clientImplementation = server_require.resolve('../client/clients/WebSocketClient');
804
+ else try {
805
+ clientImplementation = server_require.resolve(clientTransport);
806
+ } catch {
807
+ clientImplementationFound = false;
808
+ }
809
+ break;
810
+ default:
811
+ clientImplementationFound = false;
812
+ }
813
+ if (!clientImplementationFound) throw new Error(`${!isKnownWebSocketServerImplementation ? 'When you use custom web socket implementation you must explicitly specify client.webSocketTransport. ' : ''}client.webSocketTransport must be a string denoting a default implementation (e.g. 'ws') or a full path to a JS file via require.resolve(...) which exports a class `);
814
+ return clientImplementation;
815
+ }
816
+ #getServerTransport() {
817
+ let implementation;
818
+ let implementationFound = true;
819
+ switch(typeof this.options.webSocketServer.type){
820
+ case 'string':
821
+ if ('sockjs' === this.options.webSocketServer.type) throw new Error("SockJS support has been removed. Please set webSocketServer to 'ws' or provide a custom WebSocket server implementation.");
822
+ if ('ws' === this.options.webSocketServer.type) implementation = WebsocketServer;
823
+ else try {
824
+ implementation = server_require(this.options.webSocketServer.type);
825
+ } catch {
826
+ implementationFound = false;
827
+ }
828
+ break;
829
+ case 'function':
830
+ implementation = this.options.webSocketServer.type;
831
+ break;
832
+ default:
833
+ implementationFound = false;
834
+ }
835
+ if (!implementationFound) throw new Error("webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws'), a full path to a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) via require.resolve(...), or the class itself which extends BaseServer");
836
+ return implementation;
837
+ }
838
+ getClientEntry() {
839
+ return server_require.resolve('@rspack/dev-server/client/index');
840
+ }
841
+ getClientHotEntry() {
842
+ if ('only' === this.options.hot) return server_require.resolve('@rspack/core/hot/only-dev-server');
843
+ if (this.options.hot) return server_require.resolve('@rspack/core/hot/dev-server');
844
+ }
845
+ #setupProgressPlugin() {
846
+ const { ProgressPlugin } = this.compiler.compilers ? this.compiler.compilers[0].webpack : this.compiler.webpack;
847
+ new ProgressPlugin((percent, msg)=>{
848
+ const percentValue = Math.floor(100 * percent);
849
+ let msgValue = msg;
850
+ if (100 === percentValue) msgValue = 'Compilation completed';
851
+ const payload = {
852
+ percent: percentValue,
853
+ msg: msgValue
854
+ };
855
+ if (this.webSocketServer) this.sendMessage(this.webSocketServer.clients, 'progress-update', payload);
856
+ if (this.server) this.server.emit('progress-update', payload);
857
+ }).apply(this.compiler);
858
+ }
859
+ async #initialize() {
860
+ const compilers = isMultiCompiler(this.compiler) ? this.compiler.compilers : [
861
+ this.compiler
862
+ ];
863
+ for (const compiler of compilers){
864
+ const mode = compiler.options.mode || process.env.NODE_ENV;
865
+ if (this.options.hot) {
866
+ if ('production' === mode) this.logger.warn("Hot Module Replacement (HMR) is enabled for the production build. \nMake sure to disable HMR for production by setting `devServer.hot` to `false` in the configuration.");
867
+ compiler.options.resolve.alias = {
868
+ 'ansi-html-community': server_require.resolve('@rspack/dev-server/client/utils/ansiHTML'),
869
+ ...compiler.options.resolve.alias
870
+ };
871
+ }
872
+ }
873
+ this.#setupHooks();
874
+ await this.#setupApp();
875
+ await this.#createServer();
876
+ if (this.options.webSocketServer) {
877
+ const compilers = this.compiler.compilers || [
878
+ this.compiler
879
+ ];
880
+ for (const compiler of compilers){
881
+ if (false === compiler.options.devServer) continue;
882
+ this.#addAdditionalEntries(compiler);
883
+ const { ProvidePlugin, HotModuleReplacementPlugin } = compiler.rspack;
884
+ new ProvidePlugin({
885
+ __rspack_dev_server_client__: this.#getClientTransport()
886
+ }).apply(compiler);
887
+ if (this.options.hot) {
888
+ const HMRPluginExists = compiler.options.plugins.find((plugin)=>plugin && plugin.constructor === HotModuleReplacementPlugin);
889
+ if (HMRPluginExists) this.logger.warn('"hot: true" automatically applies HMR plugin, you don\'t have to add it manually to your webpack configuration.');
890
+ else {
891
+ const plugin = new HotModuleReplacementPlugin();
892
+ plugin.apply(compiler);
893
+ }
894
+ }
895
+ }
896
+ if (this.options.client && this.options.client.progress) this.#setupProgressPlugin();
897
+ }
898
+ await this.#setupWatchFiles();
899
+ await this.#setupWatchStaticFiles();
900
+ await this.#setupMiddlewares();
901
+ if (this.options.setupExitSignals) {
902
+ const signals = [
903
+ 'SIGINT',
904
+ 'SIGTERM'
905
+ ];
906
+ let needForceShutdown = false;
907
+ for (const signal of signals){
908
+ const listener = ()=>{
909
+ if (needForceShutdown) process.exit();
910
+ this.logger.info('Gracefully shutting down. Press ^C again to force exit...');
911
+ needForceShutdown = true;
912
+ this.stopCallback(()=>{
913
+ if ('function' == typeof this.compiler.close) this.compiler.close(()=>{
914
+ process.exit();
915
+ });
916
+ else process.exit();
917
+ });
918
+ };
919
+ this.listeners.push({
920
+ name: signal,
921
+ listener
922
+ });
923
+ process.on(signal, listener);
924
+ }
925
+ }
926
+ const webSocketProxies = this.webSocketProxies;
927
+ for (const webSocketProxy of webSocketProxies)this.server.on('upgrade', webSocketProxy.upgrade);
928
+ }
929
+ async #setupApp() {
930
+ this.app = 'function' == typeof this.options.app ? await this.options.app() : (await getConnect())();
931
+ }
932
+ #getStats(statsObj) {
933
+ const stats = Server.DEFAULT_STATS;
934
+ const compilerOptions = this.#getCompilerOptions();
935
+ if (compilerOptions.stats && compilerOptions.stats.warningsFilter) stats.warningsFilter = compilerOptions.stats.warningsFilter;
936
+ return statsObj.toJson(stats);
937
+ }
938
+ #setupHooks() {
939
+ this.compiler.hooks.invalid.tap('rspack-dev-server', ()=>{
940
+ if (this.webSocketServer) this.sendMessage(this.webSocketServer.clients, 'invalid');
941
+ });
942
+ this.compiler.hooks.done.tap('rspack-dev-server', (stats)=>{
943
+ if (this.webSocketServer) this.#sendStats(this.webSocketServer.clients, this.#getStats(stats));
944
+ this.stats = stats;
945
+ });
946
+ }
947
+ async #setupWatchStaticFiles() {
948
+ const watchFiles = this.options.static;
949
+ if (watchFiles.length > 0) {
950
+ for (const item of watchFiles)if (item.watch) await this.watchFiles(item.directory, item.watch);
951
+ }
952
+ }
953
+ async #setupWatchFiles() {
954
+ const watchFiles = this.options.watchFiles;
955
+ if (watchFiles.length > 0) for (const item of watchFiles)await this.watchFiles(item.paths, item.options);
956
+ }
957
+ async #setupMiddlewares() {
958
+ let middlewares = [];
959
+ middlewares.push({
960
+ name: 'host-header-check',
961
+ middleware: (req, res, next)=>{
962
+ const headers = req.headers;
963
+ const headerName = headers[':authority'] ? ':authority' : 'host';
964
+ if (this.isValidHost(headers, headerName)) return void next();
965
+ res.statusCode = 403;
966
+ res.end('Invalid Host header');
967
+ }
968
+ });
969
+ middlewares.push({
970
+ name: 'cross-origin-header-check',
971
+ middleware: (req, res, next)=>{
972
+ const headers = req.headers;
973
+ const headerName = headers[':authority'] ? ':authority' : 'host';
974
+ if (this.isValidHost(headers, headerName, false)) return void next();
975
+ if ('no-cors' === headers['sec-fetch-mode'] && 'cross-site' === headers['sec-fetch-site']) {
976
+ res.statusCode = 403;
977
+ res.end('Cross-Origin request blocked');
978
+ return;
979
+ }
980
+ next();
981
+ }
982
+ });
983
+ const isHTTP2 = 'http2' === this.options.server.type;
984
+ if (isHTTP2) middlewares.push({
985
+ name: 'http2-status-message-patch',
986
+ middleware: (_req, res, next)=>{
987
+ Object.defineProperty(res, 'statusMessage', {
988
+ get () {
989
+ return '';
990
+ },
991
+ set () {}
992
+ });
993
+ next();
994
+ }
995
+ });
996
+ if (this.options.compress) middlewares.push({
997
+ name: 'compression',
998
+ middleware: src_default()()
999
+ });
1000
+ if (void 0 !== this.options.headers) middlewares.push({
1001
+ name: 'set-headers',
1002
+ middleware: this.#setHeaders.bind(this)
1003
+ });
1004
+ middlewares.push({
1005
+ name: 'webpack-dev-middleware',
1006
+ middleware: this.middleware
1007
+ });
1008
+ middlewares.push({
1009
+ name: 'rspack-dev-server-invalidate',
1010
+ path: '/rspack-dev-server/invalidate',
1011
+ middleware: (req, res, next)=>{
1012
+ if ('GET' !== req.method && 'HEAD' !== req.method) return void next();
1013
+ this.invalidate();
1014
+ res.end();
1015
+ }
1016
+ });
1017
+ middlewares.push({
1018
+ name: 'rspack-dev-server-open-editor',
1019
+ path: '/rspack-dev-server/open-editor',
1020
+ middleware: async (req, res, next)=>{
1021
+ if ('GET' !== req.method && 'HEAD' !== req.method) return void next();
1022
+ if (!req.url) return void next();
1023
+ const resolveUrl = new URL(req.url, `http://${req.headers.host}`);
1024
+ const params = new URLSearchParams(resolveUrl.search);
1025
+ const fileName = params.get('fileName');
1026
+ if ('string' == typeof fileName) {
1027
+ const { default: launchEditor } = await import("./0~launch-editor.js").then(__webpack_require__.t.bind(__webpack_require__, "./node_modules/.pnpm/launch-editor@2.13.1/node_modules/launch-editor/index.js", 23));
1028
+ launchEditor(fileName);
1029
+ }
1030
+ res.end();
1031
+ }
1032
+ });
1033
+ middlewares.push({
1034
+ name: 'rspack-dev-server-assets',
1035
+ path: '/rspack-dev-server',
1036
+ middleware: (req, res, next)=>{
1037
+ if ('GET' !== req.method && 'HEAD' !== req.method) return void next();
1038
+ if (!this.middleware) return void next();
1039
+ this.middleware.waitUntilValid((stats)=>{
1040
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
1041
+ if ('HEAD' === req.method) return void res.end();
1042
+ res.write('<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>');
1043
+ const statsForPrint = void 0 !== stats.stats ? stats.toJson({
1044
+ assets: true
1045
+ }).children : [
1046
+ stats.toJson({
1047
+ assets: true
1048
+ })
1049
+ ];
1050
+ res.write('<h1>Assets Report:</h1>');
1051
+ for (const [index, item] of statsForPrint?.entries() ?? []){
1052
+ res.write('<div>');
1053
+ const name = void 0 !== item.name ? item.name : stats.stats ? `unnamed[${index}]` : 'unnamed';
1054
+ res.write(`<h2>Compilation: ${name}</h2>`);
1055
+ res.write('<ul>');
1056
+ const publicPath = 'auto' === item.publicPath ? '' : item.publicPath;
1057
+ const assets = item.assets;
1058
+ for (const asset of assets ?? []){
1059
+ const assetName = asset.name;
1060
+ const assetURL = `${publicPath}${assetName}`;
1061
+ res.write(`<li>
1062
+ <strong><a href="${assetURL}" target="_blank">${assetName}</a></strong>
1063
+ </li>`);
1064
+ }
1065
+ res.write('</ul>');
1066
+ res.write('</div>');
1067
+ }
1068
+ res.end('</body></html>');
1069
+ });
1070
+ }
1071
+ });
1072
+ if (this.options.proxy) {
1073
+ const { createProxyMiddleware } = server_require('http-proxy-middleware');
1074
+ const getProxyMiddleware = (proxyConfig)=>{
1075
+ const { context, ...proxyOptions } = proxyConfig;
1076
+ const pathFilter = proxyOptions.pathFilter ?? context;
1077
+ if (void 0 !== pathFilter) proxyOptions.pathFilter = pathFilter;
1078
+ if (void 0 === proxyOptions.logger) proxyOptions.logger = this.logger;
1079
+ if (proxyOptions.target || proxyOptions.router) return createProxyMiddleware(proxyOptions);
1080
+ deprecate(()=>{}, `Invalid proxy configuration:\n\n${JSON.stringify(proxyConfig, null, 2)}\n\nThe use of proxy object notation as proxy routes has been removed.\nPlease use the 'router' or 'context' options. Read more at https://github.com/chimurai/http-proxy-middleware`, 'DEP_WEBPACK_DEV_SERVER_PROXY_ROUTES_ARGUMENT')();
1081
+ };
1082
+ for (const proxyConfigOrCallback of this.options.proxy){
1083
+ let proxyMiddleware;
1084
+ let proxyConfig = 'function' == typeof proxyConfigOrCallback ? proxyConfigOrCallback() : proxyConfigOrCallback;
1085
+ proxyMiddleware = getProxyMiddleware(proxyConfig);
1086
+ if (proxyConfig.ws && proxyMiddleware) this.webSocketProxies.push(proxyMiddleware);
1087
+ const handler = async (req, res, next)=>{
1088
+ if ('function' == typeof proxyConfigOrCallback) {
1089
+ const newProxyConfig = proxyConfigOrCallback(req, res, next);
1090
+ if (newProxyConfig !== proxyConfig) {
1091
+ proxyConfig = newProxyConfig;
1092
+ const socket = req.socket || req.connection;
1093
+ const server = socket ? socket.server : null;
1094
+ if (server) server.removeAllListeners('close');
1095
+ proxyMiddleware = getProxyMiddleware(proxyConfig);
1096
+ }
1097
+ }
1098
+ if (proxyMiddleware) return proxyMiddleware(req, res, next);
1099
+ next();
1100
+ };
1101
+ middlewares.push({
1102
+ name: 'http-proxy-middleware',
1103
+ middleware: handler
1104
+ });
1105
+ middlewares.push({
1106
+ name: 'http-proxy-middleware-error-handler',
1107
+ middleware: (error, req, res, next)=>handler(req, res, next)
1108
+ });
1109
+ }
1110
+ middlewares.push({
1111
+ name: 'webpack-dev-middleware',
1112
+ middleware: this.middleware
1113
+ });
1114
+ }
1115
+ const staticOptions = this.options.static;
1116
+ if (staticOptions.length > 0) for (const staticOption of staticOptions)for (const publicPath of staticOption.publicPath)middlewares.push({
1117
+ name: 'serve-static',
1118
+ path: publicPath,
1119
+ middleware: getServeStatic()(staticOption.directory, staticOption.staticOptions)
1120
+ });
1121
+ if (this.options.historyApiFallback) {
1122
+ const connectHistoryApiFallback = server_require('connect-history-api-fallback');
1123
+ const { historyApiFallback } = this.options;
1124
+ if (void 0 === historyApiFallback && !historyApiFallback.verbose) historyApiFallback.logger = this.logger.log.bind(this.logger, '[connect-history-api-fallback]');
1125
+ middlewares.push({
1126
+ name: 'connect-history-api-fallback',
1127
+ middleware: connectHistoryApiFallback(historyApiFallback)
1128
+ });
1129
+ middlewares.push({
1130
+ name: 'webpack-dev-middleware',
1131
+ middleware: this.middleware
1132
+ });
1133
+ if (staticOptions.length > 0) for (const staticOption of staticOptions)for (const publicPath of staticOption.publicPath)middlewares.push({
1134
+ name: 'serve-static',
1135
+ path: publicPath,
1136
+ middleware: getServeStatic()(staticOption.directory, staticOption.staticOptions)
1137
+ });
1138
+ }
1139
+ middlewares.push({
1140
+ name: 'options-middleware',
1141
+ middleware: (req, res, next)=>{
1142
+ if ('OPTIONS' === req.method) {
1143
+ res.statusCode = 204;
1144
+ res.setHeader('Content-Length', '0');
1145
+ res.end();
1146
+ return;
1147
+ }
1148
+ next();
1149
+ }
1150
+ });
1151
+ if ('function' == typeof this.options.setupMiddlewares) middlewares = this.options.setupMiddlewares(middlewares, this);
1152
+ const lazyInitDevMiddleware = ()=>{
1153
+ if (!this.middleware) {
1154
+ const webpackDevMiddleware = server_require('webpack-dev-middleware');
1155
+ this.middleware = webpackDevMiddleware(this.compiler, this.options.devMiddleware);
1156
+ }
1157
+ return this.middleware;
1158
+ };
1159
+ for (const i of middlewares)if ('webpack-dev-middleware' === i.name) {
1160
+ const item = i;
1161
+ if (void 0 === item.middleware) item.middleware = lazyInitDevMiddleware();
1162
+ }
1163
+ for (const middleware of middlewares)if ('function' == typeof middleware) this.app.use(middleware);
1164
+ else if (void 0 !== middleware.path) this.app.use(middleware.path, middleware.middleware);
1165
+ else this.app.use(middleware.middleware);
1166
+ }
1167
+ async #createServer() {
1168
+ const { type, options } = this.options.server;
1169
+ if ('function' == typeof type) this.server = await type(options, this.app);
1170
+ else {
1171
+ const serverType = server_require(type);
1172
+ this.server = 'http2' === type ? serverType.createSecureServer({
1173
+ ...options,
1174
+ allowHTTP1: true
1175
+ }, this.app) : serverType.createServer(options, this.app);
1176
+ }
1177
+ this.isTlsServer = void 0 !== this.server.setSecureContext;
1178
+ this.server.on('connection', (socket)=>{
1179
+ this.sockets.push(socket);
1180
+ socket.once('close', ()=>{
1181
+ this.sockets.splice(this.sockets.indexOf(socket), 1);
1182
+ });
1183
+ });
1184
+ this.server.on('error', (error)=>{
1185
+ throw error;
1186
+ });
1187
+ }
1188
+ #createWebSocketServer() {
1189
+ this.webSocketServer = new (this.#getServerTransport())(this);
1190
+ (this.webSocketServer?.implementation).on('connection', (client, request)=>{
1191
+ const headers = void 0 !== request ? request.headers : void 0;
1192
+ if (!headers) this.logger.warn('webSocketServer implementation must pass headers for the "connection" event');
1193
+ if (!headers || !this.isValidHost(headers, 'host') || !this.isValidHost(headers, 'origin') || !this.#isSameOrigin(headers)) {
1194
+ this.sendMessage([
1195
+ client
1196
+ ], 'error', 'Invalid Host/Origin header');
1197
+ client.close();
1198
+ return;
1199
+ }
1200
+ if (true === this.options.hot || 'only' === this.options.hot) this.sendMessage([
1201
+ client
1202
+ ], 'hot');
1203
+ if (this.options.liveReload) this.sendMessage([
1204
+ client
1205
+ ], 'liveReload');
1206
+ if (this.options.client && this.options.client.progress) this.sendMessage([
1207
+ client
1208
+ ], 'progress', this.options.client.progress);
1209
+ if (this.options.client && this.options.client.reconnect) this.sendMessage([
1210
+ client
1211
+ ], 'reconnect', this.options.client.reconnect);
1212
+ if (this.options.client && this.options.client.overlay) {
1213
+ const overlayConfig = this.options.client.overlay;
1214
+ this.sendMessage([
1215
+ client
1216
+ ], 'overlay', 'object' == typeof overlayConfig ? {
1217
+ ...overlayConfig,
1218
+ errors: overlayConfig.errors && encodeOverlaySettings(overlayConfig.errors),
1219
+ warnings: overlayConfig.warnings && encodeOverlaySettings(overlayConfig.warnings),
1220
+ runtimeErrors: overlayConfig.runtimeErrors && encodeOverlaySettings(overlayConfig.runtimeErrors)
1221
+ } : overlayConfig);
1222
+ }
1223
+ if (!this.stats) return;
1224
+ this.#sendStats([
1225
+ client
1226
+ ], this.#getStats(this.stats), true);
1227
+ });
1228
+ }
1229
+ async #openBrowser(defaultOpenTarget) {
1230
+ const { default: open } = await import("./0~open.js");
1231
+ Promise.all(this.options.open.map((item)=>{
1232
+ let openTarget;
1233
+ openTarget = '<url>' === item.target ? defaultOpenTarget : Server.isAbsoluteURL(item.target) ? item.target : new URL(item.target, defaultOpenTarget).toString();
1234
+ return open(openTarget, item.options).catch(()=>{
1235
+ const app = item.options.app;
1236
+ this.logger.warn(`Unable to open "${openTarget}" page${app ? ` in "${app.name}" app${app.arguments ? ` with "${app.arguments.join(' ')}" arguments` : ''}` : ''}. If you are running in a headless environment, please do not use the "open" option or related flags like "--open", "--open-target", and "--open-app-name".`);
1237
+ });
1238
+ }));
1239
+ }
1240
+ async #logStatus() {
1241
+ const server = this.server;
1242
+ if (this.options.ipc) this.logger.info(`Project is running at: "${server?.address()}"`);
1243
+ else {
1244
+ const protocol = this.isTlsServer ? 'https' : 'http';
1245
+ const addressInfo = server?.address();
1246
+ if (!addressInfo) return;
1247
+ const { address, port } = addressInfo;
1248
+ const prettyPrintURL = (newHostname)=>format({
1249
+ protocol,
1250
+ hostname: newHostname,
1251
+ port,
1252
+ pathname: '/'
1253
+ });
1254
+ let localhost;
1255
+ let loopbackIPv4;
1256
+ let loopbackIPv6;
1257
+ let networkUrlIPv4;
1258
+ let networkUrlIPv6;
1259
+ if ('localhost' === this.options.host) localhost = prettyPrintURL('localhost');
1260
+ const parsedIP = ipaddr.parse(address);
1261
+ if ('unspecified' === parsedIP.range()) {
1262
+ localhost = prettyPrintURL('localhost');
1263
+ loopbackIPv6 = prettyPrintURL('::1');
1264
+ const networkIPv4 = Server.findIp('v4', false);
1265
+ if (networkIPv4) networkUrlIPv4 = prettyPrintURL(networkIPv4);
1266
+ const networkIPv6 = Server.findIp('v6', false);
1267
+ if (networkIPv6) networkUrlIPv6 = prettyPrintURL(networkIPv6);
1268
+ } else if ('loopback' === parsedIP.range()) {
1269
+ if ('ipv4' === parsedIP.kind()) loopbackIPv4 = prettyPrintURL(parsedIP.toString());
1270
+ else if ('ipv6' === parsedIP.kind()) loopbackIPv6 = prettyPrintURL(parsedIP.toString());
1271
+ } else {
1272
+ networkUrlIPv4 = 'ipv6' === parsedIP.kind() && parsedIP.isIPv4MappedAddress() ? prettyPrintURL(parsedIP.toIPv4Address().toString()) : prettyPrintURL(address);
1273
+ if ('ipv6' === parsedIP.kind()) networkUrlIPv6 = prettyPrintURL(address);
1274
+ }
1275
+ const urlLogs = [];
1276
+ const local = localhost || loopbackIPv4 || loopbackIPv6;
1277
+ if (local) urlLogs.push(` ${server_styleText('white', '➜')} ${server_styleText([
1278
+ 'white',
1279
+ 'dim'
1280
+ ], 'Local:')} ${server_styleText('cyan', local)}`);
1281
+ if (networkUrlIPv4) urlLogs.push(` ${server_styleText('white', '➜')} ${server_styleText([
1282
+ 'white',
1283
+ 'dim'
1284
+ ], 'Network:')} ${server_styleText('cyan', networkUrlIPv4)}`);
1285
+ else if (networkUrlIPv6) urlLogs.push(` ${server_styleText('white', '➜')} ${server_styleText([
1286
+ 'white',
1287
+ 'dim'
1288
+ ], 'Network:')} ${server_styleText('cyan', networkUrlIPv6)}`);
1289
+ if (urlLogs.length && this.#shouldLogInfrastructureInfo()) console.log(`${urlLogs.join('\n')}\n`);
1290
+ if (this.options.open?.length > 0) {
1291
+ const openTarget = prettyPrintURL(this.options.host && '0.0.0.0' !== this.options.host && '::' !== this.options.host ? this.options.host : 'localhost');
1292
+ await this.#openBrowser(openTarget);
1293
+ }
1294
+ }
1295
+ }
1296
+ #setHeaders(req, res, next) {
1297
+ let { headers } = this.options;
1298
+ if (headers) {
1299
+ if ('function' == typeof headers) headers = headers(req, res, this.middleware ? this.middleware.context : void 0);
1300
+ const allHeaders = [];
1301
+ if (!Array.isArray(headers)) {
1302
+ for(const name in headers)allHeaders.push({
1303
+ key: name,
1304
+ value: headers[name]
1305
+ });
1306
+ headers = allHeaders;
1307
+ }
1308
+ for (const { key, value } of headers)res.setHeader(key, value);
1309
+ }
1310
+ next();
1311
+ }
1312
+ #isHostAllowed(value) {
1313
+ const { allowedHosts } = this.options;
1314
+ if ('all' === allowedHosts) return true;
1315
+ if (Array.isArray(allowedHosts) && allowedHosts.length > 0) for (const allowedHost of allowedHosts){
1316
+ if (allowedHost === value) return true;
1317
+ if (allowedHost.startsWith('.') && (value === allowedHost.slice(1) || value.endsWith(allowedHost))) return true;
1318
+ }
1319
+ if (this.options.client && void 0 !== this.options.client.webSocketURL) return this.options.client.webSocketURL === value;
1320
+ return false;
1321
+ }
1322
+ isValidHost(headers, headerToCheck, validateHost = true) {
1323
+ if ('all' === this.options.allowedHosts) return true;
1324
+ const header = headers[headerToCheck];
1325
+ if (!header) return false;
1326
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(header)) return true;
1327
+ const hostname = parseHostnameFromHeader(header);
1328
+ if (null === hostname) return false;
1329
+ if (this.#isHostAllowed(hostname)) return true;
1330
+ const isValidHostname = validateHost ? ipaddr.IPv4.isValid(hostname) || ipaddr.IPv6.isValid(hostname) || 'localhost' === hostname || hostname.endsWith('.localhost') || hostname === this.options.host : false;
1331
+ return isValidHostname;
1332
+ }
1333
+ #isSameOrigin(headers) {
1334
+ if ('all' === this.options.allowedHosts) return true;
1335
+ const originHeader = headers.origin;
1336
+ if (!originHeader) return 'all' === this.options.allowedHosts;
1337
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(originHeader)) return true;
1338
+ const origin = parseHostnameFromHeader(originHeader);
1339
+ if (null === origin) return false;
1340
+ if (this.#isHostAllowed(origin)) return true;
1341
+ const hostHeader = headers.host;
1342
+ if (!hostHeader) return 'all' === this.options.allowedHosts;
1343
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(hostHeader)) return true;
1344
+ const host = parseHostnameFromHeader(hostHeader);
1345
+ if (null === host) return false;
1346
+ if (this.#isHostAllowed(host)) return true;
1347
+ return origin === host;
1348
+ }
1349
+ sendMessage(clients, type, data, params) {
1350
+ for (const client of clients)if (1 === client.readyState) client.send(JSON.stringify({
1351
+ type,
1352
+ data,
1353
+ params
1354
+ }));
1355
+ }
1356
+ #sendStats(clients, stats, force) {
1357
+ if (!stats) return;
1358
+ const shouldEmit = !force && stats && (!stats.errors || 0 === stats.errors.length) && (!stats.warnings || 0 === stats.warnings.length) && this.currentHash === stats.hash;
1359
+ if (shouldEmit) return void this.sendMessage(clients, 'still-ok');
1360
+ this.currentHash = stats.hash;
1361
+ this.sendMessage(clients, 'hash', stats.hash);
1362
+ if (stats.errors?.length > 0 || stats.warnings?.length > 0) {
1363
+ const hasErrors = stats.errors?.length > 0;
1364
+ if (stats.warnings?.length > 0) {
1365
+ let params;
1366
+ if (hasErrors) params = {
1367
+ preventReloading: true
1368
+ };
1369
+ this.sendMessage(clients, 'warnings', stats.warnings, params);
1370
+ }
1371
+ if (stats.errors?.length > 0) this.sendMessage(clients, 'errors', stats.errors);
1372
+ } else this.sendMessage(clients, 'ok');
1373
+ }
1374
+ async watchFiles(watchPath, watchOptions) {
1375
+ const { watch } = await getChokidar();
1376
+ const watcher = watch(watchPath, watchOptions);
1377
+ if (this.options.liveReload) watcher.on('change', (item)=>{
1378
+ if (this.webSocketServer) this.sendMessage(this.webSocketServer.clients, 'static-changed', item);
1379
+ });
1380
+ this.staticWatchers.push(watcher);
1381
+ }
1382
+ invalidate(callback = ()=>{}) {
1383
+ if (this.middleware) this.middleware.invalidate(callback);
1384
+ }
1385
+ async start() {
1386
+ await this.#normalizeOptions();
1387
+ if (this.options.ipc) await new Promise((resolve, reject)=>{
1388
+ const net = server_require('node:net');
1389
+ const socket = new net.Socket();
1390
+ socket.on('error', (error)=>{
1391
+ if ('ECONNREFUSED' === error.code) {
1392
+ unlinkSync(this.options.ipc);
1393
+ resolve();
1394
+ return;
1395
+ }
1396
+ if ('ENOENT' === error.code) return void resolve();
1397
+ reject(error);
1398
+ });
1399
+ socket.connect({
1400
+ path: this.options.ipc
1401
+ }, ()=>{
1402
+ throw new Error(`IPC "${this.options.ipc}" is already used`);
1403
+ });
1404
+ });
1405
+ else {
1406
+ this.options.host = await Server.getHostname(this.options.host);
1407
+ this.options.port = await Server.getFreePort(this.options.port, this.options.host);
1408
+ }
1409
+ await this.#initialize();
1410
+ const listenOptions = this.options.ipc ? {
1411
+ path: this.options.ipc
1412
+ } : {
1413
+ host: this.options.host,
1414
+ port: this.options.port
1415
+ };
1416
+ await new Promise((resolve)=>{
1417
+ this.server.listen(listenOptions, ()=>{
1418
+ resolve();
1419
+ });
1420
+ });
1421
+ if (this.options.ipc) {
1422
+ const READ_WRITE = 438;
1423
+ await promises.chmod(this.options.ipc, READ_WRITE);
1424
+ }
1425
+ if (this.options.webSocketServer) this.#createWebSocketServer();
1426
+ await this.#logStatus();
1427
+ if ('function' == typeof this.options.onListening) this.options.onListening(this);
1428
+ }
1429
+ startCallback(callback = ()=>{}) {
1430
+ this.start().then(()=>callback(), callback).catch(callback);
1431
+ }
1432
+ async stop() {
1433
+ this.webSocketProxies = [];
1434
+ await Promise.all(this.staticWatchers.map((watcher)=>watcher.close()));
1435
+ this.staticWatchers = [];
1436
+ if (this.webSocketServer) await new Promise((resolve)=>{
1437
+ this.webSocketServer.implementation.close(()=>{
1438
+ this.webSocketServer = null;
1439
+ resolve();
1440
+ });
1441
+ for (const client of this.webSocketServer.clients)client.terminate();
1442
+ this.webSocketServer.clients = [];
1443
+ });
1444
+ if (this.server) {
1445
+ await new Promise((resolve)=>{
1446
+ this.server.close(()=>{
1447
+ this.server = void 0;
1448
+ resolve();
1449
+ });
1450
+ for (const socket of this.sockets)socket.destroy();
1451
+ this.sockets = [];
1452
+ });
1453
+ if (this.middleware) {
1454
+ await new Promise((resolve, reject)=>{
1455
+ this.middleware.close((error)=>{
1456
+ if (error) return void reject(error);
1457
+ resolve();
1458
+ });
1459
+ });
1460
+ this.middleware = void 0;
1461
+ }
1462
+ }
1463
+ for (const item of this.listeners)process.removeListener(item.name, item.listener);
1464
+ }
1465
+ stopCallback(callback = ()=>{}) {
1466
+ this.stop().then(()=>callback(), callback).catch(callback);
1467
+ }
1468
+ }
1469
+ export { Server as RspackDevServer };