这样一来,在整个node服务运行的过程中,都会存在名为SOME_ENV_VAL,值为foo的一个环境变量。
NODE中获取环境变量
nodejs允许我们通过
process.env
获取当前运行环境中的所有环境变量。例如我们想取到上文中声明的
SOME_ENV_VAL
变量:
console.log(process.env.SOME_ENV_VAL)
.env文件
当我们的项目需要声明很多环境变量的时候,命令行声明的形式显然过于繁琐,而且难以管理。
.env文件允许我们将所有项目需要的环境变量放在一个单独的文件中,然后一并加载进process.env
我们可以自己编写脚本去加载.env文件,不过更加简便和推荐的方式是使用dotenv
使用dotenv加载.env文件
npm install dotenv --save
dotenv是一个零依赖模块,它将环境变量从 .env 文件加载到 process.env 中。dotenv提供许多的方法,最常用的是dotenv.config()
。
dotenv.config()
读取一个.env文件,解析其内容,将.env文件中声明的环境变量合并进process.env,然后返回一个对象result
。result.parsed
是解析出的内容,result.error
是在解析失败的时候返回的一个标识。 通常我们只需要进行dotenv.config()
操作,不需要关心result
。
先在.env文件中声明环境变量
NAME = foo
AGE = 20
为了能够尽早把.env中的环境变量加载进process.env
,我们应该尽量在项目入口顶部的位置执行dotenv.config()
。比较推荐的做法是单独抽出一个config/env.js文件来处理环境变量逻辑,然后在项目服务的入口文件中引入config/env.js。
require('dotenv').config()
console.log(process.env.NAME);
console.log(process.env.AGE);
dotenv加载优先级
dotenv.config()
方法可以接收一个option
对象,其中option.path
代表我们期望加载的.env*文件路径。
需要注意的是,只要一个环境变量已经被设置过,dotenv就不会修改它 。也就是说,dotenv始终以先加载到的变量声明为更高优先级
我们在项目的根目录下建三个文件,各自声明对应环境的环境变量:
NAME = foo
AGE = 30
COUNTRY = China
NAME = bar
AGE = 20
NAME = zhangsan
LOCAL_ENV = local
我们期望的效果是,.env.local文件中定义的环境变量获得最高优先级,.env.development其次,.env中的通用配置优先级最低,由此我们可以在config/env.js中进行如下的处理:
const path = require("path");
const fs = require("fs");
const dotEnv = require("dotenv");
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
const pathsDotenv = resolveApp(".env");
dotEnv.config({ path: `${pathsDotenv}.local` })
dotEnv.config({ path: `${pathsDotenv}.development` })
dotEnv.config({ path: `${pathsDotenv}` })
console.log(process.env.NAME);
console.log(process.env.AGE);
console.log(process.env.COUNTRY);
console.log(process.env.LOCAL_ENV);
使用dotenv-expand 开启.env文件的模板字符串语法
有时我们希望将某几个环境变量拼接为一个新的环境变量,可能会考虑如下的写法:
NAME = lisi
AGE = 40
NAME_AND_AGE = ${NAME}-is-${AGE}-years-old
我们期望注入到环境变量中的NAME_AND_AGE
是 lisi-is-40-years-old
。
然而直接dotenv.config()
,发现结果是 ${NAME}-is-${AGE}-years-old
。这说明dotenv.config()是没办法解析${NAME}
和${AGE}
这种模板字符串语法的
想要使用模板字符串语法的话,就要用到dotenv-expand了。
npm install dotenv-expand --save
使用方法:接收一个 dotenv.config()
的返回结果作为参数,如果.env*文件中有${XXX}
这种模板语法的话,自动将其解析为同文件中已声明的环境变量XXX
的值:
require('dotenv-expand')(require('dotenv').config());
console.log(process.env.NAME_AND_AGE);
覆写已声明的环境变量
前面我们提到过,dotenv.config()
遇到已经加载过的环境变量,则会跳过加载,导致后加载的.env*文件中声明的重复环境变量被忽略。
如果我们一定要让后加载的环境变量覆盖已存在的环境变量,就需要显式对原有环境变量进行赋值操作。
举个例子:
const fs = require('fs')
const dotenv = require('dotenv')
const envConfig = dotenv.parse(fs.readFileSync('.env.override'))
for (const k in envConfig) {
process.env[k] = envConfig[k]
不过官方并不推荐这样操作,随意修改process.env
的话,后期可能会造成维护的困难。
webpack打包时将环境变量注入前端代码
有时我们希望项目运行时也能取到编译时的环境变量,例如在一个业务代码文件中:
if (process.env.REACT_APP_NODE_ENV === 'development') {
我们可以直接参考一个createReactApp项目中,React帮我们生成的config/env.js里的操作:
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter((key) => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
NODE_ENV: process.env.NODE_ENV || "development",
PUBLIC_URL: publicUrl,
const stringified = {
"process.env": Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
return { raw, stringified };
module.exports = getClientEnvironment;
对应的webpack打包配置:
module.exports = function (webpackEnv) {
return {
plugins: [
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
new webpack.DefinePlugin(env.stringified),
前端工程师 @ 一线小厂
12.0k
粉丝