<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
dotenv
從.env
檔案中讀取環境變數,然後將其新增到process.env
中。這是一個非常簡單的庫,但是它在開發中非常有用,因為它允許你在.env
檔案中儲存敏感資訊,而不是將其儲存在程式碼中。
現在很多庫都支援.env
檔案,例如create-react-app
,vue-cli
,next.js
等。
原始碼地址:github.com/motdotla/do…
根據README
,dotenv
只有兩個方法:
config
:讀取.env
檔案並將其新增到process.env
中。parse
:解析一段包含環境變數的字串或Buffer
,並返回一個物件。const dotenv = require('dotenv') // 讀取.env檔案並將其新增到process.env中 dotenv.config() // 解析一段包含環境變數的字串或Buffer,返回一個物件 const config1 = dotenv.parse('FOO=barnBAR=foo') console.log(config1) // { FOO: 'bar', BAR: 'foo' } const buffer = Buffer.from('FOO=barnBAR=foo') const config2 = dotenv.parse(buffer) console.log(config2) // { FOO: 'bar', BAR: 'foo' }
可以看到,dotenv
的使用非常簡單,通常我們只需要呼叫config
方法即可。
還有一種方法是預載入,直接通過node -r dotenv/config
來執行指令碼,這樣就不需要在指令碼中引入dotenv
了。
原始碼在lib/main.js
中,先來看一下全部的程式碼:
const fs = require('fs') const path = require('path') const os = require('os') const packageJson = require('../package.json') const version = packageJson.version const LINE = /(?:^|^)s*(?:exports+)?([w.-]+)(?:s*=s*?|:s+?)(s*'(?:'|[^'])*'|s*"(?:"|[^"])*"|s*`(?:`|[^`])*`|[^#rn]+)?s*(?:#.*)?(?:$|$)/mg // Parser src into an Object function parse (src) { const obj = {} // Convert buffer to string let lines = src.toString() // Convert line breaks to same format lines = lines.replace(/rn?/mg, 'n') let match while ((match = LINE.exec(lines)) != null) { const key = match[1] // Default undefined or null to empty string let value = (match[2] || '') // Remove whitespace value = value.trim() // Check if double quoted const maybeQuote = value[0] // Remove surrounding quotes value = value.replace(/^(['"`])([sS]*)1$/mg, '$2') // Expand newlines if double quoted if (maybeQuote === '"') { value = value.replace(/n/g, 'n') value = value.replace(/r/g, 'r') } // Add to object obj[key] = value } return obj } function _log (message) { console.log(`[dotenv@${version}][DEBUG] ${message}`) } function _resolveHome (envPath) { return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath } // Populates process.env from .env file function config (options) { let dotenvPath = path.resolve(process.cwd(), '.env') let encoding = 'utf8' const debug = Boolean(options && options.debug) const override = Boolean(options && options.override) if (options) { if (options.path != null) { dotenvPath = _resolveHome(options.path) } if (options.encoding != null) { encoding = options.encoding } } try { // Specifying an encoding returns a string instead of a buffer const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding })) Object.keys(parsed).forEach(function (key) { if (!Object.prototype.hasOwnProperty.call(process.env, key)) { process.env[key] = parsed[key] } else { if (override === true) { process.env[key] = parsed[key] } if (debug) { if (override === true) { _log(`"${key}" is already defined in `process.env` and WAS overwritten`) } else { _log(`"${key}" is already defined in `process.env` and was NOT overwritten`) } } } }) return { parsed } } catch (e) { if (debug) { _log(`Failed to load ${dotenvPath} ${e.message}`) } return { error: e } } } const DotenvModule = { config, parse } module.exports.config = DotenvModule.config module.exports.parse = DotenvModule.parse module.exports = DotenvModule
可以看到最後匯出的是一個物件,包含了config
和parse
兩個方法。
config
方法的作用是讀取.env
檔案,並將其新增到process.env
中。
function config (options) { let dotenvPath = path.resolve(process.cwd(), '.env') let encoding = 'utf8' const debug = Boolean(options && options.debug) const override = Boolean(options && options.override) }
首先定義了一些變數:
dotenvPath
是.env
檔案的路徑encoding
是檔案的編碼debug
和override
分別表示是否開啟偵錯模式和是否覆蓋已有的環境變數。if (options) { if (options.path != null) { dotenvPath = _resolveHome(options.path) } if (options.encoding != null) { encoding = options.encoding } }
然後判斷了一下options
是否存在,如果存在的話,就會根據options
的值來修改dotenvPath
和encoding
的值。
const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }))
然後是呼叫parse
方法來解析.env
檔案,parse
方法的實現在下面會講到。
這裡是只用fs.readFileSync
來讀取.env
檔案,然後將其傳入parse
方法中,接著往下:
Object.keys(parsed).forEach(function (key) { if (!Object.prototype.hasOwnProperty.call(process.env, key)) { process.env[key] = parsed[key] } else { if (override === true) { process.env[key] = parsed[key] } if (debug) { if (override === true) { _log(`"${key}" is already defined in `process.env` and WAS overwritten`) } else { _log(`"${key}" is already defined in `process.env` and was NOT overwritten`) } } } })
這裡是遍歷parsed
物件,然後將其新增到process.env
中,如果process.env
中已經存在了該環境變數,那麼就會根據override
的值來決定是否覆蓋。
debug
的值表示是否開啟偵錯模式,如果開啟了偵錯模式,那麼就會列印一些紀錄檔。
最後就是直接返回parsed
物件。
parse
方法的作用是解析.env
檔案,將其轉換為一個物件。
const LINE = /(?:^|^)s*(?:exports+)?([w.-]+)(?:s*=s*?|:s+?)(s*'(?:'|[^'])*'|s*"(?:"|[^"])*"|s*`(?:`|[^`])*`|[^#rn]+)?s*(?:#.*)?(?:$|$)/mg function parse (src) { const obj = {} // Convert buffer to string let lines = src.toString() // Convert line breaks to same format lines = lines.replace(/rn?/mg, 'n') let match while ((match = LINE.exec(lines)) != null) { const key = match[1] // Default undefined or null to empty string let value = (match[2] || '') // Remove whitespace value = value.trim() // Check if double quoted const maybeQuote = value[0] // Remove surrounding quotes value = value.replace(/^(['"`])([sS]*)1$/mg, '$2') // Expand newlines if double quoted if (maybeQuote === '"') { value = value.replace(/n/g, 'n') value = value.replace(/r/g, 'r') } // Add to object obj[key] = value } return obj }
首先定義了一個正規表示式LINE
,用來匹配.env
檔案中的每一行。
然後是將src
轉換為字串,然後將換行符統一為n
。
接著就是核心,通過正規表示式的特性通過while
迴圈來匹配每一行。
這個正則著實有點複雜,我是正則渣渣,可以在regex101檢視一下。
這個正則上面標出了三種顏色,和下面的匹配的值的顏色相互對應,然後右邊會展示匹配的值。
這裡我不過多解讀,可以自己去看一下,然後輸入不同的值對比一下結果。
通過上面的截圖可以看到匹配會捕獲兩個值,第一個是環境變數的名稱,第二個是環境變數的值。
然後對值進行處理,首先去掉首尾的空格,然後通過正則去掉首尾的引號,最後再將跳脫的換行符轉換還原。
經過上面的處理,就可以將每一行的環境變數新增到obj
物件中了,最後返回obj
物件。
dotenv
真的是非常驚豔的一個庫,沒有任何依賴,只有一個檔案,而且功能也非常強大。
如果你將README
中的內容全部看完,你還會發現dotenv
還有很多其他的功能,都是一些很實用的功能,並且還有很多引導你如何使用的例子。
以上就是dotenv原始碼解讀從.env檔案中讀取環境變數的詳細內容,更多關於dotenv .env檔案讀取環境變數的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45