1. 前言
大家好,我是若川。持續組織了5個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。
本文倉庫 https://github.com/lxchuan12/dotenv-analysis.git,求個star^_^[1]
源碼共讀活動
每周一期,已進行到19期。于是搜尋各種值得我們學習,且代碼行數不多的源碼。dotenv 主文件僅118行[2],非常值得我們學習。
閱讀本文,你將學到:
1.?學會?dotenv?原理和實現
2.?學會使用?fs模塊?獲取文件并解析
3.?等等
2. 環境準備
#?推薦克隆我的項目,保證與文章同步
git?clone?https://github.com/lxchuan12/dotenv-analysis.git
#?npm?i?-g?yarn
cd?dotenv-analysis/dotenv?&&?yarn?i
#?VSCode?直接打開當前項目
#?code?.
#?我寫的例子都在?examples?這個文件夾中,可以啟動服務本地查看調試
#?在?dotenv-analysis?目錄下
node?examples/index.js#?或者克隆官方項目
git?clone?https://github.com/motdotla/dotenv.git
#?npm?i?-g?yarn
cd?dotenv?&&?yarn?i
#?VSCode?直接打開當前項目
#?code?.
如果需要對源碼進行調試,可以看我的這篇文章:新手向:前端程序員必學基本技能——調試JS代碼,這里就不再贅述了。
3. dotenv 的作用
dotenv[3]
Dotenv
是一個零依賴模塊,可將 .env
文件中的環境變量加載到 process.env
中。
如果需要使用變量,則配合如下擴展包使用。
dotenv-expand[4]
眾所周知,.env
文件在我們項目中非常常見,在 vue-cli
和 create-react-app
中都有使用。
vue-cli .env[5]
create-react-app .env[6]
4. .env 文件使用
我們項目中經常會用到.env 文件
寫法:
NAME=若川
AGE=18
BLOG=https://lxchuan12.gitee.io
MP_WEIXIN='若川視野'
ACTIVITY=每周一起學200行左右的源碼共讀活動
WEIXIN=加我微信?ruochuan12?參與
單從這個文件來看,我們可以知道有如下功能需要實現:
讀取 .env 文件
解析 .env 文件拆成鍵值對的對象形式
賦值到 process.env 上
最后返回解析后得到的對象
5. 簡單實現
根據分析問題,我們最終可以簡單把代碼實現如下:
const?fs?=?require('fs');
const?path?=?require('path');const?parse?=?function?parse(src){const?obj?=?{};//?用換行符?分割//?比如/***?NAME=若川*?AGE=18*?MP_WEIXIN=若川視野*?BLOG=https://lxchuan12.gitee.io*?ACTIVITY=每周一起學200行左右的源碼共讀活動*?WEIXIN=加我微信?ruochuan12?參與*/src.toString().split('\n').forEach(function(line,?index){//?用等號分割const?keyValueArr?=?line.split('=');//?NAMEkey?=?keyValueArr[0];//?若川val?=?keyValueArr[1]?||?'';obj[key]?=?val;});//?{?NAME:?'若川',?...?}return?obj;
}const?config?=?function(){//?讀取?node?執行的當前路徑下的?.env?文件let?dotenvPath?=?path.resolve(process.cwd(),?'.env');//?按?utf-8?解析文件,得到對象//?{?NAME:?'若川',?...?}const?parsed?=?parse(fs.readFileSync(dotenvPath,?'utf-8'));//?鍵值對形式賦值到?process.env?變量上,原先存在的不賦值Object.keys(parsed).forEach(function(key){if(!Object.prototype.hasOwnProperty.call(process.env,?key)){process.env[key]?=?parsed[key];}});//?返回對象return?parsed;
};console.log(config());
console.log(process.env);//?導出?config?parse?函數
module.exports.config?=?config;
module.exports.parse?=?parse;
6. 繼續完善 config 函數
簡版的 config 函數還缺失挺多功能,比如:
可由用戶自定義路徑
可由用戶自定義解析編碼規則
添加?debug?模式
完善報錯輸出,用戶寫的 env 文件自由度比較大,所以需要容錯機制。
根據功能,我們很容易實現以下代碼:
function?resolveHome?(envPath)?{return?envPath[0]?===?'~'???path.join(os.homedir(),?envPath.slice(1))?:?envPath
}const?config?=?function(options){//?讀取?node?執行的當前路徑下的?.env?文件let?dotenvPath?=?path.resolve(process.cwd(),?'.env');//?utf8let?encoding?=?'utf8';//?debug?模式,輸出提示等信息let?debug?=?false;//?對象if?(options)?{if?(options.path?!=?null)?{//?解析路徑dotenvPath?=?resolveHome(options.path)}//?使用配置的編碼方式if?(options.encoding?!=?null)?{encoding?=?options.encoding}//?有配置就設置為?trueif?(options.debug?!=?null)?{debug?=?true}}try?{//?按?utf-8?解析文件,得到對象//?{?NAME:?'若川',?...?}//?debug?傳遞給?parse?函數?便于const?parsed?=?parse(fs.readFileSync(dotenvPath,?{?encoding?}),?{?debug?});//?鍵值對形式賦值到?process.env?變量上,原先存在的不賦值Object.keys(parsed).forEach(function(key){if(!Object.prototype.hasOwnProperty.call(process.env,?key)){process.env[key]?=?parsed[key];}?else?if?(debug)?{console.log(`"${key}"?is?already?defined?in?\`process.env\`?and?will?not?be?overwritten`);}});//?返回對象return?parsed;}catch?(e)?{return?{?error:?e?};}
};
dotenv
源碼中,parse
函數主要是一些正則和單雙引號、跨平臺等細致處理。這里就暫時不闡述,讀者朋友可以查看dotenv 源碼[7]。
7. 總結
鑒于文章不宜過長,文章只比較深入的分析了 config
函數。parse
函數目前沒有深入分析。
一句話總結 dotenv
庫的原理。用 fs.readFileSync
讀取 .env
文件,并解析文件為鍵值對形式的對象,將最終結果對象遍歷賦值到 process.env
上。
我們也可以不看 dotenv
源碼,根據 api
倒推,自己來實現這樣的功能。最終看看和 ?dotenv
源碼本身有什么差別。這樣也許更能鍛煉自己。或者用 ts
重構它。
本文同時也給我們啟發:圍繞工作常用的技術包和庫值得深入學習,做到知其然,知其所以然。
值得一提的是:dotenv
源碼使用的是 flow
類型。vue2 源碼也是用的 flow
。vue3 源碼改用 ts
了。
最后可以持續關注我@若川。歡迎加我微信 ruochuan12 交流,參與 源碼共讀 活動,每周大家一起學習200行左右的源碼,共同進步。
參考資料
[1]
本文倉庫 https://github.com/lxchuan12/dotenv-analysis.git,求個star^_^: https://github.com/lxchuan12/dotenv-analysis.git
[2]dotenv 主文件僅118行: https://github.com/motdotla/dotenv/blob/master/lib/main.js
[3]dotenv: https://github.com/motdotla/dotenv
[4]dotenv-expand: https://github.com/motdotla/dotenv-expand
[5]vue-cli .env: https://cli.vuejs.org/zh/guide/mode-and-env.html#%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F
[6]create-react-app .env: https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used
[7]dotenv 源碼: https://github.com/motdotla/dotenv/blob/master/lib/main.js
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
識別上方二維碼加我微信、拉你進源碼共讀群
今日話題
略。分享、收藏、點贊、在看我的文章就是對我最大的支持~