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