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