chore(api): use .env.production on server, .env for local dev only

Load production env without .env override; sync-api-env targets .env.production; PM2 NODE_ENV=production; Prisma uses with-api-env.cjs on deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 23:33:34 +08:00
parent c6af8480a4
commit 6dc051f26d
13 changed files with 68 additions and 41 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
# 杜康 API 环境变量模板
# 本地开发:复制为 .env 后按需修改(pnpm dev:api 仅读取 .env / .env.local
# 可选 .env.local — 本机覆盖(gitignore
# 服务器部署bash deploy/sync-api-env.sh development|production(同步到远端 .env
# .env.development / .env.production — 部署源模板,本地 dev 不自动加载
# 服务器:仅使用 .env.productionbash deploy/sync-api-env.sh production
# .env.development — 本地参考模板,不部署到服务器
DATABASE_URL="mysql://root:root@localhost:3306/dukang_haoke"
REDIS_URL="redis://localhost:6379"
+2 -2
View File
@@ -1,6 +1,6 @@
# 生产环境(真实第三方,关闭 Mock)
# 用途:deploy/sync-api-env.sh production 的源文件,同步到服务器 .env
# 本地开发请使用 .env(从 .env.example 复制)
# 用途:服务器 runtime 配置;bash deploy/sync-api-env.sh production 同步到远端 .env.production
# 本地开发请使用 .env(从 .env.example 复制),勿与生产混用
NODE_ENV=production
@@ -0,0 +1,30 @@
import { config } from 'dotenv';
import { spawnSync } from 'child_process';
import { existsSync } from 'fs';
import { resolve } from 'path';
const apiRoot = resolve(__dirname, '..');
const envFile = process.env.DUKANG_ENV_FILE ?? '.env.production';
const envPath = resolve(apiRoot, envFile);
if (!existsSync(envPath)) {
console.error(`[with-api-env] 未找到 ${envPath}`);
process.exit(1);
}
config({ path: envPath, override: true });
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('用法: node scripts/with-api-env.cjs <command> [args...]');
process.exit(1);
}
const result = spawnSync(args[0], args.slice(1), {
cwd: apiRoot,
stdio: 'inherit',
env: process.env,
shell: true,
});
process.exit(result.status ?? 1);
+5 -9
View File
@@ -5,22 +5,18 @@ import { resolve } from 'path';
/**
* 环境变量加载策略(后加载的文件覆盖先前的同名键):
*
* - 本地开发NODE_ENV !== production:仅 `.env` + `.env.local`
* `.env.development` 仅作 deploy/sync-api-env.sh 的源模板,不在本地 dev 自动加载
* - 本地开发:仅 `.env` + `.env.local`
* `.env.development` 仅作参考模板,不自动加载
*
* - 线上NODE_ENV=production):`.env.production` `.env.production.local` → `.env`
* 服务器实际运行时以 sync 脚本写入的 `.env` 为准
* - 服务器NODE_ENV=production):`.env.production` + `.env.production.local`
* 不使用 `.env`,避免与本地开发配置混淆
*/
const apiRoot = resolve(__dirname, '..');
const nodeEnv = process.env.NODE_ENV ?? 'development';
const isProduction = nodeEnv === 'production';
const layers = isProduction
? [
resolve(apiRoot, '.env.production'),
resolve(apiRoot, '.env.production.local'),
resolve(apiRoot, '.env'),
]
? [resolve(apiRoot, '.env.production'), resolve(apiRoot, '.env.production.local')]
: [resolve(apiRoot, '.env'), resolve(apiRoot, '.env.local')];
for (const file of layers) {