每天閱讀一個npm 包源碼:dotenv的作用,項目中.env文件是干嘛的?
點擊上方 前端陽光,關(guān)注公眾號
回復(fù)加群,加入技術(shù)交流群交流群

.env文件 的作用
?? 加載 .env 文件中的變量到 process.env 中
.env 文件是用來自定義配置的一個簡單方法。我們可以將一些不能在代碼中存儲的 敏感信息 / 賬號數(shù)據(jù) 從代碼中剝離出來,作為環(huán)境變量存儲在 .env 文件中。
.env 的使用方法
.env 文件通常不包含在版本控制內(nèi),因為它可能包含敏感的 API Key 或 密碼。所有需要環(huán)境變量定義的項目都可以創(chuàng)建一個 .env.example 文件。項目合作開發(fā)者可以獨立的復(fù)制 .env.example 并重命名為 .env,同時將其修改為正確的本地環(huán)境配置:API Key 或者其他必要的值。在這個使用方法中 .env 文件應(yīng)該添加到 .gitignore 文件中保證永遠(yuǎn)不會出現(xiàn)在 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 中的環(huán)境變量被加載到 `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 中,可以看到剛開始先初始化了幾個正則表達(dá)式
正則表達(dá)式
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
const RE_NEWLINES = /\\n/g
const NEWLINES_MATCH = /\r\n|\n|\r/
我們可以通過 regexr.com 來交互式查看表達(dá)式各部分的含義:
-
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/匹配 .env 文件中的環(huán)境變量,如 DB_HOST=127.0.0.1,注意到表達(dá)式中有兩個部分被 () 包起來了,這是為了后續(xù)正則匹配的時候方便提取出匹配的字符串,即環(huán)境變量 key,value 的值 -
const RE_NEWLINES = /\\n/g匹配 \n 字符串,\:前面的 \ 將后面的 \ 轉(zhuǎn)義掉了,所以這里匹配的是 \n 字符串,而不是換行符。 -
const NEWLINES_MATCH = /\r\n|\n|\r/匹配換行符:三種換行符是為了兼容各操作系統(tǒng),不同操作系統(tǒng)換行符有所不同:\n: Unix系統(tǒng),\r\n: Windows系統(tǒng),\r: Mac系統(tǒng)
回車 \r 本義是光標(biāo)重新回到本行開頭,r 的英文 return,控制字符為 CR,即 Carriage Return; 換行 \n 本義是光標(biāo)往下一行(不一定到下一行行首),n 的英文 newline,控制字符為 LF,即 Line Feed;
parse 函數(shù)
?? 將 .env 中的字符串轉(zhuǎn)換成 Object
核心邏輯簡化如下:
function parse(src) {
const obj = {}
// 用 NEWLINES_MATCH 分割每行表達(dá)式,再 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
}
其關(guān)鍵是用了 match 方法匹配 'KEY=VAL' 中的 'KEY' 和 'VAL'。match 方法若匹配到了 line 中的鍵值對則會返回一個數(shù)組,這個數(shù)組的第一項是整個正則表達(dá)式所匹配的字符串,后面會接表達(dá)式中用 () 包圍起來的正則表達(dá)式匹配的字符串。所以 key = keyValueArr[1],val = keyValueArr[2]。
config 函數(shù)
?? 將 .env 中的環(huán)境變量加載到 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 函數(shù)分三步:
-
獲取 .env 文件的路徑并讀取文件 -
將文件的字符串傳入 parse 函數(shù)中解析成 Object -
遍歷 Object 將其加載到 process.env中
注意代碼中使用 Object.prototype.hasOwnProperty.call(process.env, key) 判斷 key 是否已經(jīng)存在于 process.env 中,若存在,則不進(jìn)行覆蓋。使用 Object.prototype.hasOwnProperty 是避免原型鏈查找,只判斷 key 是否存在于 process.env 中,而不是其原型鏈上,這樣做可以省去原型鏈查找的耗時。
總結(jié)
dotenv 源碼非常簡短只有 118 行,但其有 14.5k star(截止至本文寫稿時間),源碼簡單易懂,建議自己動手看看。
參考資料
github 倉庫地址:https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fmotdotla%2Fdotenv
Nodejs 環(huán)境下 .env 配置環(huán)境變量:http://www.4k8k.xyz/article/weixin_40817115/86189969
作者:前端唯一深情 鏈接:https://juejin.cn/post/7040397337138561054
我組建了技術(shù)交流群,里面有很多 大佬,歡迎進(jìn)來交流、學(xué)習(xí)、共建。回復(fù)加群即可。
“分享、點贊、在看” 支持一波??
