@rspack/dev-server 1.2.1 → 2.0.0-beta.1

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/server.js CHANGED
@@ -24,26 +24,32 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
24
24
  }) : function(o, v) {
25
25
  o["default"] = v;
26
26
  });
27
- var __importStar = (this && this.__importStar) || function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- var __importDefault = (this && this.__importDefault) || function (mod) {
35
- return (mod && mod.__esModule) ? mod : { "default": mod };
36
- };
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
37
44
  Object.defineProperty(exports, "__esModule", { value: true });
38
45
  exports.Server = void 0;
46
+ const fs = __importStar(require("node:fs"));
39
47
  const os = __importStar(require("node:os"));
40
48
  const path = __importStar(require("node:path"));
41
49
  const url = __importStar(require("node:url"));
42
50
  const util = __importStar(require("node:util"));
43
- const fs = __importStar(require("graceful-fs"));
44
51
  const ipaddr = __importStar(require("ipaddr.js"));
45
- const schema_utils_1 = require("schema-utils");
46
- const options_json_1 = __importDefault(require("./options.json"));
52
+ const { styleText } = util;
47
53
  // Define BasicApplication and Server as ambient, or import them
48
54
  if (!process.env.WEBPACK_SERVE) {
49
55
  process.env.WEBPACK_SERVE = 'true';
@@ -70,18 +76,33 @@ const encodeOverlaySettings = (setting) => {
70
76
  : setting;
71
77
  };
72
78
  const DEFAULT_ALLOWED_PROTOCOLS = /^(file|.+-extension):/i;
79
+ /**
80
+ * Extracts and normalizes the hostname from a header, removing brackets for IPv6.
81
+ */
82
+ function parseHostnameFromHeader(header) {
83
+ try {
84
+ const parsedUrl = new URL(
85
+ // if header doesn't have scheme, add // for parsing.
86
+ /^(.+:)?\/\//.test(header) ? header : `//${header}`, 'http://localhost/');
87
+ let { hostname } = parsedUrl;
88
+ // `URL#hostname` keeps IPv6 brackets, but our validation expects bare IPv6.
89
+ if (hostname.startsWith('[') && hostname.endsWith(']')) {
90
+ hostname = hostname.slice(1, -1);
91
+ }
92
+ return hostname;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
73
98
  function isMultiCompiler(compiler) {
74
99
  return Array.isArray(compiler.compilers);
75
100
  }
76
101
  class Server {
77
102
  constructor(options, compiler) {
78
103
  this.isTlsServer = false;
79
- (0, schema_utils_1.validate)(options_json_1.default, options, {
80
- name: 'Dev Server',
81
- baseDataPath: 'options',
82
- });
83
104
  this.compiler = compiler;
84
- this.logger = this.compiler.getInfrastructureLogger('webpack-dev-server');
105
+ this.logger = this.compiler.getInfrastructureLogger('rspack-dev-server');
85
106
  this.options = options;
86
107
  this.staticWatchers = [];
87
108
  this.listeners = [];
@@ -89,9 +110,6 @@ class Server {
89
110
  this.sockets = [];
90
111
  this.currentHash = undefined;
91
112
  }
92
- static get schema() {
93
- return options_json_1.default;
94
- }
95
113
  static get DEFAULT_STATS() {
96
114
  return {
97
115
  all: false,
@@ -158,14 +176,6 @@ class Server {
158
176
  }
159
177
  }
160
178
  }
161
- // TODO remove me in the next major release, we have `findIp`
162
- static async internalIP(family) {
163
- return Server.findIp(family, false);
164
- }
165
- // TODO remove me in the next major release, we have `findIp`
166
- static internalIPSync(family) {
167
- return Server.findIp(family, false);
168
- }
169
179
  static async getHostname(hostname) {
170
180
  if (hostname === 'local-ip') {
171
181
  return (Server.findIp('v4', false) || Server.findIp('v6', false) || '0.0.0.0');
@@ -184,13 +194,13 @@ class Server {
184
194
  }
185
195
  const { default: pRetry } = await import('p-retry');
186
196
  const getPort = require('./getPort');
187
- const basePort = typeof process.env.WEBPACK_DEV_SERVER_BASE_PORT !== 'undefined'
188
- ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
197
+ const basePort = typeof process.env.RSPACK_DEV_SERVER_BASE_PORT !== 'undefined'
198
+ ? Number.parseInt(process.env.RSPACK_DEV_SERVER_BASE_PORT, 10)
189
199
  : 8080;
190
200
  // Try to find unused port and listen on it for 3 times,
191
201
  // if port is not specified in options.
192
- const defaultPortRetry = typeof process.env.WEBPACK_DEV_SERVER_PORT_RETRY !== 'undefined'
193
- ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
202
+ const defaultPortRetry = typeof process.env.RSPACK_DEV_SERVER_PORT_RETRY !== 'undefined'
203
+ ? Number.parseInt(process.env.RSPACK_DEV_SERVER_PORT_RETRY, 10)
194
204
  : 3;
195
205
  return pRetry(() => getPort(basePort, host), {
196
206
  retries: defaultPortRetry,
@@ -214,45 +224,19 @@ class Server {
214
224
  dir = parent;
215
225
  }
216
226
  if (!dir) {
217
- return path.resolve(cwd, '.cache/webpack-dev-server');
227
+ return path.resolve(cwd, '.cache/rspack-dev-server');
218
228
  }
219
229
  if (process.versions.pnp === '1') {
220
- return path.resolve(dir, '.pnp/.cache/webpack-dev-server');
230
+ return path.resolve(dir, '.pnp/.cache/rspack-dev-server');
221
231
  }
222
232
  if (process.versions.pnp === '3') {
223
- return path.resolve(dir, '.yarn/.cache/webpack-dev-server');
233
+ return path.resolve(dir, '.yarn/.cache/rspack-dev-server');
224
234
  }
225
- return path.resolve(dir, 'node_modules/.cache/webpack-dev-server');
226
- }
227
- static isWebTarget(compiler) {
228
- if (compiler.platform?.web) {
229
- return compiler.platform.web;
230
- }
231
- // TODO improve for the next major version and keep only `webTargets` to fallback for old versions
232
- if (compiler.options.externalsPresets?.web) {
233
- return true;
234
- }
235
- if (compiler.options.resolve?.conditionNames?.includes('browser')) {
236
- return true;
237
- }
238
- const webTargets = [
239
- 'web',
240
- 'webworker',
241
- 'electron-preload',
242
- 'electron-renderer',
243
- 'nwjs',
244
- 'node-webkit',
245
- undefined,
246
- null,
247
- ];
248
- if (Array.isArray(compiler.options.target)) {
249
- return compiler.options.target.some((r) => webTargets.includes(r));
250
- }
251
- return webTargets.includes(compiler.options.target);
235
+ return path.resolve(dir, 'node_modules/.cache/rspack-dev-server');
252
236
  }
253
237
  addAdditionalEntries(compiler) {
254
238
  const additionalEntries = [];
255
- const isWebTarget = Server.isWebTarget(compiler);
239
+ const isWebTarget = Boolean(compiler.platform.web);
256
240
  // TODO maybe empty client
257
241
  if (this.options.client && isWebTarget) {
258
242
  let webSocketURLStr = '';
@@ -277,20 +261,14 @@ class Server {
277
261
  searchParams.set('password', webSocketURL.password);
278
262
  }
279
263
  let hostname;
280
- // SockJS is not supported server mode, so `hostname` and `port` can't specified, let's ignore them
281
- const isSockJSType = webSocketServer.type === 'sockjs';
282
264
  const isWebSocketServerHostDefined = typeof webSocketServer.options.host !== 'undefined';
283
265
  const isWebSocketServerPortDefined = typeof webSocketServer.options.port !== 'undefined';
284
- if (isSockJSType &&
285
- (isWebSocketServerHostDefined || isWebSocketServerPortDefined)) {
286
- this.logger.warn("SockJS only supports client mode and does not support custom hostname and port options. Please consider using 'ws' if you need to customize these options.");
287
- }
288
266
  // We are proxying dev server and need to specify custom `hostname`
289
267
  if (typeof webSocketURL.hostname !== 'undefined') {
290
268
  hostname = webSocketURL.hostname;
291
269
  }
292
- // Web socket server works on custom `hostname`, only for `ws` because `sock-js` is not support custom `hostname`
293
- else if (isWebSocketServerHostDefined && !isSockJSType) {
270
+ // Web socket server works on custom `hostname`
271
+ else if (isWebSocketServerHostDefined) {
294
272
  hostname = webSocketServer.options.host;
295
273
  }
296
274
  // The `host` option is specified
@@ -307,8 +285,8 @@ class Server {
307
285
  if (typeof webSocketURL.port !== 'undefined') {
308
286
  port = webSocketURL.port;
309
287
  }
310
- // Web socket server works on custom `port`, only for `ws` because `sock-js` is not support custom `port`
311
- else if (isWebSocketServerPortDefined && !isSockJSType) {
288
+ // Web socket server works on custom `port`
289
+ else if (isWebSocketServerPortDefined) {
312
290
  port = webSocketServer.options.port;
313
291
  }
314
292
  // The `port` option is specified
@@ -331,10 +309,8 @@ class Server {
331
309
  pathname = webSocketURL.pathname;
332
310
  }
333
311
  // Web socket server works on custom `path`
334
- else if (typeof webSocketServer.options.prefix !== 'undefined' ||
335
- typeof webSocketServer.options.path !== 'undefined') {
336
- pathname =
337
- webSocketServer.options.prefix || webSocketServer.options.path;
312
+ else if (typeof webSocketServer.options.path !== 'undefined') {
313
+ pathname = webSocketServer.options.path;
338
314
  }
339
315
  searchParams.set('pathname', pathname);
340
316
  const client = this.options.client;
@@ -374,10 +350,9 @@ class Server {
374
350
  if (clientHotEntry) {
375
351
  additionalEntries.push(clientHotEntry);
376
352
  }
377
- const webpack = compiler.webpack || require('webpack');
378
353
  // use a hook to add entries if available
379
354
  for (const additionalEntry of additionalEntries) {
380
- new webpack.EntryPlugin(compiler.context, additionalEntry, {
355
+ new compiler.rspack.EntryPlugin(compiler.context, additionalEntry, {
381
356
  name: undefined,
382
357
  }).apply(compiler);
383
358
  }
@@ -396,25 +371,21 @@ class Server {
396
371
  if (compilerWithDevServer) {
397
372
  return compilerWithDevServer.options;
398
373
  }
399
- // Configuration with `web` preset
400
- const compilerWithWebPreset = this.compiler.compilers.find((config) => config.options.externalsPresets?.web ||
401
- [
402
- 'web',
403
- 'webworker',
404
- 'electron-preload',
405
- 'electron-renderer',
406
- 'node-webkit',
407
- undefined,
408
- null,
409
- ].includes(config.options.target));
410
- if (compilerWithWebPreset) {
411
- return compilerWithWebPreset.options;
374
+ // Compiler for `web` target
375
+ const compilerWithWebTarget = this.compiler.compilers.find((compiler) => Boolean(compiler.platform.web));
376
+ if (compilerWithWebTarget) {
377
+ return compilerWithWebTarget.options;
412
378
  }
413
379
  // Fallback
414
380
  return this.compiler.compilers[0].options;
415
381
  }
416
382
  return this.compiler.options;
417
383
  }
384
+ shouldLogInfrastructureInfo() {
385
+ const compilerOptions = this.getCompilerOptions();
386
+ const { level = 'info' } = compilerOptions.infrastructureLogging || {};
387
+ return level === 'info' || level === 'log' || level === 'verbose';
388
+ }
418
389
  async normalizeOptions() {
419
390
  const { options } = this;
420
391
  const compilerOptions = this.getCompilerOptions();
@@ -545,12 +516,6 @@ class Server {
545
516
  options.allowedHosts.includes('all')) {
546
517
  options.allowedHosts = 'all';
547
518
  }
548
- if (typeof options.bonjour === 'undefined') {
549
- options.bonjour = false;
550
- }
551
- else if (typeof options.bonjour === 'boolean') {
552
- options.bonjour = options.bonjour ? {} : false;
553
- }
554
519
  if (typeof options.client === 'undefined' ||
555
520
  (typeof options.client === 'object' && options.client !== null)) {
556
521
  if (!options.client) {
@@ -634,13 +599,7 @@ class Server {
634
599
  };
635
600
  }
636
601
  const serverOptions = options.server.options;
637
- if (options.server.type === 'spdy' &&
638
- typeof serverOptions.spdy === 'undefined') {
639
- serverOptions.spdy = { protocols: ['h2', 'http/1.1'] };
640
- }
641
- if (options.server.type === 'https' ||
642
- options.server.type === 'http2' ||
643
- options.server.type === 'spdy') {
602
+ if (options.server.type === 'https' || options.server.type === 'http2') {
644
603
  if (typeof serverOptions.requestCert === 'undefined') {
645
604
  serverOptions.requestCert = false;
646
605
  }
@@ -674,7 +633,6 @@ class Server {
674
633
  return stats ? fs.readFileSync(item) : item;
675
634
  }
676
635
  };
677
- // @ts-expect-error too complex
678
636
  serverOptions[property] = (Array.isArray(value)
679
637
  ? value.map((item) => readFile(item))
680
638
  : readFile(value));
@@ -706,10 +664,14 @@ class Server {
706
664
  this.logger.info('Generating SSL certificate...');
707
665
  const selfsigned = require('selfsigned');
708
666
  const attributes = [{ name: 'commonName', value: 'localhost' }];
709
- const pems = selfsigned.generate(attributes, {
667
+ const notBeforeDate = new Date();
668
+ const notAfterDate = new Date(notBeforeDate);
669
+ notAfterDate.setDate(notAfterDate.getDate() + 30);
670
+ const pems = await selfsigned.generate(attributes, {
710
671
  algorithm: 'sha256',
711
- days: 30,
712
672
  keySize: 2048,
673
+ notBeforeDate,
674
+ notAfterDate,
713
675
  extensions: [
714
676
  {
715
677
  name: 'basicConstraints',
@@ -844,44 +806,6 @@ class Server {
844
806
  if (typeof options.port === 'string' && options.port !== 'auto') {
845
807
  options.port = Number(options.port);
846
808
  }
847
- /**
848
- * Assume a proxy configuration specified as:
849
- * proxy: {
850
- * 'context': { options }
851
- * }
852
- * OR
853
- * proxy: {
854
- * 'context': 'target'
855
- * }
856
- */
857
- if (typeof options.proxy !== 'undefined') {
858
- options.proxy = options.proxy.map((item) => {
859
- if (typeof item === 'function') {
860
- return item;
861
- }
862
- const getLogLevelForProxy = (level) => {
863
- if (level === 'none') {
864
- return 'silent';
865
- }
866
- if (level === 'log') {
867
- return 'info';
868
- }
869
- if (level === 'verbose') {
870
- return 'debug';
871
- }
872
- return level;
873
- };
874
- if (typeof item.logLevel === 'undefined') {
875
- item.logLevel = getLogLevelForProxy(compilerOptions.infrastructureLogging
876
- ? compilerOptions.infrastructureLogging.level
877
- : 'info');
878
- }
879
- if (typeof item.logProvider === 'undefined') {
880
- item.logProvider = () => this.logger;
881
- }
882
- return item;
883
- });
884
- }
885
809
  if (typeof options.setupExitSignals === 'undefined') {
886
810
  options.setupExitSignals = true;
887
811
  }
@@ -974,9 +898,7 @@ class Server {
974
898
  typeof this.options.webSocketServer
975
899
  .type === 'string' &&
976
900
  // @ts-expect-error
977
- (this.options.webSocketServer.type === 'ws' ||
978
- this.options.webSocketServer.type ===
979
- 'sockjs');
901
+ this.options.webSocketServer.type === 'ws';
980
902
  let clientTransport;
981
903
  if (this.options.client) {
982
904
  if (typeof this.options.client
@@ -996,12 +918,13 @@ class Server {
996
918
  }
997
919
  switch (typeof clientTransport) {
998
920
  case 'string':
999
- // could be 'sockjs', 'ws', or a path that should be required
921
+ // could be 'ws' or a path that should be required
1000
922
  if (clientTransport === 'sockjs') {
1001
- clientImplementation = require.resolve('../client/clients/SockJSClient');
923
+ throw new Error("SockJS support has been removed. Please set client.webSocketTransport to 'ws' or provide a custom transport implementation path.");
1002
924
  }
1003
- else if (clientTransport === 'ws') {
1004
- clientImplementation = require.resolve('../client/clients/WebSocketClient');
925
+ if (clientTransport === 'ws') {
926
+ clientImplementation =
927
+ require.resolve('../client/clients/WebSocketClient');
1005
928
  }
1006
929
  else {
1007
930
  try {
@@ -1018,7 +941,7 @@ class Server {
1018
941
  if (!clientImplementationFound) {
1019
942
  throw new Error(`${!isKnownWebSocketServerImplementation
1020
943
  ? 'When you use custom web socket implementation you must explicitly specify client.webSocketTransport. '
1021
- : ''}client.webSocketTransport must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to a JS file via require.resolve(...) which exports a class `);
944
+ : ''}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 `);
1022
945
  }
1023
946
  return clientImplementation;
1024
947
  }
@@ -1027,12 +950,12 @@ class Server {
1027
950
  let implementationFound = true;
1028
951
  switch (typeof this.options.webSocketServer.type) {
1029
952
  case 'string':
1030
- // Could be 'sockjs', in the future 'ws', or a path that should be required
953
+ // Could be 'ws' or a path that should be required
1031
954
  if (this.options.webSocketServer
1032
955
  .type === 'sockjs') {
1033
- implementation = require('./servers/SockJSServer');
956
+ throw new Error("SockJS support has been removed. Please set webSocketServer to 'ws' or provide a custom WebSocket server implementation.");
1034
957
  }
1035
- else if (this.options.webSocketServer
958
+ if (this.options.webSocketServer
1036
959
  .type === 'ws') {
1037
960
  implementation = require('./servers/WebsocketServer');
1038
961
  }
@@ -1053,7 +976,7 @@ class Server {
1053
976
  implementationFound = false;
1054
977
  }
1055
978
  if (!implementationFound) {
1056
- throw new Error("webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to " +
979
+ throw new Error("webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws'), a full path to " +
1057
980
  'a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) ' +
1058
981
  'via require.resolve(...), or the class itself which extends BaseServer');
1059
982
  }
@@ -1074,24 +997,21 @@ class Server {
1074
997
  const { ProgressPlugin } = this.compiler.compilers
1075
998
  ? this.compiler.compilers[0].webpack
1076
999
  : this.compiler.webpack;
1077
- new ProgressPlugin((percent, msg, addInfo, pluginName) => {
1000
+ new ProgressPlugin((percent, msg) => {
1078
1001
  const percentValue = Math.floor(percent * 100);
1079
1002
  let msgValue = msg;
1080
1003
  if (percentValue === 100) {
1081
1004
  msgValue = 'Compilation completed';
1082
1005
  }
1083
- if (addInfo) {
1084
- msgValue = `${msgValue} (${addInfo})`;
1085
- }
1006
+ const payload = {
1007
+ percent: percentValue,
1008
+ msg: msgValue,
1009
+ };
1086
1010
  if (this.webSocketServer) {
1087
- this.sendMessage(this.webSocketServer.clients, 'progress-update', {
1088
- percent: percentValue,
1089
- msg: msgValue,
1090
- pluginName,
1091
- });
1011
+ this.sendMessage(this.webSocketServer.clients, 'progress-update', payload);
1092
1012
  }
1093
1013
  if (this.server) {
1094
- this.server.emit('progress-update', { percent, msg, pluginName });
1014
+ this.server.emit('progress-update', payload);
1095
1015
  }
1096
1016
  }).apply(this.compiler);
1097
1017
  }
@@ -1127,19 +1047,18 @@ class Server {
1127
1047
  continue;
1128
1048
  }
1129
1049
  this.addAdditionalEntries(compiler);
1130
- const webpack = compiler.webpack || require('webpack');
1131
- new webpack.ProvidePlugin({
1050
+ const { ProvidePlugin, HotModuleReplacementPlugin } = compiler.rspack;
1051
+ new ProvidePlugin({
1132
1052
  __webpack_dev_server_client__: this.getClientTransport(),
1133
1053
  }).apply(compiler);
1134
1054
  if (this.options.hot) {
1135
- const HMRPluginExists = compiler.options.plugins.find((plugin) => plugin &&
1136
- plugin.constructor === webpack.HotModuleReplacementPlugin);
1055
+ const HMRPluginExists = compiler.options.plugins.find((plugin) => plugin && plugin.constructor === HotModuleReplacementPlugin);
1137
1056
  if (HMRPluginExists) {
1138
1057
  this.logger.warn('"hot: true" automatically applies HMR plugin, you don\'t have to add it manually to your webpack configuration.');
1139
1058
  }
1140
1059
  else {
1141
1060
  // Apply the HMR plugin
1142
- const plugin = new webpack.HotModuleReplacementPlugin();
1061
+ const plugin = new HotModuleReplacementPlugin();
1143
1062
  plugin.apply(compiler);
1144
1063
  }
1145
1064
  }
@@ -1162,7 +1081,7 @@ class Server {
1162
1081
  // eslint-disable-next-line n/no-process-exit
1163
1082
  process.exit();
1164
1083
  }
1165
- this.logger.info('Gracefully shutting down. To force exit, press ^C again. Please wait...');
1084
+ this.logger.info('Gracefully shutting down. Press ^C again to force exit...');
1166
1085
  needForceShutdown = true;
1167
1086
  this.stopCallback(() => {
1168
1087
  if (typeof this.compiler.close === 'function') {
@@ -1204,12 +1123,12 @@ class Server {
1204
1123
  return statsObj.toJson(stats);
1205
1124
  }
1206
1125
  setupHooks() {
1207
- this.compiler.hooks.invalid.tap('webpack-dev-server', () => {
1126
+ this.compiler.hooks.invalid.tap('rspack-dev-server', () => {
1208
1127
  if (this.webSocketServer) {
1209
1128
  this.sendMessage(this.webSocketServer.clients, 'invalid');
1210
1129
  }
1211
1130
  });
1212
- this.compiler.hooks.done.tap('webpack-dev-server', (stats) => {
1131
+ this.compiler.hooks.done.tap('rspack-dev-server', (stats) => {
1213
1132
  if (this.webSocketServer) {
1214
1133
  this.sendStats(this.webSocketServer.clients, this.getStats(stats));
1215
1134
  }
@@ -1286,7 +1205,7 @@ class Server {
1286
1205
  });
1287
1206
  }
1288
1207
  // compress is placed last and uses unshift so that it will be the first middleware used
1289
- if (this.options.compress && !isHTTP2) {
1208
+ if (this.options.compress) {
1290
1209
  const compression = require('compression');
1291
1210
  middlewares.push({ name: 'compression', middleware: compression() });
1292
1211
  }
@@ -1300,42 +1219,9 @@ class Server {
1300
1219
  name: 'webpack-dev-middleware',
1301
1220
  middleware: this.middleware,
1302
1221
  });
1303
- // Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
1304
1222
  middlewares.push({
1305
- name: 'webpack-dev-server-sockjs-bundle',
1306
- path: '/__webpack_dev_server__/sockjs.bundle.js',
1307
- middleware: (req, res, next) => {
1308
- if (req.method !== 'GET' && req.method !== 'HEAD') {
1309
- next();
1310
- return;
1311
- }
1312
- const clientPath = path.join(__dirname, '../', 'client/modules/sockjs-client/index.js');
1313
- // Express send Etag and other headers by default, so let's keep them for compatibility reasons
1314
- if (typeof res.sendFile === 'function') {
1315
- res.sendFile(clientPath);
1316
- return;
1317
- }
1318
- let stats;
1319
- try {
1320
- // TODO implement `inputFileSystem.createReadStream` in webpack
1321
- stats = fs.statSync(clientPath);
1322
- }
1323
- catch {
1324
- next();
1325
- return;
1326
- }
1327
- res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
1328
- res.setHeader('Content-Length', stats.size);
1329
- if (req.method === 'HEAD') {
1330
- res.end();
1331
- return;
1332
- }
1333
- fs.createReadStream(clientPath).pipe(res);
1334
- },
1335
- });
1336
- middlewares.push({
1337
- name: 'webpack-dev-server-invalidate',
1338
- path: '/webpack-dev-server/invalidate',
1223
+ name: 'rspack-dev-server-invalidate',
1224
+ path: '/rspack-dev-server/invalidate',
1339
1225
  middleware: (req, res, next) => {
1340
1226
  if (req.method !== 'GET' && req.method !== 'HEAD') {
1341
1227
  next();
@@ -1346,8 +1232,8 @@ class Server {
1346
1232
  },
1347
1233
  });
1348
1234
  middlewares.push({
1349
- name: 'webpack-dev-server-open-editor',
1350
- path: '/webpack-dev-server/open-editor',
1235
+ name: 'rspack-dev-server-open-editor',
1236
+ path: '/rspack-dev-server/open-editor',
1351
1237
  middleware: (req, res, next) => {
1352
1238
  if (req.method !== 'GET' && req.method !== 'HEAD') {
1353
1239
  next();
@@ -1368,8 +1254,8 @@ class Server {
1368
1254
  },
1369
1255
  });
1370
1256
  middlewares.push({
1371
- name: 'webpack-dev-server-assets',
1372
- path: '/webpack-dev-server',
1257
+ name: 'rspack-dev-server-assets',
1258
+ path: '/rspack-dev-server',
1373
1259
  middleware: (req, res, next) => {
1374
1260
  if (req.method !== 'GET' && req.method !== 'HEAD') {
1375
1261
  next();
@@ -1388,9 +1274,11 @@ class Server {
1388
1274
  }
1389
1275
  res.write('<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>');
1390
1276
  const statsForPrint = typeof stats.stats !== 'undefined'
1391
- ? stats.toJson({})
1277
+ ? stats.toJson({ assets: true })
1392
1278
  .children
1393
- : [stats.toJson()];
1279
+ : [
1280
+ stats.toJson({ assets: true }),
1281
+ ];
1394
1282
  res.write('<h1>Assets Report:</h1>');
1395
1283
  for (const [index, item] of statsForPrint?.entries() ?? []) {
1396
1284
  res.write('<div>');
@@ -1420,19 +1308,18 @@ class Server {
1420
1308
  if (this.options.proxy) {
1421
1309
  const { createProxyMiddleware } = require('http-proxy-middleware');
1422
1310
  const getProxyMiddleware = (proxyConfig) => {
1423
- // It is possible to use the `bypass` method without a `target` or `router`.
1424
- // However, the proxy middleware has no use in this case, and will fail to instantiate.
1425
- if (proxyConfig.target) {
1426
- const context = proxyConfig.context || proxyConfig.path;
1427
- return createProxyMiddleware(context, proxyConfig);
1311
+ const { context, ...proxyOptions } = proxyConfig;
1312
+ const pathFilter = proxyOptions.pathFilter ?? context;
1313
+ if (typeof pathFilter !== 'undefined') {
1314
+ proxyOptions.pathFilter = pathFilter;
1428
1315
  }
1429
- if (proxyConfig.router) {
1430
- return createProxyMiddleware(proxyConfig);
1316
+ if (typeof proxyOptions.logger === 'undefined') {
1317
+ proxyOptions.logger = this.logger;
1431
1318
  }
1432
- // TODO improve me after drop `bypass` to always generate error when configuration is bad
1433
- if (!proxyConfig.bypass) {
1434
- util.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/tree/v2.0.6#http-proxy-middleware-options`, 'DEP_WEBPACK_DEV_SERVER_PROXY_ROUTES_ARGUMENT')();
1319
+ if (proxyOptions.target || proxyOptions.router) {
1320
+ return createProxyMiddleware(proxyOptions);
1435
1321
  }
1322
+ util.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')();
1436
1323
  };
1437
1324
  /**
1438
1325
  * @example
@@ -1473,34 +1360,10 @@ class Server {
1473
1360
  proxyMiddleware = getProxyMiddleware(proxyConfig);
1474
1361
  }
1475
1362
  }
1476
- // - Check if we have a bypass function defined
1477
- // - In case the bypass function is defined we'll retrieve the
1478
- // bypassUrl from it otherwise bypassUrl would be null
1479
- // TODO remove in the next major in favor `context` and `router` options
1480
- const isByPassFuncDefined = typeof proxyConfig.bypass === 'function';
1481
- if (isByPassFuncDefined) {
1482
- util.deprecate(() => { }, "Using the 'bypass' option is deprecated. Please use the 'router' or 'context' options. Read more at https://github.com/chimurai/http-proxy-middleware/tree/v2.0.6#http-proxy-middleware-options", 'DEP_WEBPACK_DEV_SERVER_PROXY_BYPASS_ARGUMENT')();
1483
- }
1484
- const bypassUrl = isByPassFuncDefined
1485
- ? await proxyConfig.bypass(req, res, proxyConfig)
1486
- : null;
1487
- if (typeof bypassUrl === 'boolean') {
1488
- // skip the proxy
1489
- res.statusCode = 404;
1490
- req.url = '';
1491
- next();
1492
- }
1493
- else if (typeof bypassUrl === 'string') {
1494
- // byPass to that url
1495
- req.url = bypassUrl;
1496
- next();
1497
- }
1498
- else if (proxyMiddleware) {
1363
+ if (proxyMiddleware) {
1499
1364
  return proxyMiddleware(req, res, next);
1500
1365
  }
1501
- else {
1502
- next();
1503
- }
1366
+ next();
1504
1367
  };
1505
1368
  middlewares.push({
1506
1369
  name: 'http-proxy-middleware',
@@ -1659,15 +1522,11 @@ class Server {
1659
1522
  });
1660
1523
  }
1661
1524
  createWebSocketServer() {
1662
- // @ts-expect-error constructor
1663
1525
  this.webSocketServer = new (this.getServerTransport())(this);
1664
1526
  (this.webSocketServer?.implementation).on('connection', (client, request) => {
1665
1527
  const headers = typeof request !== 'undefined'
1666
1528
  ? request.headers
1667
- : typeof client
1668
- .headers !== 'undefined'
1669
- ? client.headers
1670
- : undefined;
1529
+ : undefined;
1671
1530
  if (!headers) {
1672
1531
  this.logger.warn('webSocketServer implementation must pass headers for the "connection" event');
1673
1532
  }
@@ -1741,56 +1600,7 @@ class Server {
1741
1600
  });
1742
1601
  }));
1743
1602
  }
1744
- runBonjour() {
1745
- const { Bonjour } = require('bonjour-service');
1746
- const type = this.isTlsServer ? 'https' : 'http';
1747
- this.bonjour = new Bonjour();
1748
- this.bonjour?.publish({
1749
- name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
1750
- port: this.options.port,
1751
- type,
1752
- subtypes: ['webpack'],
1753
- ...this.options.bonjour,
1754
- });
1755
- }
1756
- stopBonjour(callback = () => { }) {
1757
- this.bonjour?.unpublishAll(() => {
1758
- this.bonjour?.destroy();
1759
- if (callback) {
1760
- callback();
1761
- }
1762
- });
1763
- }
1764
1603
  async logStatus() {
1765
- const { cyan, isColorSupported, red } = require('colorette');
1766
- const getColorsOption = (compilerOptions) => {
1767
- let colorsEnabled;
1768
- if (compilerOptions.stats &&
1769
- typeof compilerOptions.stats.colors !==
1770
- 'undefined') {
1771
- colorsEnabled = compilerOptions.stats
1772
- .colors;
1773
- }
1774
- else {
1775
- colorsEnabled = isColorSupported;
1776
- }
1777
- return colorsEnabled;
1778
- };
1779
- const colors = {
1780
- info(useColor, msg) {
1781
- if (useColor) {
1782
- return cyan(msg);
1783
- }
1784
- return msg;
1785
- },
1786
- error(useColor, msg) {
1787
- if (useColor) {
1788
- return red(msg);
1789
- }
1790
- return msg;
1791
- },
1792
- };
1793
- const useColor = getColorsOption(this.getCompilerOptions());
1794
1604
  const server = this.server;
1795
1605
  if (this.options.ipc) {
1796
1606
  this.logger.info(`Project is running at: "${server?.address()}"`);
@@ -1803,28 +1613,13 @@ class Server {
1803
1613
  }
1804
1614
  const { address, port } = addressInfo;
1805
1615
  const prettyPrintURL = (newHostname) => url.format({ protocol, hostname: newHostname, port, pathname: '/' });
1806
- let host;
1807
1616
  let localhost;
1808
1617
  let loopbackIPv4;
1809
1618
  let loopbackIPv6;
1810
1619
  let networkUrlIPv4;
1811
1620
  let networkUrlIPv6;
1812
- if (this.options.host) {
1813
- if (this.options.host === 'localhost') {
1814
- localhost = prettyPrintURL('localhost');
1815
- }
1816
- else {
1817
- let isIP;
1818
- try {
1819
- isIP = ipaddr.parse(this.options.host);
1820
- }
1821
- catch {
1822
- // Ignore
1823
- }
1824
- if (!isIP) {
1825
- host = prettyPrintURL(this.options.host);
1826
- }
1827
- }
1621
+ if (this.options.host === 'localhost') {
1622
+ localhost = prettyPrintURL('localhost');
1828
1623
  }
1829
1624
  const parsedIP = ipaddr.parse(address);
1830
1625
  if (parsedIP.range() === 'unspecified') {
@@ -1856,28 +1651,19 @@ class Server {
1856
1651
  networkUrlIPv6 = prettyPrintURL(address);
1857
1652
  }
1858
1653
  }
1859
- this.logger.info('Project is running at:');
1860
- if (host) {
1861
- this.logger.info(`Server: ${colors.info(useColor, host)}`);
1862
- }
1863
- if (localhost || loopbackIPv4 || loopbackIPv6) {
1864
- const loopbacks = [];
1865
- if (localhost) {
1866
- loopbacks.push([colors.info(useColor, localhost)]);
1867
- }
1868
- if (loopbackIPv4) {
1869
- loopbacks.push([colors.info(useColor, loopbackIPv4)]);
1870
- }
1871
- if (loopbackIPv6) {
1872
- loopbacks.push([colors.info(useColor, loopbackIPv6)]);
1873
- }
1874
- this.logger.info(`Loopback: ${loopbacks.join(', ')}`);
1654
+ const urlLogs = [];
1655
+ const local = localhost || loopbackIPv4 || loopbackIPv6;
1656
+ if (local) {
1657
+ urlLogs.push(` ${styleText('white', '➜')} ${styleText(['white', 'dim'], 'Local:')} ${styleText('cyan', local)}`);
1875
1658
  }
1876
1659
  if (networkUrlIPv4) {
1877
- this.logger.info(`On Your Network (IPv4): ${colors.info(useColor, networkUrlIPv4)}`);
1660
+ urlLogs.push(` ${styleText('white', '➜')} ${styleText(['white', 'dim'], 'Network:')} ${styleText('cyan', networkUrlIPv4)}`);
1661
+ }
1662
+ else if (networkUrlIPv6) {
1663
+ urlLogs.push(` ${styleText('white', '➜')} ${styleText(['white', 'dim'], 'Network:')} ${styleText('cyan', networkUrlIPv6)}`);
1878
1664
  }
1879
- if (networkUrlIPv6) {
1880
- this.logger.info(`On Your Network (IPv6): ${colors.info(useColor, networkUrlIPv6)}`);
1665
+ if (urlLogs.length && this.shouldLogInfrastructureInfo()) {
1666
+ console.log(`${urlLogs.join('\n')}\n`);
1881
1667
  }
1882
1668
  if (this.options.open?.length > 0) {
1883
1669
  const openTarget = prettyPrintURL(!this.options.host ||
@@ -1888,22 +1674,6 @@ class Server {
1888
1674
  await this.openBrowser(openTarget);
1889
1675
  }
1890
1676
  }
1891
- if (this.options.static?.length > 0) {
1892
- this.logger.info(`Content not from webpack is served from '${colors.info(useColor, this.options.static
1893
- .map((staticOption) => staticOption.directory)
1894
- .join(', '))}' directory`);
1895
- }
1896
- if (this.options.historyApiFallback) {
1897
- this.logger.info(`404s will fallback to '${colors.info(useColor, this.options.historyApiFallback
1898
- .index || '/index.html')}'`);
1899
- }
1900
- if (this.options.bonjour) {
1901
- const bonjourProtocol = this.options.bonjour?.type ||
1902
- this.isTlsServer
1903
- ? 'https'
1904
- : 'http';
1905
- this.logger.info(`Broadcasting "${bonjourProtocol}" with subtype of "webpack" via ZeroConf DNS (Bonjour)`);
1906
- }
1907
1677
  }
1908
1678
  setHeaders(req, res, next) {
1909
1679
  let { headers } = this.options;
@@ -1971,12 +1741,7 @@ class Server {
1971
1741
  if (DEFAULT_ALLOWED_PROTOCOLS.test(header)) {
1972
1742
  return true;
1973
1743
  }
1974
- // use the node url-parser to retrieve the hostname from the host-header.
1975
- // TODO resolve me in the next major release
1976
- // eslint-disable-next-line n/no-deprecated-api
1977
- const { hostname } = url.parse(
1978
- // if header doesn't have scheme, add // for parsing.
1979
- /^(.+:)?\/\//.test(header) ? header : `//${header}`, false, true);
1744
+ const hostname = parseHostnameFromHeader(header);
1980
1745
  if (hostname === null) {
1981
1746
  return false;
1982
1747
  }
@@ -1987,8 +1752,8 @@ class Server {
1987
1752
  // A note on IPv6 addresses:
1988
1753
  // header will always contain the brackets denoting
1989
1754
  // an IPv6-address in URLs,
1990
- // these are removed from the hostname in url.parse(),
1991
- // so we have the pure IPv6-address in hostname.
1755
+ // these are not removed from `URL#hostname`,
1756
+ // so we normalize to a pure IPv6-address when parsing.
1992
1757
  // For convenience, always allow localhost (hostname === 'localhost')
1993
1758
  // and its subdomains (hostname.endsWith(".localhost")).
1994
1759
  // allow hostname of listening address (hostname === this.options.host)
@@ -2012,9 +1777,7 @@ class Server {
2012
1777
  if (DEFAULT_ALLOWED_PROTOCOLS.test(originHeader)) {
2013
1778
  return true;
2014
1779
  }
2015
- // TODO resolve me in the next major release
2016
- // eslint-disable-next-line n/no-deprecated-api
2017
- const origin = url.parse(originHeader, false, true).hostname;
1780
+ const origin = parseHostnameFromHeader(originHeader);
2018
1781
  if (origin === null) {
2019
1782
  return false;
2020
1783
  }
@@ -2028,10 +1791,7 @@ class Server {
2028
1791
  if (DEFAULT_ALLOWED_PROTOCOLS.test(hostHeader)) {
2029
1792
  return true;
2030
1793
  }
2031
- // eslint-disable-next-line n/no-deprecated-api
2032
- const host = url.parse(
2033
- // if hostHeader doesn't have scheme, add // for parsing.
2034
- /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`, false, true).hostname;
1794
+ const host = parseHostnameFromHeader(hostHeader);
2035
1795
  if (host === null) {
2036
1796
  return false;
2037
1797
  }
@@ -2042,8 +1802,7 @@ class Server {
2042
1802
  }
2043
1803
  sendMessage(clients, type, data, params) {
2044
1804
  for (const client of clients) {
2045
- // `sockjs` uses `1` to indicate client is ready to accept data
2046
- // `ws` uses `WebSocket.OPEN`, but it is mean `1` too
1805
+ // `ws` uses `WebSocket.OPEN` to indicate client is ready to accept data
2047
1806
  if (client.readyState === 1) {
2048
1807
  client.send(JSON.stringify({ type, data, params }));
2049
1808
  }
@@ -2147,9 +1906,6 @@ class Server {
2147
1906
  if (this.options.webSocketServer) {
2148
1907
  this.createWebSocketServer();
2149
1908
  }
2150
- if (this.options.bonjour) {
2151
- this.runBonjour();
2152
- }
2153
1909
  await this.logStatus();
2154
1910
  if (typeof this.options.onListening === 'function') {
2155
1911
  this.options.onListening(this);
@@ -2161,13 +1917,6 @@ class Server {
2161
1917
  .catch(callback);
2162
1918
  }
2163
1919
  async stop() {
2164
- if (this.bonjour) {
2165
- await new Promise((resolve) => {
2166
- this.stopBonjour(() => {
2167
- resolve();
2168
- });
2169
- });
2170
- }
2171
1920
  this.webSocketProxies = [];
2172
1921
  await Promise.all(this.staticWatchers.map((watcher) => watcher.close()));
2173
1922
  this.staticWatchers = [];