每天阅读一个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 中。

  1. 在根目录下添加 .env 文件,eg:
DB_HOST=127.0.0.1
DB_NAME=timeseriesmonitor
DB_PORT=5432
DB_USER=tsm
DB_UNSECURE=true
  1. 引入 dotenv:npm install dotenv
const dotenv = require('dotenv');

dotenv.config('./env');  // .env 中的环境变量被加载到 `process.env` 中

console.log(`process.env`);
  1. 打印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 函数分三步:

  1. 获取 .env 文件的路径并读取文件
  2. 将文件的字符串传入 parse 函数中解析成 Object
  3. 遍历 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

技术交流群


我组建了技术交流群,里面有很多 大佬,欢迎进来交流、学习、共建。回复加群即可。



   “分享、点赞在看” 支持一波👍



浏览 96
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报