前端项目中.env文件如何实现的

前端项目中.env文件,很常见,.env配置项目的环境变量,一般被放在项目的根目录里;在服务配置文件里的process.env对象中就可以获取配置的变量

  • .env配置变量
  //.env
  VUE_APP_DEV_VAR = 'development'
  • 此处vue项目为例
 // vue.config.js
 const VAR = process.env.VUE_APP_VAR
  • 一般我们在vue项目中,无法找到跟.env相关的包文件的,其实我们在vue在项目中node_modules能找到个名叫dotenv这个包的,这个项目的包名被加载到@vue/cli-service中,从加载的路径中,我们可以看到,这个跟node加载有关了;那我们就打开cli-service/lib中找到Service文件
...
const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')
...
class Service{
  ...
   loadEnv (mode) {
  const logger = debug('vue:env')
  const basePath = path.resolve(this.context, `.env${mode ? `.${mode}` : ``}`)
  const localPath = `${basePath}.local`
  const load = envPath => {
    try {
      const env = dotenv.config({ path: envPath, debug: process.env.DEBUG })
      dotenvExpand(env)
      logger(envPath, env)
    } catch (err) {
      // only ignore error if file is not found
      if (err.toString().indexOf('ENOENT') < 0) {
        error(err)
      }
    }
  }
  load(localPath)
  load(basePath)
 ...
}
...
}
  • 从上面代码loadEnv方法可以看出是需要加载环境解析环境目录路径,通过dotenv.config解析出环境变量,拿它是如何解析.env文件和设置到process.env对象中,那我就把他们的源码代码给拉下来,进行进一步分析;
  • dotenv源码分析
  1. 整体看一下项目目录:lib和tests目录,它的核心源码在lib文件中
  • main.js
  • main.d.ts
  • cli-options.js
  • env.options.js
  • package.json
  1. 在package.json中main字段配置的文件是main.js,所以main.js是出口文件,其实在main.js中configparse两个方法
  2. 从上面以@vue/cli-service项目中,就是直接使用dotenv.config方法,那我们就先来分析一config方法
  • 先加载解析.env的文件路径
  • 再判断option/options.pathoptions.encoding是不是存在
  • 不存在加载默认.env路径和utf-8字符编码,存在,采用用户配置的.env.XXX文件路径和字符编码
  • 再通过fs.readFileSync同步读取.env相关的文件内容
  • 再通过parse方法解析文件内容
  • 在根据回车换行进行切割文件内容形成一个数组
const NEWLINES_MATCH = /\r\n|\n|\r/
const lines = src.toString().split(NEWLINES_MATCH)
  • 对切割好的内容数组,进行遍历循环,进行下一步操作,将=赋值的左右两边解析城key和value值,通过正则匹配赋值等式
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*("[^"]*"|'[^']*'|[^#]*)?(\s*|\s*#.*)?$/
for (let idx = 0; idx < lines.length; idx++) {
  let line = lines[idx]
  // matching "KEY' and 'VAL' in 'KEY=VAL'
  const keyValueArr = line.match(RE_INI_KEY_VAL)
}
  • 通过判断正则match好的返回的值,存在,返回的数组的第二个值为key值,第三个为value值
  • 判断是否多行,识别是单引号还是双引号还是没有引号
  • 多行表示字符串如下事例,需要用户配置options字段参数multiline参数为true即可
MULTI_SINGLE_QUOTED='THIS
IS
A
MULTILINE
STRING'
  • 在vue项目中源码可知,vue-cli-server,并没有进行多行配置
  • 多行配置时,需要对字符串进行遍历,进行累加到一起,形成一个变量字符串
  • 不是多行,只需要判断单双引号,进行相应的截取
  • 最后将处理好的val值,存放到字典中,并且返回
  if (keyValueArr != null) {
    const key = keyValueArr[1]
    // default undefined or missing values to empty string
    let val = (keyValueArr[2] || '')
    let end = val.length - 1
    const isDoubleQuoted = val[0] === '"' && val[end] === '"'
    const isSingleQuoted = val[0] === "'" && val[end] === "'"

    const isMultilineDoubleQuoted = val[0] === '"' && val[end] !== '"'
    const isMultilineSingleQuoted = val[0] === "'" && val[end] !== "'"

    // if parsing line breaks and the value starts with a quote
    if (multiline && (isMultilineDoubleQuoted || isMultilineSingleQuoted)) {
      const quoteChar = isMultilineDoubleQuoted ? '"' : "'"

      val = val.substring(1)

      while (idx++ < lines.length - 1) {
        line = lines[idx]
        end = line.length - 1
        if (line[end] === quoteChar) {
          val += NEWLINE + line.substring(0, end)
          break
        }
        val += NEWLINE + line
      }
    // if single or double quoted, remove quotes
    } else if (isSingleQuoted || isDoubleQuoted) {
      val = val.substring(1, end)

      // if double quoted, expand newlines
      if (isDoubleQuoted) {
        val = val.replace(RE_NEWLINES, NEWLINE)
      }
    } else {
      // remove surrounding whitespace
      val = val.trim()
    }

    obj[key] = val
} else if (debug) {
    const trimmedLine = line.trim()

    // ignore empty and commented lines
    if (trimmedLine.length && trimmedLine[0] !== '#') {
      log(`Failed to match key and value when parsing line ${idx + 1}: ${line}`)
    }
}
  • parse解析好的字典值,进行遍历操作,存在到process.env对象
  • 最后只要通过process.env获取对应的变量。
  1. 这就是.env文件解析的整个过程

总结:

  1. 加载解析.env文件路径,判断是用户是否配置的路径和字符编码,不然采用默认值;
  2. 再读取.env文件内容,先通过正则匹配回车换行切割文件内容,后遍历切割好的数组,对切割好的数组进行正则匹配;
  3. 判断用户是否进行多行设置,进行多行设置的内容进行进行循环处理累加成单行字符串,非多行设置,识别一下引号进行截取,替换等操作,最后存放到字典返回;
  4. 处理好的返回值进行遍历,存放到process.env中,最后用户只需要通过process.env获取相应的变量值即可。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值