Vue3里的NODE_ENV到底是啥?为啥打包前后会不一样?搞懂能避好多坑
NODE_ENV是Vue3专属的变量吗?先搞清楚它的真实身份
很多刚接触Vue3的人会误以为NODE_ENV是Vue框架单独造出来的,其实不是——它是Node.js生态里的全局环境变量约定,准确来说是“Node.js环境标识”的通用说法,最早流行这个约定的是前端构建工具Webpack,后来Rollup、Vite这些工具也都沿用了,Vue3不管用Vite还是Webpack脚手架搭建,都会默认绑定这个变量来做一些自动化操作。
那Node.js里的真实全局变量是什么?其实是process.env对象,NODE_ENV只是这个对象里最常用的一个键值对,比如你在Node.js的终端里直接输入process.env,会输出一堆你电脑当前的环境变量,但默认情况下不会有NODE_ENV这个键——得靠我们手动加,或者让构建工具在打包时临时生成。
Vue3项目里NODE_ENV有哪几种常见值?分别对应什么场景?
目前Vue3生态里统一约定了三种NODE_ENV的标准值,少部分团队可能会自定义,但大多数项目(尤其是用官方脚手架创建的)都用这三个:
- development:开发环境,对应你平时写代码时的本地预览阶段
- test:测试环境,对应跑单元测试、E2E测试的阶段
- production:生产环境,对应打包上线给用户用的阶段
这三个值不是随便写的,构建工具和Vue3本身都会对它们有不同的“反应”,比如用Vite的话,开发模式下默认就会把NODE_ENV设为development,打包预览或者正式打包会设为production;如果用Vue Test Utils跑测试,它会自动设为test,如果乱写成prod、dev这种简写,很多工具的自动优化功能就失效了,甚至会报错。
怎么在Vue3项目里查看和修改NODE_ENV的值?
查看NODE_ENV
查看的方法要分场景,不能一概而论:
- 在Vite/Vue CLI的终端命令行里?不可能直接输出终端默认值
刚才说过,Node.js默认没有这个变量,只有在构建工具启动后,它的进程里才会有,不过你可以在项目的入口文件(比如main.js/main.ts)里临时加一段代码,启动开发服务器或者打包运行预览后,在浏览器的控制台里看——注意,只有入口文件或者Vue组件的脚本里的代码,才会在浏览器环境里能拿到这个变量哦?不对不对,等下纠正:Vite和Vue CLI都做了变量注入,把构建工具进程里的process.env.NODEENV,注入到了前端代码的全局变量里,但为了安全,前端代码里只能拿到以特定前缀开头的变量(Vite默认是VITE,Vue CLI默认是VUEAPP),而NODE_ENV是例外,不管前缀,只要是这三个标准值,都会被注入到
import.meta.env.MODE(Vite)或者process.env.NODE_ENV(Vue CLI的前端代码)里?
哦对,这点要讲清楚,不然会混淆,举个具体的例子:
- 如果你用的是Vite创建的Vue3项目:
- 开发阶段:在main.ts里加
console.log('Vite当前模式:', import.meta.env.MODE); console.log('Vite是否开发:', import.meta.env.DEV); console.log('Vite是否生产:', import.meta.env.PROD); console.log('Vite前端拿到的NODE_ENV-like变量:', import.meta.env.VITE_APP_NODE_ENV);——这里前三个是Vite默认注入的,不需要前缀,MODE就是NODE_ENV的标准值,DEV和PROD是布尔值,比判断字符串更安全;第四个必须是你自己加了VITE_前缀的环境变量,才会在前端拿到 - 生产打包阶段:打包出来的代码里会把这些注入的变量替换成常量,比如
if(import.meta.env.DEV)会直接替换成if(false),然后Tree Shaking就会把这段开发用的调试代码删掉,减小体积
- 开发阶段:在main.ts里加
- 如果你用的是Vue CLI创建的Vue3项目:
- 前端代码里可以直接用
process.env.NODE_ENV,比如console.log('Vue CLI当前环境:', process.env.NODE_ENV);,但注意这是构建工具注入的,不是Node.js原生的process.env - 另外Vue CLI也支持自定义前缀VUE_APP_的变量,规则和Vite类似
- 前端代码里可以直接用
- 在Node.js后端脚本或者构建工具的配置文件里?直接用process.env.NODE_ENV就行
比如你在vite.config.ts或者vue.config.js里写配置,这时候是Node.js环境,所以可以直接用
process.env.NODE_ENV来判断当前是开发还是生产,然后动态改配置——比如开发阶段代理后端接口,生产阶段关闭代理;或者开发阶段用sourcemap,生产阶段用更简洁的sourcemap甚至关闭。
修改NODE_ENV
修改的方法也要分场景,还有分构建工具:
- 临时修改(只对当前终端命令有效) 这个最常用,比如你想临时看一下生产模式的打包效果,但不想改配置文件:
- Windows CMD:
set NODE_ENV=production && npm run build - Windows PowerShell:
$env:NODE_ENV="production"; npm run build - macOS/Linux:
NODE_ENV=production npm run build不过注意,用Vite的话,其实不需要这么麻烦,直接用Vite的模式参数就行:npm run build -- --mode production(默认就是production,比如想自定义一个staging预发布模式,就--mode staging);Vue CLI的话是npm run build -- --mode production或者npm run build:prod(如果package.json里配置了的话)。
- 永久修改(通过.env文件) 这个更规范,适合团队协作,因为临时修改的命令别人可能不知道,而且容易忘,不管是Vite还是Vue CLI,都支持用.env文件来配置环境变量:
- 通用规则:
- .env:所有环境都会加载的基础变量
- .env.local:所有环境都会加载,但会被git忽略(适合放敏感信息,比如后端接口的密钥)
- .env.[mode]:只在指定mode下加载的变量,env.development、.env.production
- .env.[mode].local:只在指定mode下加载,且被git忽略
- Vite的特殊规则:
- 只有以VITE_开头的变量才会被注入到前端代码里
- Vite默认的三个模式对应的NODE_ENV/MODE/PROD/DEV是固定的吗?不对不对,等下,比如你自定义了一个staging模式,创建了.env.staging文件,里面如果写
NODE_ENV=production,那Vite的import.meta.env.MODE是staging,但import.meta.env.PROD是true,import.meta.env.NODE_ENV(哦不对Vite前端代码里没有直接的NODE_ENV,只有MODE对应构建工具里的NODE_ENV?等下查一下权威资料的说法,哦对,不管自定义什么模式,只要.env.[mode]里没有显式设置NODE_ENV,Vite会把NODE_ENV设为production如果mode是production或者其他非development/test的自定义模式,设为development如果mode是development,设为test如果mode是test;如果显式设置了NODE_ENV,就用显式的,但PROD和DEV还是会根据显式的NODE_ENV来判断 - 举个例子,创建.env.staging文件,里面写
VITE_APP_API_URL=https://staging.example.com,然后运行npm run build -- --mode staging,这时候import.meta.env.MODE是staging,import.meta.env.PROD是true(因为默认自定义非test/development模式NODE_ENV是production),import.meta.env.VITE_APP_API_URL是https://staging.example.com
- Vue CLI的特殊规则:
- 只有以VUE_APP_开头的变量才会被注入到前端代码里
- Vue CLI默认的三个模式对应的NODE_ENV是固定的,自定义模式如果.env.[mode]里没有显式设置NODE_ENV,就和Vite不一样?哦不对,Vue CLI的自定义模式如果.env.[mode]里没有显式设置NODE_ENV,默认NODE_ENV是development?等下再确认一下,哦对,比如Vue CLI自定义一个staging模式,.env.staging里只写VUE_APP_API_URL,那NODE_ENV还是development,这时候打包出来的代码体积会很大,因为没有开启Tree Shaking和压缩,所以自定义生产相关的模式(比如staging预发布),一定要在.env.[mode]里显式写
NODE_ENV=production
搞懂NODE_ENV能避哪些Vue3项目里的常见坑?
这部分是重点,也是很多新手踩过的,我整理了四个最常见的:
坑1:调试代码忘删,打包上线后还在控制台输出一堆log
这个太常见了,新手写代码的时候喜欢加console.log调试,上线的时候忘了删,结果用户打开浏览器控制台能看到一堆没用的信息,甚至可能暴露敏感数据,但如果用NODE_ENV来判断,就可以自动解决这个问题:
- Vite项目里:
// 封装一个通用的log函数,只有开发模式下才输出 const devLog = (...args) => { if (import.meta.env.DEV) { console.log(...args); } };
// 然后在组件里用devLog代替console.log devLog('这是调试信息,只有开发模式能看到');
- Vue CLI项目里:
```javascript
const devLog = (...args) => {
if (process.env.NODE_ENV === 'development') {
console.log(...args);
}
};
这样打包生产模式的时候,构建工具会把if(import.meta.env.DEV)替换成if(false),然后Tree Shaking就会把整个if块删掉,连devLog函数的定义如果没在生产模式下用到也会被删掉,完全不用担心。
坑2:开发阶段和生产阶段后端接口地址不一样,手动改来改去容易错
这个也是团队协作里的大问题,比如开发阶段用的是本地mock接口或者测试服务器接口,生产阶段用的是正式服务器接口,如果手动改代码里的接口地址,不仅麻烦,而且容易漏改或者改错,用.env文件和NODE_ENV配合就可以自动切换:
- Vite项目里:
- 创建.env.development文件,写
VITE_APP_API_URL=http://localhost:3000/mock - 创建.env.production文件,写
VITE_APP_API_URL=https://api.example.com - 创建.env.staging文件(如果需要预发布),写
NODE_ENV=production和VITE_APP_API_URL=https://staging-api.example.com - 然后在封装axios的文件里直接用:
import axios from 'axios';
- 创建.env.development文件,写
const request = axios.create({ baseURL: import.meta.env.VITE_APP_API_URL, timeout: 5000, });
// 其他拦截器配置... export default request;
这样开发阶段自动用mock地址,生产打包自动用正式地址,预发布打包用staging地址,完全不用手动改。
### 坑3:Vue Devtools在生产模式下还能打开,暴露项目结构和数据
Vue Devtools是开发Vue项目的神器,但在生产模式下如果不关闭,用户可以通过它看到你的组件结构、状态管理数据(比如Pinia/Vuex的state),甚至可以修改数据,这是非常不安全的,不过Vue3本身会根据NODE_ENV自动处理吗?
- 用Vite/Vue CLI官方脚手架创建的项目,默认生产打包会关闭Vue Devtools的注入,因为生产模式下Vue会去掉devtools相关的代码,但如果是自己手动配置的构建工具,或者用了一些第三方插件覆盖了默认配置,可能会导致生产模式下还能打开Devtools,这时候可以显式在入口文件里加判断:
```javascript
// Vite项目
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
if (!import.meta.env.DEV) {
app.config.devtools = false;
}
app.mount('#app');
// Vue CLI项目
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
if (process.env.NODE_ENV !== 'development') {
app.config.devtools = false;
}
app.mount('#app');
不过注意,显式设置app.config.devtools = false在生产模式下其实是冗余的,但加上更保险,防止第三方插件搞破坏。
坑4:生产打包出来的代码体积特别大,没开启压缩和Tree Shaking
这个刚才提到过,如果用了自定义模式但没在.env.[mode]里显式设置NODE_ENV=production,就会导致这个问题,比如Vue CLI自定义staging模式,.env.staging里只写了VUE_APP_API_URL,没有写NODE_ENV=production,那打包出来的代码还是开发模式的,没有压缩,没有Tree Shaking,体积可能是生产模式的好几倍,加载速度特别慢,严重影响用户体验。
那怎么判断打包出来的代码是不是真正的生产模式?很简单,看打包后的文件名:
- Vite生产模式打包的文件名会有哈希值,比如
index.abc123.js,而且体积很小,打开dist/index.html里的script标签,会看到代码是压缩过的(没有换行,变量名都是单个字母) - Vue CLI生产模式打包的文件名也会有哈希值,比如
js/chunk-vendors.def456.js,同样是压缩过的
如果打包出来的文件名没有哈希值,或者代码没有压缩,那大概率是NODE_ENV没设对。
除了这三个标准值,自定义NODE_ENV有没有必要?
其实大多数情况下,用Vite的自定义mode配合显式设置NODE_ENV就够了,不需要自定义NODE_ENV的非标准值,比如刚才提到的staging预发布模式,自定义mode为staging,然后在.env.staging里显式设置NODE_ENV=production,这样既可以用不同的接口地址、不同的配置,又可以享受到生产模式的压缩和Tree Shaking。
那什么时候才需要自定义NODE_ENV的非标准值?比如你的项目有非常特殊的需求,比如需要区分“灰度发布环境”和“正式生产环境”,而且这两个环境的构建工具配置差异很大(比如灰度发布环境保留部分调试信息,正式生产环境完全去掉),这时候可以自定义NODE_ENV为gray和production,然后在构建工具的配置文件里根据process.env.NODE_ENV来做更细的区分。
不过要注意,自定义非标准的NODE_ENV值,很多第三方插件可能不支持,比如Vue Devtools可能不会自动关闭,压缩插件可能不会自动开启,所以需要手动在构建工具配置文件里调整,比较麻烦,非必要不建议用。
总结一下
Vue3里的NODE_ENV虽然不是Vue专属的,但它是连接构建工具和Vue项目的重要桥梁,搞懂它的真实身份、常见值、查看修改方法,以及用它能避的坑,能让你的Vue3开发效率更高,项目更稳定,上线更安全。
最后再给大家划个重点:
- NODE_ENV是Node.js生态的全局环境变量约定,不是Vue专属的
- 标准值只有development、test、production三个,非必要不自定义
- Vite用import.meta.env.MODE/DEV/PROD,Vue CLI用process.env.NODE_ENV,前端代码只能拿到特定前缀的自定义变量
- 用.env文件配置环境变量更规范,适合团队协作
- 自定义生产相关的模式(比如staging),一定要在.env.[mode]里显式设置NODE_ENV=production
- 用NODE_ENV判断可以自动解决调试代码忘删、接口地址手动切换、Devtools生产开放、打包体积大等常见坑
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


