欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

dotenv源碼解讀從.env文件中讀取環(huán)境變量

 更新時(shí)間:2022年12月25日 09:11:20   作者:田八  
這篇文章主要為大家介紹了dotenv源碼解讀從.env文件中讀取環(huán)境變量示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

dotenv.env文件中讀取環(huán)境變量,然后將其添加到process.env中。這是一個(gè)非常簡(jiǎn)單的庫(kù),但是它在開(kāi)發(fā)中非常有用,因?yàn)樗试S你在.env文件中存儲(chǔ)敏感信息,而不是將其存儲(chǔ)在代碼中。

現(xiàn)在很多庫(kù)都支持.env文件,例如create-react-app,vue-cli,next.js等。

源碼地址:github.com/motdotla/do…

使用

根據(jù)README,dotenv只有兩個(gè)方法:

  • config:讀取.env文件并將其添加到process.env中。
  • parse:解析一段包含環(huán)境變量的字符串或Buffer,并返回一個(gè)對(duì)象。
const dotenv = require('dotenv')
// 讀取.env文件并將其添加到process.env中
dotenv.config()
// 解析一段包含環(huán)境變量的字符串或Buffer,返回一個(gè)對(duì)象
const config1 = dotenv.parse('FOO=bar\nBAR=foo')
console.log(config1) // { FOO: 'bar', BAR: 'foo' }
const buffer = Buffer.from('FOO=bar\nBAR=foo')
const config2 = dotenv.parse(buffer)
console.log(config2) // { FOO: 'bar', BAR: 'foo' }

可以看到,dotenv的使用非常簡(jiǎn)單,通常我們只需要調(diào)用config方法即可。

還有一種方法是預(yù)加載,直接通過(guò)node -r dotenv/config來(lái)運(yùn)行腳本,這樣就不需要在腳本中引入dotenv了。

源碼

源碼在lib/main.js中,先來(lái)看一下全部的代碼:

const fs = require('fs')
const path = require('path')
const os = require('os')
const packageJson = require('../package.json')
const version = packageJson.version
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\'|[^'])*'|\s*"(?:\"|[^"])*"|\s*`(?:\`|[^`])*`|[^#\r\n]+)?\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(/\r\n?/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(/^(['"`])([\s\S]*)\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

可以看到最后導(dǎo)出的是一個(gè)對(duì)象,包含了configparse兩個(gè)方法。

config

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是文件的編碼
  • debugoverride分別表示是否開(kāi)啟調(diào)試模式和是否覆蓋已有的環(huán)境變量。
if (options) {
  if (options.path != null) {
    dotenvPath = _resolveHome(options.path)
  }
  if (options.encoding != null) {
    encoding = options.encoding
  }
}

然后判斷了一下options是否存在,如果存在的話,就會(huì)根據(jù)options的值來(lái)修改dotenvPathencoding的值。

const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }))

然后是調(diào)用parse方法來(lái)解析.env文件,parse方法的實(shí)現(xiàn)在下面會(huì)講到。

這里是只用fs.readFileSync來(lái)讀取.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對(duì)象,然后將其添加到process.env中,如果process.env中已經(jīng)存在了該環(huán)境變量,那么就會(huì)根據(jù)override的值來(lái)決定是否覆蓋。

debug的值表示是否開(kāi)啟調(diào)試模式,如果開(kāi)啟了調(diào)試模式,那么就會(huì)打印一些日志。

最后就是直接返回parsed對(duì)象。

parse

parse方法的作用是解析.env文件,將其轉(zhuǎn)換為一個(gè)對(duì)象。

const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\'|[^'])*'|\s*"(?:\"|[^"])*"|\s*`(?:\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
function parse (src) {
  const obj = {}
  // Convert buffer to string
  let lines = src.toString()
  // Convert line breaks to same format
  lines = lines.replace(/\r\n?/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(/^(['"`])([\s\S]*)\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
}

首先定義了一個(gè)正則表達(dá)式LINE,用來(lái)匹配.env文件中的每一行。

然后是將src轉(zhuǎn)換為字符串,然后將換行符統(tǒng)一為\n

接著就是核心,通過(guò)正則表達(dá)式的特性通過(guò)while循環(huán)來(lái)匹配每一行。

這個(gè)正則著實(shí)有點(diǎn)復(fù)雜,我是正則渣渣,可以在regex101查看一下。

這個(gè)正則上面標(biāo)出了三種顏色,和下面的匹配的值的顏色相互對(duì)應(yīng),然后右邊會(huì)展示匹配的值。

這里我不過(guò)多解讀,可以自己去看一下,然后輸入不同的值對(duì)比一下結(jié)果。

通過(guò)上面的截圖可以看到匹配會(huì)捕獲兩個(gè)值,第一個(gè)是環(huán)境變量的名稱(chēng),第二個(gè)是環(huán)境變量的值。

然后對(duì)值進(jìn)行處理,首先去掉首尾的空格,然后通過(guò)正則去掉首尾的引號(hào),最后再將轉(zhuǎn)義的換行符轉(zhuǎn)換還原。

經(jīng)過(guò)上面的處理,就可以將每一行的環(huán)境變量添加到obj對(duì)象中了,最后返回obj對(duì)象。

總結(jié)

dotenv真的是非常驚艷的一個(gè)庫(kù),沒(méi)有任何依賴(lài),只有一個(gè)文件,而且功能也非常強(qiáng)大。

如果你將README中的內(nèi)容全部看完,你還會(huì)發(fā)現(xiàn)dotenv還有很多其他的功能,都是一些很實(shí)用的功能,并且還有很多引導(dǎo)你如何使用的例子。

以上就是dotenv源碼解讀從.env文件中讀取環(huán)境變量的詳細(xì)內(nèi)容,更多關(guān)于dotenv .env文件讀取環(huán)境變量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論