Node.js/Vue/Nuxt.js项目中的环境变量process.env用法详解
1. Node.js的环境变量对象 process.env
https://nodejs.org/dist/latest-v8.x/docs/api/process.html#process_process_env
process.env是一个包含了操作系统当前用户的环境变量的对象。
所以
- 遵从操作系统环境变量的规则。
参考Linux的环境变量: https://man7.org/linux/man-pages/man7/environ.7.html - 在系统全局修改、或者当前运行环境中修改环境变量,都会反应到新启动的Node.js应用中。
几个要点:
- 环境变量只在启动时被加载
- 进程隔离
process.env的值可以被在Node.js进程中被修改,但是,并不会真正修改用户的环境变量,也就是说,脱离这个进程之后,这些修改将不生效。
例如:
$ node -e 'process.env.foo = "bar"' && echo "foo=$foo"
将输出:
foo=
这是因为,实际上,process.envs是环境变量的值拷贝,而不直接操作环境变量。
- process.env中的值都是字符串
对process.env中的属性进行赋值,将直接被转换为字符串类型,例如:
process.env.test = null;
console.log(process.env.test);
// => 'null'
process.env.test = undefined;
console.log(process.env.test);
// => 'undefined'
- Windows系统中,process.env的属性是大小写无关的。
- 使用delete可以移除process.env中的配置
process.env.TEST = 1;
console.log(process.env.TEST);
// => '1'
delete process.env.TEST;
console.log(process.env.TEST);
// => undefined
2. Vue项目的环境变量
Vue,准确的说是vue-cli-service在处理环境变量。
2.1. 运行模式
vue-cli-service 支持3种模式:
- development 开发环境
- test 单元测试环境
- production 生产环境
NODE_ENV 可用于指定vue-cli-service运行的模式。
2.2. 环境变量文件
vue-cli-service使用dotenv来管理环境变量,定义在环境变量文件中的参数,会被注入到process.env中。
关于dotenv: https://github.com/motdotla/dotenv
自动环境变量文件
Vue项目根目录下,如果包含以下环境变量文件,将按照一定规则被自动加载:
.env # 在所有的环境中被载入
.env.local # 在所有的环境中被载入,但会被 git 忽略
.env.[mode] # 只在指定的模式中被载入
.env.[mode].local # 只在指定的模式中被载入,但会被 git 忽略
注意
未测试Nuxt.js项目是否遵从这个规则。
2.3. 运行时的环境变量
所有变量可以在vue-cli-service的命令、插件或者依赖中被使用。
但是,只有 NODE_ENV,BASE_URL 和以 VUE_APP_ 开头的变量,会被编译到客户端代码中。
特别注意
编译的方式是直接替换成实际的值。
也就是说,在编译后的客户端代码,是无法直接访问process.env的。
这也符合Node.js对process.env的规定:process.env是Node.js进程中的一个对象,而Vue的客户端并不是一个Node.js进程。
大胆猜测一下,进一步的,在一个编译后的Vue应用中,process.env也许甚至不能被访问(undefined),或者是一个空对象。(注意:实际结果未经测试)
特殊参数
- NODE_ENV 用于定义当前的运行模式,始终是development, production, test中的一个。
- BASE_URL 与vue.config.js中的publicPath一致,是应用会被部署到的基础路径。
3. Nuxt.js项目的环境变量
首先,Nuxt.js是一个Node.js项目,所以也遵守Node.js的环境变量规则,使用process.env来访问环境变量。
其次,Nuxt.js也是一个Vue项目,也遵守Vue的一些规则。至于到底遵守多少,得看Nuxt.js的具体实现。
最后,Nuxt.js又不是一个单纯的Vue项目或者Node.js项目,它既包含了服务端的代码,也包含了客户端的代码,所以也有自己的环境变量规则。
官方文档:
从官方文档可以看到,nuxt.config.js 提供了多个配置环境变量的字段和方法,看起来很乱。
实际上,nuxt.js中有两种环境变量:
- 编译阶段的环境变量
- 运行阶段的环境变量
3.1. 编译阶段的环境变量
通过在nuxt.config.js文件中配置env字段,可以设置在编译阶段使用的环境变量,这些变量无法在运行时被访问(无论服务端还是客户端)。
示例
{
export default {
env: {
NODE_ENV="staging",
VERSION="1.2.3"
}
}
}
3.2. 运行阶段的环境变量
与Vue项目一样,Nuxt.js也使用dotenv库来实现运行阶段的环境变量设置。
如果项目的根目录下存在.env
文件,则会被自动加载进process.env。
如果配置文件是别的名字,也可以在启动的时候,显示指定并加载:
--dotenv <配置文件>
通过这种方式,可以为不同环境指定不同的配置文件。
.env文件的变量是被加载进process.env的,那么如何在代码中使用呢?
首先,我们知道,nuxt.js提供了多种渲染方式,服务端渲染、客户端渲染、静态渲染。为了安全,Nuxt.js又提出了两种运行时配置:
- 运行阶段的公有配置 publicRuntimeConfig
- 运行阶段的私有配置 privateRuntimeConfig
1). 公有配置 publicRuntimeConfig 字段
nuxt.config.js中的publicRuntimeConfig用于设置在服务端和客户端都可以使用的参数:
export default {
publicRuntimeConfig: {
GUEST_USER: process.env.GUEST_USER || "guest",
GUEST_SECRET: process.env.GUEST_SECRET || "guest"
}
}
在运行时,可以直接使用$config.<参数>
来访问。
注意: 不是什么代码中都可以直接使用$config
2). 私有配置 privateRuntimeConfig 字段
nuxt.config.js中privateRuntimeConfig用于设置仅在服务端使用的参数,通常用于保存敏感信息:
export default {
publicRuntimeConfig: {
ADMIN_USER: process.env.ADMIN_USER || "admin",
ADMIN_SECRET: process.env.ADMIN_SECRET || "password"
}
}
同样的,在运行时,可以直接使用$config.<参数>
来访问。
注意
如果privateRuntimeConfig与publicRuntimeConfig有同名参数,则私有参数覆盖公有参数,也就是privateRuntimeConfig优先级更高。
3). 使用运行阶段的配置参数
运行阶段的配置参数会被注入到nuxt.config中。
在script中,可以通过context.$config,或者this.$config来访问:
<script>
asyncData ({ $config: { baseURL } }) {
const posts = await fetch(`${baseURL}/posts`)
.then(res => res.json())
}
</script>
注意 也就说,script的环境中需要有Nuxt.js的context才能访问。
或者template中,直接使用$config
<template>
<p>Our Url is: {{ $config.baseURL}}</p>
</template>
官方提示
如果在服务端之外的环境中使用$config,则可能会暴露私有配置。也就说,不要在客户端代码中使用私有参数。
那么,问题来了:
这是因为这些参数会被静态嵌入到客户端代码里,还是注入到客户端的$config,从而被暴露?
3.3. 模块Modules的参数配置
nuxt.config.js中还可以直接为模块设置参数,具体参数的由每个模块自己来实现。
例如,常用的axios网络模块,会读取nuxt.config.js中的 axios 字段作为自己的默认参数:
axios: {
// baseURL: process.env.API_URL + '/api',
// proxy: true,
baseURL: process.env.BASE_URL
}
而谷歌分析模块@nuxtjs/google-analytics
读取字段 googleAnalytics:
googleAnalytics: {
id: process.env.GOOGLE_ANALYTICS_ID
},
那么,问题又来了:
这些参数是编译阶段参数、还是运行阶段参数?在私有还是公有?该如何使用呢?
要回答这些问题,需要参考Nuxt.js的module文档:
3.4. 总结
Nuxt.js项目中,环境变量可以
- 在操作系统中设置
- 在启动命令中设置(运行时设置,或者配置在package.json中)
- 在nuxt.config.js中的env中配置
使用时,
- 在编译阶段,可以使用process.env来访问环境变量
- 而在运行阶段,通过将process.env赋值给publicRuntimeConfig或者privateRuntimeConfig,注入到context.$config,供服务端代码或者客户端代码使用。
4. 其他
在博文《Node环境变量 process.env 的那些事儿》的评论中,有一个有趣的回复: