From 43fa8ebef0c6a0c25c072990881a7035c85b4f9f Mon Sep 17 00:00:00 2001 From: Mars <3361409208a@gmail.com> Date: Tue, 23 Jun 2026 15:10:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(dev):=20=E6=9C=AC=E5=9C=B0=20API=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=AB=AF=E5=8F=A3=E6=94=B9=E4=B8=BA=203100?= =?UTF-8?q?=20=E9=81=BF=E5=BC=80=20Windows=20=E4=BF=9D=E7=95=99=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hyper-V 常保留 2960-3059,3000 会 EACCES;ensure-port-free 与 Vite 代理从 apps/api/.env 读取 PORT --- .env.example | 3 ++- apps/admin/vite.config.ts | 6 ++++-- apps/api/package.json | 2 +- apps/player/vite.config.ts | 7 +++++-- scripts/dev-api-target.mjs | 28 ++++++++++++++++++++++++++++ scripts/ensure-port-free.mjs | 3 ++- 6 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 scripts/dev-api-target.mjs diff --git a/.env.example b/.env.example index 9942dce..41a4867 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,8 @@ JWT_SECRET=change-me-in-production-use-long-random-string JWT_PLAYER_EXPIRES=24h JWT_ADMIN_EXPIRES=2h JWT_AGENT_EXPIRES=8h -PORT=3000 +# 本地开发建议 3100:Windows Hyper-V 常保留 2960–3059,3000 会 EACCES +PORT=3100 NODE_ENV=development UPLOAD_DIR= diff --git a/apps/admin/vite.config.ts b/apps/admin/vite.config.ts index 5520ea0..3118525 100644 --- a/apps/admin/vite.config.ts +++ b/apps/admin/vite.config.ts @@ -1,6 +1,7 @@ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { resolve } from 'path'; +import { resolveApiDevTarget } from '../../scripts/dev-api-target.mjs'; import { visualizer } from 'rollup-plugin-visualizer'; import AutoImport from 'unplugin-auto-import/vite'; import Components from 'unplugin-vue-components/vite'; @@ -8,6 +9,7 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; export default defineConfig(({ mode }) => { const analyze = process.env.ANALYZE === '1' || mode === 'analyze'; + const apiTarget = resolveApiDevTarget(); return { plugins: [ @@ -75,8 +77,8 @@ export default defineConfig(({ mode }) => { server: { port: 5174, proxy: { - '/api': { target: 'http://localhost:3000', changeOrigin: true }, - '/uploads': { target: 'http://localhost:3000', changeOrigin: true }, + '/api': { target: apiTarget, changeOrigin: true }, + '/uploads': { target: apiTarget, changeOrigin: true }, }, }, }; diff --git a/apps/api/package.json b/apps/api/package.json index 7e44964..0463899 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "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", "test": "jest", "test:watch": "jest --watch", diff --git a/apps/player/vite.config.ts b/apps/player/vite.config.ts index bf00cfa..1704b59 100644 --- a/apps/player/vite.config.ts +++ b/apps/player/vite.config.ts @@ -1,6 +1,9 @@ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { resolve } from 'path'; +import { resolveApiDevTarget } from '../../scripts/dev-api-target.mjs'; + +const apiTarget = resolveApiDevTarget(); export default defineConfig({ plugins: [vue()], @@ -37,8 +40,8 @@ export default defineConfig({ server: { port: 5173, proxy: { - '/api': { target: 'http://localhost:3000', changeOrigin: true }, - '/uploads': { target: 'http://localhost:3000', changeOrigin: true }, + '/api': { target: apiTarget, changeOrigin: true }, + '/uploads': { target: apiTarget, changeOrigin: true }, }, }, }); diff --git a/scripts/dev-api-target.mjs b/scripts/dev-api-target.mjs new file mode 100644 index 0000000..5477f60 --- /dev/null +++ b/scripts/dev-api-target.mjs @@ -0,0 +1,28 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); + +/** 本地 dev 默认端口;3000 在部分 Windows(Hyper-V 保留 2960–3059)上会 EACCES */ +const DEFAULT_DEV_API_PORT = '3100'; + +/** 与 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'); + if (existsSync(envPath)) { + const match = readFileSync(envPath, 'utf8').match(/^PORT=(\d+)\s*$/m); + if (match) port = match[1]; + } + 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()}`; +} diff --git a/scripts/ensure-port-free.mjs b/scripts/ensure-port-free.mjs index c30a9e6..fddbc29 100644 --- a/scripts/ensure-port-free.mjs +++ b/scripts/ensure-port-free.mjs @@ -1,6 +1,7 @@ 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) { let out = '';