@4399ywkf/core 5.1.2 → 5.1.4

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/cli/index.js CHANGED
@@ -2127,7 +2127,7 @@ var defaultConfig = {
2127
2127
  strictMode: true,
2128
2128
  dev: {
2129
2129
  port: 3e3,
2130
- host: "localhost",
2130
+ host: "127.0.0.1",
2131
2131
  proxy: {},
2132
2132
  https: false
2133
2133
  },
@@ -4169,6 +4169,10 @@ function getNetworkAddress(port) {
4169
4169
  }
4170
4170
  return null;
4171
4171
  }
4172
+ function displayHost(host) {
4173
+ if (host === "0.0.0.0" || host === "::") return "localhost";
4174
+ return host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
4175
+ }
4172
4176
  var BAR_WIDTH = 30;
4173
4177
  function renderBar(percent) {
4174
4178
  const filled = Math.round(BAR_WIDTH * percent);
@@ -4270,7 +4274,7 @@ var DevPrinter = class {
4270
4274
  * 打印服务器信息面板(dev 模式使用)
4271
4275
  */
4272
4276
  printServerInfo() {
4273
- const localUrl = `http://localhost:${this.port}/`;
4277
+ const localUrl = `http://${displayHost(this._host)}:${this.port}/`;
4274
4278
  const networkUrl = getNetworkAddress(this.port);
4275
4279
  console.log(` ${chalk.bold(">")} Local: ${chalk.cyan(localUrl)}`);
4276
4280
  if (networkUrl) {
@@ -4313,7 +4317,7 @@ function registerShortcuts(getPrinter, opts) {
4313
4317
  getPrinter().printShortcuts();
4314
4318
  break;
4315
4319
  case "o": {
4316
- const url = `http://localhost:${opts.getPort()}/`;
4320
+ const url = `http://${displayHost(opts.getHost())}:${opts.getPort()}/`;
4317
4321
  import("child_process").then((cp) => {
4318
4322
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
4319
4323
  cp.exec(`${command} ${url}`);
@@ -4386,7 +4390,7 @@ async function build(options = {}) {
4386
4390
  let rspackConfig = createRspackConfig(config, cwd, { isDev: false });
4387
4391
  rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
4388
4392
  const pluginNames = pluginManager.getPluginNames();
4389
- const printer = new DevPrinter("localhost", 0, pluginNames, true);
4393
+ const printer = new DevPrinter("127.0.0.1", 0, pluginNames, true);
4390
4394
  printer.printBanner();
4391
4395
  printer.printBuildStart();
4392
4396
  printer.updateProgress(0, "preparing");
@@ -4440,33 +4444,74 @@ import { RspackDevServer } from "@rspack/dev-server";
4440
4444
  import chalk3 from "chalk";
4441
4445
 
4442
4446
  // src/cli/port.ts
4447
+ import { execFile } from "child_process";
4443
4448
  import net from "net";
4444
- function isPortAvailable(port, host) {
4445
- return new Promise((resolve5) => {
4449
+ import { promisify } from "util";
4450
+ var execFileAsync = promisify(execFile);
4451
+ var PortInUseError = class extends Error {
4452
+ constructor(port, host) {
4453
+ super(`Port ${port} is already in use on ${host}`);
4454
+ this.port = port;
4455
+ this.host = host;
4456
+ this.name = "PortInUseError";
4457
+ }
4458
+ };
4459
+ function ensurePortAvailable(port, host) {
4460
+ return new Promise((resolve5, reject) => {
4446
4461
  const server = net.createServer();
4447
4462
  server.once("error", (err) => {
4448
4463
  if (err.code === "EADDRINUSE") {
4449
- resolve5(false);
4464
+ reject(new PortInUseError(port, host));
4450
4465
  } else {
4451
- resolve5(false);
4466
+ reject(err);
4452
4467
  }
4453
4468
  });
4454
4469
  server.once("listening", () => {
4455
- server.close(() => resolve5(true));
4470
+ server.close(() => resolve5());
4456
4471
  });
4457
4472
  server.listen(port, host);
4458
4473
  });
4459
4474
  }
4460
- async function getAvailablePort(preferredPort, host) {
4461
- const MAX_ATTEMPTS = 20;
4462
- for (let i = 0; i < MAX_ATTEMPTS; i++) {
4463
- const port = preferredPort + i;
4464
- const available = await isPortAvailable(port, host);
4465
- if (available) return port;
4466
- }
4467
- throw new Error(
4468
- `No available port found in range ${preferredPort}-${preferredPort + MAX_ATTEMPTS - 1}`
4469
- );
4475
+ async function findPortHolder(port) {
4476
+ try {
4477
+ if (process.platform === "win32") {
4478
+ const { stdout: stdout2 } = await execFileAsync("netstat", ["-ano", "-p", "tcp"], {
4479
+ timeout: 1500
4480
+ });
4481
+ const pid2 = parseWindowsNetstatPid(stdout2, port);
4482
+ return pid2 === null ? null : { pid: pid2 };
4483
+ }
4484
+ const { stdout } = await execFileAsync(
4485
+ "lsof",
4486
+ ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"],
4487
+ { timeout: 1500 }
4488
+ );
4489
+ const pid = Number.parseInt(stdout.trim().split(/\s+/)[0], 10);
4490
+ if (!Number.isInteger(pid)) return null;
4491
+ let name;
4492
+ try {
4493
+ const { stdout: comm } = await execFileAsync(
4494
+ "ps",
4495
+ ["-p", String(pid), "-o", "comm="],
4496
+ { timeout: 1500 }
4497
+ );
4498
+ name = comm.trim().split("/").pop() || void 0;
4499
+ } catch {
4500
+ }
4501
+ return { pid, name };
4502
+ } catch {
4503
+ return null;
4504
+ }
4505
+ }
4506
+ function parseWindowsNetstatPid(stdout, port) {
4507
+ for (const line of stdout.split(/\r?\n/)) {
4508
+ const parts = line.trim().split(/\s+/);
4509
+ if (parts.length >= 5 && parts[3] === "LISTENING" && parts[1]?.endsWith(`:${port}`)) {
4510
+ const pid = Number.parseInt(parts[4], 10);
4511
+ if (Number.isInteger(pid)) return pid;
4512
+ }
4513
+ }
4514
+ return null;
4470
4515
  }
4471
4516
 
4472
4517
  // src/cli/restart-watcher.ts
@@ -4531,6 +4576,22 @@ async function loadFullConfig(cwd, mode, envSnapshot, opts = {}) {
4531
4576
  loadEnv(config, cwd, mode, "development");
4532
4577
  return config;
4533
4578
  }
4579
+ async function renderPortInUseError(err) {
4580
+ const holder = await findPortHolder(err.port);
4581
+ console.error();
4582
+ console.error(chalk3.red(` \u2716 \u7AEF\u53E3 ${err.port} \u5DF2\u88AB\u5360\u7528\uFF0C\u65E0\u6CD5\u542F\u52A8 dev server`));
4583
+ if (holder) {
4584
+ const label = holder.name ? `${holder.name} ` : "";
4585
+ const killCmd = process.platform === "win32" ? `taskkill /PID ${holder.pid} /F` : `kill ${holder.pid}`;
4586
+ console.error(chalk3.gray(` \u5360\u7528\u8FDB\u7A0B\uFF1A${label}(PID ${holder.pid})`));
4587
+ console.error(chalk3.gray(` \xB7 \u7ED3\u675F\u5B83\uFF1A${killCmd}`));
4588
+ console.error(chalk3.gray(" \xB7 \u6216\u4FEE\u6539\u914D\u7F6E dev.port \u6362\u4E00\u4E2A\u7AEF\u53E3"));
4589
+ } else {
4590
+ console.error(chalk3.gray(" \xB7 \u4FEE\u6539\u914D\u7F6E dev.port \u6362\u4E00\u4E2A\u7AEF\u53E3"));
4591
+ console.error(chalk3.gray(" \xB7 \u6216\u5148\u91CA\u653E\u5360\u7528\u8BE5\u7AEF\u53E3\u7684\u8FDB\u7A0B"));
4592
+ }
4593
+ console.error();
4594
+ }
4534
4595
  async function startDevServer(cwd, config) {
4535
4596
  const pluginManager = new PluginManager(config, cwd, true);
4536
4597
  if (config.plugins && config.plugins.length > 0) {
@@ -4539,14 +4600,10 @@ async function startDevServer(cwd, config) {
4539
4600
  await pluginManager.runBeforeDevServer();
4540
4601
  let rspackConfig = createRspackConfig(config, cwd, { isDev: true });
4541
4602
  rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
4542
- const host = config.dev.host || "localhost";
4543
- const preferredPort = config.dev.port || 3e3;
4544
- const port = await getAvailablePort(preferredPort, host);
4603
+ const host = config.dev.host || "127.0.0.1";
4604
+ const port = config.dev.port || 3e3;
4605
+ await ensurePortAvailable(port, host);
4545
4606
  const pluginNames = pluginManager.getPluginNames();
4546
- if (port !== preferredPort) {
4547
- console.log(chalk3.yellow(` Port ${preferredPort} is in use, using ${port} instead.
4548
- `));
4549
- }
4550
4607
  const printer = new DevPrinter(host, port, pluginNames);
4551
4608
  printer.printBanner();
4552
4609
  printer.printBuildStart();
@@ -4622,6 +4679,7 @@ async function dev(options = {}) {
4622
4679
  };
4623
4680
  registerShortcuts(() => current.printer, {
4624
4681
  getPort: () => current.port,
4682
+ getHost: () => current.host,
4625
4683
  onQuit: async () => {
4626
4684
  console.log(chalk3.gray("\n Shutting down...\n"));
4627
4685
  await shutdown();
@@ -4663,10 +4721,17 @@ async function dev(options = {}) {
4663
4721
  await current.close();
4664
4722
  current = await startDevServer(cwd, nextConfig);
4665
4723
  } catch (error) {
4666
- console.error(
4667
- chalk3.red(" \u2716 dev server \u91CD\u542F\u5931\u8D25\uFF0C\u5F53\u524D\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u8BF7\u4FEE\u6B63\u540E\u4FDD\u5B58\u91CD\u8BD5:")
4668
- );
4669
- console.error(error);
4724
+ if (error instanceof PortInUseError) {
4725
+ await renderPortInUseError(error);
4726
+ console.error(
4727
+ chalk3.red(" \u2716 dev server \u91CD\u542F\u5931\u8D25\uFF0C\u5F53\u524D\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u8BF7\u4FEE\u6B63\u540E\u4FDD\u5B58\u91CD\u8BD5")
4728
+ );
4729
+ } else {
4730
+ console.error(
4731
+ chalk3.red(" \u2716 dev server \u91CD\u542F\u5931\u8D25\uFF0C\u5F53\u524D\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u8BF7\u4FEE\u6B63\u540E\u4FDD\u5B58\u91CD\u8BD5:")
4732
+ );
4733
+ console.error(error);
4734
+ }
4670
4735
  }
4671
4736
  } while (pending);
4672
4737
  } finally {
@@ -4675,6 +4740,10 @@ async function dev(options = {}) {
4675
4740
  }
4676
4741
  });
4677
4742
  } catch (error) {
4743
+ if (error instanceof PortInUseError) {
4744
+ await renderPortInUseError(error);
4745
+ process.exit(1);
4746
+ }
4678
4747
  console.error();
4679
4748
  console.error(chalk3.red(" \u2716 Dev server failed to start"));
4680
4749
  console.error(error);