@4399ywkf/core 5.1.3 → 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/index.js CHANGED
@@ -4447,33 +4447,74 @@ import { RspackDevServer } from "@rspack/dev-server";
4447
4447
  import chalk3 from "chalk";
4448
4448
 
4449
4449
  // src/cli/port.ts
4450
+ import { execFile } from "child_process";
4450
4451
  import net from "net";
4451
- function isPortAvailable(port, host) {
4452
- return new Promise((resolve5) => {
4452
+ import { promisify } from "util";
4453
+ var execFileAsync = promisify(execFile);
4454
+ var PortInUseError = class extends Error {
4455
+ constructor(port, host) {
4456
+ super(`Port ${port} is already in use on ${host}`);
4457
+ this.port = port;
4458
+ this.host = host;
4459
+ this.name = "PortInUseError";
4460
+ }
4461
+ };
4462
+ function ensurePortAvailable(port, host) {
4463
+ return new Promise((resolve5, reject) => {
4453
4464
  const server = net.createServer();
4454
4465
  server.once("error", (err) => {
4455
4466
  if (err.code === "EADDRINUSE") {
4456
- resolve5(false);
4467
+ reject(new PortInUseError(port, host));
4457
4468
  } else {
4458
- resolve5(false);
4469
+ reject(err);
4459
4470
  }
4460
4471
  });
4461
4472
  server.once("listening", () => {
4462
- server.close(() => resolve5(true));
4473
+ server.close(() => resolve5());
4463
4474
  });
4464
4475
  server.listen(port, host);
4465
4476
  });
4466
4477
  }
4467
- async function getAvailablePort(preferredPort, host) {
4468
- const MAX_ATTEMPTS = 20;
4469
- for (let i = 0; i < MAX_ATTEMPTS; i++) {
4470
- const port = preferredPort + i;
4471
- const available = await isPortAvailable(port, host);
4472
- if (available) return port;
4478
+ async function findPortHolder(port) {
4479
+ try {
4480
+ if (process.platform === "win32") {
4481
+ const { stdout: stdout2 } = await execFileAsync("netstat", ["-ano", "-p", "tcp"], {
4482
+ timeout: 1500
4483
+ });
4484
+ const pid2 = parseWindowsNetstatPid(stdout2, port);
4485
+ return pid2 === null ? null : { pid: pid2 };
4486
+ }
4487
+ const { stdout } = await execFileAsync(
4488
+ "lsof",
4489
+ ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"],
4490
+ { timeout: 1500 }
4491
+ );
4492
+ const pid = Number.parseInt(stdout.trim().split(/\s+/)[0], 10);
4493
+ if (!Number.isInteger(pid)) return null;
4494
+ let name;
4495
+ try {
4496
+ const { stdout: comm } = await execFileAsync(
4497
+ "ps",
4498
+ ["-p", String(pid), "-o", "comm="],
4499
+ { timeout: 1500 }
4500
+ );
4501
+ name = comm.trim().split("/").pop() || void 0;
4502
+ } catch {
4503
+ }
4504
+ return { pid, name };
4505
+ } catch {
4506
+ return null;
4473
4507
  }
4474
- throw new Error(
4475
- `No available port found in range ${preferredPort}-${preferredPort + MAX_ATTEMPTS - 1}`
4476
- );
4508
+ }
4509
+ function parseWindowsNetstatPid(stdout, port) {
4510
+ for (const line of stdout.split(/\r?\n/)) {
4511
+ const parts = line.trim().split(/\s+/);
4512
+ if (parts.length >= 5 && parts[3] === "LISTENING" && parts[1]?.endsWith(`:${port}`)) {
4513
+ const pid = Number.parseInt(parts[4], 10);
4514
+ if (Number.isInteger(pid)) return pid;
4515
+ }
4516
+ }
4517
+ return null;
4477
4518
  }
4478
4519
 
4479
4520
  // src/cli/restart-watcher.ts
@@ -4538,6 +4579,22 @@ async function loadFullConfig(cwd, mode, envSnapshot, opts = {}) {
4538
4579
  loadEnv(config, cwd, mode, "development");
4539
4580
  return config;
4540
4581
  }
4582
+ async function renderPortInUseError(err) {
4583
+ const holder = await findPortHolder(err.port);
4584
+ console.error();
4585
+ console.error(chalk3.red(` \u2716 \u7AEF\u53E3 ${err.port} \u5DF2\u88AB\u5360\u7528\uFF0C\u65E0\u6CD5\u542F\u52A8 dev server`));
4586
+ if (holder) {
4587
+ const label = holder.name ? `${holder.name} ` : "";
4588
+ const killCmd = process.platform === "win32" ? `taskkill /PID ${holder.pid} /F` : `kill ${holder.pid}`;
4589
+ console.error(chalk3.gray(` \u5360\u7528\u8FDB\u7A0B\uFF1A${label}(PID ${holder.pid})`));
4590
+ console.error(chalk3.gray(` \xB7 \u7ED3\u675F\u5B83\uFF1A${killCmd}`));
4591
+ console.error(chalk3.gray(" \xB7 \u6216\u4FEE\u6539\u914D\u7F6E dev.port \u6362\u4E00\u4E2A\u7AEF\u53E3"));
4592
+ } else {
4593
+ console.error(chalk3.gray(" \xB7 \u4FEE\u6539\u914D\u7F6E dev.port \u6362\u4E00\u4E2A\u7AEF\u53E3"));
4594
+ console.error(chalk3.gray(" \xB7 \u6216\u5148\u91CA\u653E\u5360\u7528\u8BE5\u7AEF\u53E3\u7684\u8FDB\u7A0B"));
4595
+ }
4596
+ console.error();
4597
+ }
4541
4598
  async function startDevServer(cwd, config) {
4542
4599
  const pluginManager = new PluginManager(config, cwd, true);
4543
4600
  if (config.plugins && config.plugins.length > 0) {
@@ -4547,13 +4604,9 @@ async function startDevServer(cwd, config) {
4547
4604
  let rspackConfig = createRspackConfig(config, cwd, { isDev: true });
4548
4605
  rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
4549
4606
  const host = config.dev.host || "127.0.0.1";
4550
- const preferredPort = config.dev.port || 3e3;
4551
- const port = await getAvailablePort(preferredPort, host);
4607
+ const port = config.dev.port || 3e3;
4608
+ await ensurePortAvailable(port, host);
4552
4609
  const pluginNames = pluginManager.getPluginNames();
4553
- if (port !== preferredPort) {
4554
- console.log(chalk3.yellow(` Port ${preferredPort} is in use, using ${port} instead.
4555
- `));
4556
- }
4557
4610
  const printer = new DevPrinter(host, port, pluginNames);
4558
4611
  printer.printBanner();
4559
4612
  printer.printBuildStart();
@@ -4671,10 +4724,17 @@ async function dev(options = {}) {
4671
4724
  await current.close();
4672
4725
  current = await startDevServer(cwd, nextConfig);
4673
4726
  } catch (error) {
4674
- console.error(
4675
- 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:")
4676
- );
4677
- console.error(error);
4727
+ if (error instanceof PortInUseError) {
4728
+ await renderPortInUseError(error);
4729
+ console.error(
4730
+ 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")
4731
+ );
4732
+ } else {
4733
+ console.error(
4734
+ 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:")
4735
+ );
4736
+ console.error(error);
4737
+ }
4678
4738
  }
4679
4739
  } while (pending);
4680
4740
  } finally {
@@ -4683,6 +4743,10 @@ async function dev(options = {}) {
4683
4743
  }
4684
4744
  });
4685
4745
  } catch (error) {
4746
+ if (error instanceof PortInUseError) {
4747
+ await renderPortInUseError(error);
4748
+ process.exit(1);
4749
+ }
4686
4750
  console.error();
4687
4751
  console.error(chalk3.red(" \u2716 Dev server failed to start"));
4688
4752
  console.error(error);