fix(dev): 本地 API 默认端口改为 3100 避开 Windows 保留段

Hyper-V 常保留 2960-3059,3000 会 EACCES;ensure-port-free 与 Vite 代理从 apps/api/.env 读取 PORT
This commit is contained in:
2026-06-23 15:10:43 +08:00
parent aa1a82e8e3
commit a379f9e522
4 changed files with 20 additions and 9 deletions

View File

@@ -4,7 +4,8 @@ JWT_SECRET=change-me-in-production-use-long-random-string
JWT_PLAYER_EXPIRES=24h JWT_PLAYER_EXPIRES=24h
JWT_ADMIN_EXPIRES=2h JWT_ADMIN_EXPIRES=2h
JWT_AGENT_EXPIRES=8h JWT_AGENT_EXPIRES=8h
PORT=3000 # 本地开发建议 3100Windows Hyper-V 常保留 296030593000 会 EACCES
PORT=3100
NODE_ENV=development NODE_ENV=development
UPLOAD_DIR= UPLOAD_DIR=

View File

@@ -4,7 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"dev": "node ../../scripts/ensure-port-free.mjs 3000 && nest start --watch", "dev": "node ../../scripts/ensure-port-free.mjs && nest start --watch",
"start": "node dist/main", "start": "node dist/main",
"test": "jest", "test": "jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",

View File

@@ -4,16 +4,25 @@ import { fileURLToPath } from 'node:url';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
/** 本地 dev:与 apps/api/.env 的 PORT 对齐,供 player/admin Vite 代理使用 */ /** 本地 dev 默认端口3000 在部分 WindowsHyper-V 保留 29603059上会 EACCES */
export function resolveApiDevTarget() { const DEFAULT_DEV_API_PORT = '3100';
if (process.env.VITE_DEV_API_TARGET) return process.env.VITE_DEV_API_TARGET;
if (process.env.API_DEV_TARGET) return process.env.API_DEV_TARGET;
let port = '3000'; /** 与 apps/api/.env 的 PORT 对齐 */
export function resolveApiDevPort() {
if (process.env.PORT) return String(process.env.PORT);
let port = DEFAULT_DEV_API_PORT;
const envPath = resolve(repoRoot, 'apps/api/.env'); const envPath = resolve(repoRoot, 'apps/api/.env');
if (existsSync(envPath)) { if (existsSync(envPath)) {
const match = readFileSync(envPath, 'utf8').match(/^PORT=(\d+)\s*$/m); const match = readFileSync(envPath, 'utf8').match(/^PORT=(\d+)\s*$/m);
if (match) port = match[1]; if (match) port = match[1];
} }
return `http://localhost:${port}`; return port;
}
/** 供 player/admin Vite 代理使用 */
export function resolveApiDevTarget() {
if (process.env.VITE_DEV_API_TARGET) return process.env.VITE_DEV_API_TARGET;
if (process.env.API_DEV_TARGET) return process.env.API_DEV_TARGET;
return `http://localhost:${resolveApiDevPort()}`;
} }

View File

@@ -1,6 +1,7 @@
import { execSync } from 'node:child_process'; import { execSync } from 'node:child_process';
import { resolveApiDevPort } from './dev-api-target.mjs';
const port = process.argv[2] ?? '3000'; const port = process.argv[2] ?? resolveApiDevPort();
function killWindows(portNum) { function killWindows(portNum) {
let out = ''; let out = '';