6a23e79f4c
dev deploys to /opt/dukang-staging (819x, *-test domains); main deploys to production. Staging uses full Mock with shared WeChat app ids. Co-authored-by: Cursor <cursoragent@cursor.com>
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import { config } from 'dotenv';
|
||
import { existsSync } from 'fs';
|
||
import { resolve } from 'path';
|
||
|
||
/**
|
||
* 环境变量加载策略(后加载的文件覆盖先前的同名键):
|
||
*
|
||
* - local:`.env` + `.env.local`
|
||
* - staging:`.env.staging` + `.env.staging.local`(同机测试栈,APP_ENV=staging)
|
||
* - production:`.env.production` + `.env.production.local`
|
||
*
|
||
* 判定:优先 `APP_ENV`;未设置时 `NODE_ENV=production` → production,否则 local。
|
||
* staging 在 PM2 中仍设 `NODE_ENV=production`(构建产物),靠 `APP_ENV=staging` 区分。
|
||
*/
|
||
const apiRoot = resolve(__dirname, '..');
|
||
const nodeEnv = process.env.NODE_ENV ?? 'development';
|
||
|
||
function resolveAppEnv(): 'local' | 'staging' | 'production' {
|
||
const raw = (process.env.APP_ENV ?? '').trim().toLowerCase();
|
||
if (raw === 'staging' || raw === 'stage' || raw === 'test') return 'staging';
|
||
if (raw === 'production' || raw === 'prod') return 'production';
|
||
if (raw === 'local' || raw === 'development' || raw === 'dev') return 'local';
|
||
if (nodeEnv === 'production') return 'production';
|
||
return 'local';
|
||
}
|
||
|
||
const appEnv = resolveAppEnv();
|
||
|
||
const layers =
|
||
appEnv === 'staging'
|
||
? [resolve(apiRoot, '.env.staging'), resolve(apiRoot, '.env.staging.local')]
|
||
: appEnv === 'production'
|
||
? [resolve(apiRoot, '.env.production'), resolve(apiRoot, '.env.production.local')]
|
||
: [resolve(apiRoot, '.env'), resolve(apiRoot, '.env.local')];
|
||
|
||
for (const file of layers) {
|
||
if (existsSync(file)) {
|
||
config({ path: file, override: true });
|
||
}
|
||
}
|
||
|
||
if (!process.env.NODE_ENV) {
|
||
process.env.NODE_ENV = nodeEnv;
|
||
}
|
||
if (!process.env.APP_ENV) {
|
||
process.env.APP_ENV = appEnv;
|
||
}
|