每天阅读一个npm 包源码:dotenv的作用,项目中.env文件是干嘛的?
共 4619字,需浏览 10分钟
·
2021-12-16 04:38
点击上方 前端阳光,关注公众号
回复加群,加入技术交流群交流群
.env文件 的作用
💡 加载 .env 文件中的变量到 process.env
中
.env 文件是用来自定义配置的一个简单方法。我们可以将一些不能在代码中存储的 敏感信息 / 账号数据 从代码中剥离出来,作为环境变量存储在 .env 文件中。
.env 的使用方法
.env
文件通常不包含在版本控制内,因为它可能包含敏感的 API Key
或 密码。所有需要环境变量定义的项目都可以创建一个 .env.example
文件。项目合作开发者可以独立的复制 .env.example
并重命名为 .env,同时将其修改为正确的本地环境配置:API Key
或者其他必要的值。在这个使用方法中 .env
文件应该添加到 .gitignore
文件中保证永远不会出现在 git 中。
-
在根目录下添加 .env 文件,eg:
DB_HOST=127.0.0.1
DB_NAME=timeseriesmonitor
DB_PORT=5432
DB_USER=tsm
DB_UNSECURE=true
-
引入 dotenv:npm install dotenv
const dotenv = require('dotenv');
dotenv.config('./env'); // .env 中的环境变量被加载到 `process.env` 中
console.log(`process.env`);
-
打印log如下:
{
...
DB_HOST: '127.0.0.1',
DB_NAME: 'timeseriesmonitor',
DB_PORT: '5432',
DB_UNSECURE: 'true',
DB_USER: 'tsm',
...
}
.env 源码解读
核心代码逻辑在 lib/main.js 中,可以看到刚开始先初始化了几个正则表达式
正则表达式
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
const RE_NEWLINES = /\\n/g
const NEWLINES_MATCH = /\r\n|\n|\r/
我们可以通过 regexr.com 来交互式查看表达式各部分的含义:
-
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
匹配 .env 文件中的环境变量,如 DB_HOST=127.0.0.1,注意到表达式中有两个部分被 () 包起来了,这是为了后续正则匹配的时候方便提取出匹配的字符串,即环境变量 key,value 的值 -
const RE_NEWLINES = /\\n/g
匹配 \n 字符串,\:前面的 \ 将后面的 \ 转义掉了,所以这里匹配的是 \n 字符串,而不是换行符。 -
const NEWLINES_MATCH = /\r\n|\n|\r/
匹配换行符:三种换行符是为了兼容各操作系统,不同操作系统换行符有所不同:\n: Unix系统,\r\n: Windows系统,\r: Mac系统
回车 \r 本义是光标重新回到本行开头,r 的英文 return,控制字符为 CR,即 Carriage Return; 换行 \n 本义是光标往下一行(不一定到下一行行首),n 的英文 newline,控制字符为 LF,即 Line Feed;
parse 函数
💡 将 .env 中的字符串转换成 Object
核心逻辑简化如下:
function parse(src) {
const obj = {}
// 用 NEWLINES_MATCH 分割每行表达式,再 forEach 依次处理
src.split(NEWLINES_MATCH).forEach(function (line, idx) {
// 用 RE_INI_KEY_VAL 匹配 'KEY=VAL' 中的 'KEY' 和 'VAL'
const keyValueArr = line.match(RE_INI_KEY_VAL)
// matched?
if (keyValueArr != null) {
const key = keyValueArr[1]
const val = (keyValueArr[2] || '').trim()
obj[key] = val
}
})
return obj
}
其关键是用了 match 方法匹配 'KEY=VAL' 中的 'KEY' 和 'VAL'。match 方法若匹配到了 line 中的键值对则会返回一个数组,这个数组的第一项是整个正则表达式所匹配的字符串,后面会接表达式中用 () 包围起来的正则表达式匹配的字符串。所以 key = keyValueArr[1],val = keyValueArr[2]。
config 函数
💡 将 .env 中的环境变量加载到 process.env
中
核心逻辑简化如下:
function config(options) {
let dotenvPath = path.resolve(process.cwd(), '.env')
const parsed = parse(fs.readFileSync(dotenvPath, { encoding: 'utf8' }))
Object.keys(parsed).forEach(function (key) {
if (!Object.prototype.hasOwnProperty.call(`process.env`, key)) {
`process.env`[key] = parsed[key]
}
})
return { parsed }
}
config 函数分三步:
-
获取 .env 文件的路径并读取文件 -
将文件的字符串传入 parse 函数中解析成 Object -
遍历 Object 将其加载到 process.env
中
注意代码中使用 Object.prototype.hasOwnProperty.call(process.env, key)
判断 key 是否已经存在于 process.env
中,若存在,则不进行覆盖。使用 Object.prototype.hasOwnProperty
是避免原型链查找,只判断 key 是否存在于 process.env
中,而不是其原型链上,这样做可以省去原型链查找的耗时。
总结
dotenv 源码非常简短只有 118 行,但其有 14.5k star(截止至本文写稿时间),源码简单易懂,建议自己动手看看。
参考资料
github 仓库地址:https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fmotdotla%2Fdotenv
Nodejs 环境下 .env 配置环境变量:http://www.4k8k.xyz/article/weixin_40817115/86189969
作者:前端唯一深情 链接:https://juejin.cn/post/7040397337138561054
我组建了技术交流群,里面有很多 大佬,欢迎进来交流、学习、共建。回复加群即可。
“分享、点赞、在看” 支持一波👍