Vue CLI 环境变量和模式:让开发、测试、生产配置分开
先说问题:不要在业务代码里到处判断 NODE_ENV
最开始我习惯这样写:
const BASE_URL = process.env.NODE_ENV === 'development'
? 'http://localhost'
: 'https://example.com'
只有开发和生产两个环境时,这段代码还能勉强工作。一旦项目增加测试、预发布或演示环境,就会出现两个麻烦:
- 同一类配置要在多个文件里重复判断;
NODE_ENV只能表达构建环境,不能表达“这是测试环境还是预发布环境”。
更清楚的做法是:用 mode 选择配置文件,用 NODE_ENV 表示当前构建工具处于什么类型的运行状态。
Vue CLI 会读取哪些环境文件
在项目根目录可以放置:
.env # 所有模式都会加载
.env.local # 所有模式都会加载,但通常不提交 Git
.env.[mode] # 只在指定 mode 下加载
.env.[mode].local # 只在指定 mode 下加载,通常不提交 Git
例如:
.env
.env.local
.env.development
.env.test
.env.production
.env.test.local
同名变量存在时,模式专属文件和 .local 文件通常用于覆盖通用配置。不同 Vue CLI 版本的加载细节应以项目当前版本文档为准,最重要的是不要把密钥提交到公共仓库。
一个实际的配置例子
当时本地开发需要访问局域网服务,所以在 .env.local 中写了:
VUE_APP_BUILD_MODE=development
VUE_APP_BASE_URL=http://172.16.6.132:8002/threemiju/
测试环境单独写在 .env.test:
VUE_APP_BUILD_MODE=test
VUE_APP_BASE_URL=https://test.example.com/threemiju/
生产环境写在 .env.production:
VUE_APP_BUILD_MODE=production
VUE_APP_BASE_URL=https://example.com/threemiju/
Vue CLI 暴露给客户端代码的变量需要使用 VUE_APP_ 前缀:
export const baseURL = process.env.VUE_APP_BASE_URL
export const buildMode = process.env.VUE_APP_BUILD_MODE
这个前缀不是权限控制。只要变量被打进前端 bundle,用户就能在浏览器里看到它。因此 API Key、数据库密码和其他真正的 secret 不能放在 VUE_APP_ 变量里。
在 package.json 中显式选择 mode
一个简单的脚本可以这样写:
{
"scripts": {
"serve": "vue-cli-service serve",
"serve:test": "vue-cli-service serve --mode test",
"build:test": "vue-cli-service build --mode test",
"build:production": "vue-cli-service build --mode production"
}
}
运行时:
npm run serve
npm run serve:test
npm run build:test
npm run build:production
--mode test 的作用是选择 .env.test,不是让业务代码自己去猜当前环境。构建命令本身仍然会影响 NODE_ENV:开发服务器通常是 development,生产构建通常是 production。不要仅仅为了区分测试环境,就在 .env.test 里盲目覆盖 NODE_ENV。
如果测试构建确实需要生产优化,应先确认当前 Vue CLI 版本的行为,再检查构建结果,而不是只根据是否生成了一个 app.js 判断代码分割是否生效。
mode 和 NODE_ENV 的区别
可以这样理解:
| 概念 | 解决的问题 | 示例 |
|---|---|---|
| mode | 选择哪一组 .env.[mode] 配置 | development、test、production |
NODE_ENV | 告诉 Vue CLI 当前运行/构建处于哪种优化状态 | development、production、test |
| 自定义变量 | 表达项目自己的业务环境 | VUE_APP_BUILD_MODE=test |
如果业务只需要显示“当前是测试环境”,使用 VUE_APP_BUILD_MODE 更直观,不要把所有逻辑都绑在 NODE_ENV 上。
环境变量的使用场景
1. 请求地址
import axios from 'axios'
export const api = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: 10000
})
2. 页面显示构建环境
<template>
<span :title="buildMode">{{ version }} · {{ buildMode }}</span>
</template>
<script>
export default {
data() {
return {
version: '1.0.0',
buildMode: process.env.VUE_APP_BUILD_MODE || process.env.NODE_ENV
}
}
}
</script>
构建时变量会被替换进静态资源,所以修改 .env 后需要重新启动开发服务器或重新执行构建,运行中的页面不会自动读取新文件。
.local 文件什么时候有用
.local 文件适合保存“只属于当前机器”的配置:
- 本机局域网 API 地址;
- 临时调试开关;
- 不希望提交到仓库的开发参数;
- 团队成员各自不同的本地配置。
建议在仓库中提交一个不含敏感值的示例:
.env.local.example
并在 .gitignore 中忽略真正的本地文件:
.env.local
.env.*.local
这次踩坑留下的检查清单
遇到环境配置不生效时,我现在会按这个顺序检查:
- 当前命令实际使用了哪个
--mode; - 文件名是否是
.env.[mode],而不是写成其他格式; - 客户端变量是否使用了
VUE_APP_前缀; - 修改变量后是否重启了开发服务器;
- 生产构建时是否把敏感信息打进了 bundle;
- 构建产物里是否真的出现了预期的接口地址;
- 是否错误地把 mode 和
NODE_ENV当成了同一个概念。
环境变量的价值不是让配置文件变多,而是让“配置选择”从业务代码中移出去。项目环境一多,越应该让命令、配置文件和构建产物之间的关系清清楚楚。
参考资料
可用性说明:本文发布于 2020 年 8 月,距今已超过五年。文中涉及的软件版本、接口、下载地址、命令参数和操作界面可能已经发生变化,部分方案在当前环境下可能失效。请结合官方最新文档核对后再操作,生产环境使用前务必先行验证。
版权声明: 本文首发于 指尖魔法屋-Vue CLI 环境变量和模式:让开发、测试、生产配置分开(https://blog.thinkmoon.cn/post/894-guide-environment-vue/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。