在真实项目里,「如果每次切换环境都手动改代码,不仅低效,还极易把测试地址带到线上。Vue CLI 把「模式 + 环境变量」做成了一套约定大于配置的体系,只要理解规则,就能让同一份源码在任意环境自动作出正确的行为。
一、模式(mode)

Vue CLI 把「运行命令」抽象成三种默认模式:
development
:对应vue-cli-service serve
production
:对应vue-cli-service build
test
:对应vue-cli-service test:unit
模式本身不携带任何变量,它只是约定文件名前缀。
当你执行:
bash
npm run serve # 实际等价于 vue-cli-service serve --mode development
npm run build:staging # 自定义命令,等价于 vue-cli-service build --mode staging
CLI 会按以下顺序寻找文件:
.env.[mode].local
.env.[mode]
.env.local
(永远被 git ignore).env
同名变量后者覆盖前者,因此你可以把公共值写在 .env
,把敏感值写在 .env.local
,把环境特有值写在 .env.staging
,一条命令即可切换。
二、环境变量
- 只有
VUE_APP_
开头的变量才会被打包
任何机器级环境变量(PATH
、HOME
...)都会被忽略,避免污染前端运行时。
想让变量进 bundle,必须加前缀:
bash
# .env.staging
VUE_APP_API_BASE=https://staging.api.example.com
在代码里直接用:
js
axios.defaults.baseURL = process.env.VUE_APP_API_BASE
构建时 CLI 会把 process.env.VUE_APP_API_BASE
替换为字符串字面量,零运行时开销。
- 运行时不可动态修改
变量在 npm run build
那一刻就被写死,前端无法通过 process.env.XXX = 'new'
去改。
需要运行时可变配置?把变量写成 JSON 文件或接口返回,再在前端异步加载即可。
三、一个文件,一条命令,三种环境
假设我们要同时支持 dev / staging / prod
:
bash
根目录
├─ .env # 公共配置
├─ .env.development # 本地开发
├─ .env.staging # 预发
├─ .env.production # 线上
└─ package.json
文件内容示例:
bash
# .env
VUE_APP_TITLE=MyApp
# .env.development
VUE_APP_API_BASE=http://localhost:3000
# .env.staging
VUE_APP_API_BASE=https://staging.api.example.com
# .env.production
VUE_APP_API_BASE=https://api.example.com
自定义脚本:
json
"scripts": {
"serve": "vue-cli-service serve",
"build:staging": "vue-cli-service build --mode staging",
"build": "vue-cli-service build"
}
执行:
bash
npm run build:staging
CLI 自动读取 .env.staging
与 .env
合并,输出包里只有 https://staging.api.example.com
。
四、CI/CD 中的最佳实践
-
不把敏感密钥写进仓库
把
.env*.local
加入.gitignore
,在 CI 里用环境变量注入:
bash
echo $STAGING_KEY >> .env.staging.local
-
单一 Dockerfile,多阶段构建
通过
ARG MODE
动态决定--mode
,同一份镜像可在测试、预发、生产之间漂移。 -
可视化差异
在构建日志里打印
console.log('Build mode:', process.env.NODE_ENV, process.env.VUE_APP_API_BASE)
,一眼确认变量是否生效。
五、常见问题
-
变量名可以改前缀吗?
可以,在
vue.config.js
里设置envPrefix: 'APP_'
即可。 -
为什么本地
.env
改了值不生效?vue-cli-service serve
会缓存旧进程,重启 dev-server 或加--no-cache
即可。 -
如何读取非 VUE_APP 变量?
在
vue.config.js
用chainWebpack
手动注入:
js
config.plugin('define').tap(args => {
args[0]['process.env.CUSTOM'] = JSON.stringify(process.env.CUSTOM)
return args
})