温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

dotenv怎么从.env文件中读取环境变量

发布时间:2022-12-27 16:22:36 来源:亿速云 阅读:112 作者:iii 栏目:开发技术

这篇文章主要讲解了“dotenv怎么从.env文件中读取环境变量”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“dotenv怎么从.env文件中读取环境变量”吧!

    引言

    dotenv.env文件中读取环境变量,然后将其添加到process.env中。这是一个非常简单的库,但是它在开发中非常有用,因为它允许你在.env文件中存储敏感信息,而不是将其存储在代码中。

    现在很多库都支持.env文件,例如create-react-appvue-clinext.js等。

    使用

    根据READMEdotenv只有两个方法:

    • config:读取.env文件并将其添加到process.env中。

    • parse:解析一段包含环境变量的字符串或Buffer,并返回一个对象。

    const dotenv = require('dotenv')
    // 读取.env文件并将其添加到process.env中
    dotenv.config()
    // 解析一段包含环境变量的字符串或Buffer,返回一个对象
    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的使用非常简单,通常我们只需要调用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*(?: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

    可以看到最后导出的是一个对象,包含了configparse两个方法。

    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分别表示是否开启调试模式和是否覆盖已有的环境变量。

    if (options) {
      if (options.path != null) {
        dotenvPath = _resolveHome(options.path)
      }
      if (options.encoding != null) {
        encoding = options.encoding
      }
    }

    然后判断了一下options是否存在,如果存在的话,就会根据options的值来修改dotenvPathencoding的值。

    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

    parse方法的作用是解析.env文件,将其转换为一个对象。

    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
    }

    首先定义了一个正则表达式LINE,用来匹配.env文件中的每一行。

    然后是将src转换为字符串,然后将换行符统一为\n

    接着就是核心,通过正则表达式的特性通过while循环来匹配每一行。

    这个正则着实有点复杂,我是正则渣渣,可以在regex101查看一下。

    dotenv怎么从.env文件中读取环境变量

    这个正则上面标出了三种颜色,和下面的匹配的值的颜色相互对应,然后右边会展示匹配的值。

    这里我不过多解读,可以自己去看一下,然后输入不同的值对比一下结果。

    通过上面的截图可以看到匹配会捕获两个值,第一个是环境变量的名称,第二个是环境变量的值。

    然后对值进行处理,首先去掉首尾的空格,然后通过正则去掉首尾的引号,最后再将转义的换行符转换还原。

    经过上面的处理,就可以将每一行的环境变量添加到obj对象中了,最后返回obj对象。

    感谢各位的阅读,以上就是“dotenv怎么从.env文件中读取环境变量”的内容了,经过本文的学习后,相信大家对dotenv怎么从.env文件中读取环境变量这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI