import.meta.env 是构建时静态注入的环境变量对象,需通过 --mode 指定对应 .env.[mode] 文件实现编译期分支控制,CI/CD 应精准触发不同模式构建而非运行时修改。

import.meta.env 是 Vite 等现代前端构建工具在编译时注入的环境变量对象,它不是运行时动态读取的,而是在构建阶段由构建工具根据 .env 文件和 --mode 参数静态替换生成的。因此,它本身不支持“运行时自动注入”或“CI/CD 中动态写入”,但可以被 CI/CD 流程精准控制,从而实现模块行为的分支控制——关键在于:让不同环境的构建使用不同的 --mode,并确保对应 .env.[mode] 文件内容准确、隔离、可审计。
以下是具体落地方式:
一、按环境定义独立的 env 模式与变量
在项目根目录下创建多个环境配置文件:
.env # 默认,本地开发(可选) .env.development # 开发环境构建用(vite build --mode development) .env.staging # 预发环境 .env.production # 生产环境
每个文件中声明明确的行为控制变量,例如:
# .env.staging VUE_APP_API_BASE_URL="https://api-staging.example.com" MODULE_FEATURE_PAY="true" MODULE_ANALYTICS="false" MODULE_A_B_TEST="group-b"
✅ 优势:变量名语义清晰,值为字符串,便于模块内做条件判断;所有变量在构建时硬编码进 JS,无网络请求开销。
二、CI/CD 中按部署目标触发对应模式构建
在 GitHub Actions / GitLab CI 等流程中,禁止在构建脚本里手动 export 或 sed 替换 import.meta.env(这会破坏确定性),而是通过 --mode 显式指定:
# .github/workflows/deploy.yml
jobs:
build-staging:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build -- --mode staging # ← 关键:指向 .env.staging
- uses: actions/upload-artifact@v3
with:
name: staging-dist
path: dist/同理,生产环境用 --mode production,确保构建产物只含该环境的变量值。
三、模块内用 import.meta.env 实现行为分支
无需额外工具或运行时解析,直接在代码中做轻量判断:
// src/modules/payment/index.ts
if (import.meta.env.MODULE_FEATURE_PAY === 'true') {
export const initPayment = () => { /* 启用支付模块 */ };
} else {
export const initPayment = () => { /* 空实现或降级逻辑 */ };
}
// src/modules/analytics/tracker.ts
if (import.meta.env.MODULE_ANALYTICS === 'true') {
startAnalyticsTracker();
}也可以封装成更安全的类型化访问:
const ENV = import.meta.env as ImportMetaEnv & {
MODULE_FEATURE_PAY: string;
MODULE_A_B_TEST: string;
};
export const isPayEnabled = ENV.MODULE_FEATURE_PAY === 'true';
export const abGroup = ENV.MODULE_A_B_TEST || 'default';四、规避常见陷阱
- ❌ 不要尝试在 CI 中
echo "VUE_APP_X=xxx" >> .env:污染默认文件,易引发跨环境泄漏 - ❌ 不要在 JS 里用
fetch('/env.json')动态加载:违背import.meta.env设计初衷,失去编译期优化与 tree-shaking 优势 - ✅ 推荐做法:所有环境变量必须来自
.env.*文件,且每个文件仅被一个--mode引用;CI 流水线中禁止修改源码树(如sed -i)
本质上,这是编译时分支(compile-time branching),而非运行时配置。CI/CD 的作用是确保“哪个分支被编译”,而不是“在已编译代码里改什么”。
不复杂但容易忽略

















