源码阅读:你应该知道的 .env 的原理

213 阅读2分钟

项目中的 .env 解析的原理,使用 dotenv 解析 .env 文件。

1. dotenv 的功能是什么?

dotenv 是一个零依赖 node 模块,可将 .env 文件中的配置项加载到 process.env 中。

2. dotenv 的使用方式是什么?

在项目的根目录下创建一个 .env 文件,并在其中添加配置项。

name = "lyt"

以这样的方式添加配置项,可以在项目中使用 process.env.name 获取配置项的值。

3. dotenv 的安装方式是什么?

安装方式:npm install dotenv --save

4. dotenv 的使用场景是什么?

在项目中使用 dotenv 来加载 .env 文件中的配置项,可以在项目中使用 process.env.name 获取配置项的值。

可以通过在 dotenv 配置一些全局环境变量。达到简单合适地使用配置项的目的。

5. dotenv 的原理是什么?

使用 node 中的 fs path 模块,即文件系统

fs.readFileSync() 方法读取 .env 文件,并解析文件为键值对形式的对象,将最终结果对象遍历赋值到 process.env 变量上。

const path = require('path');
const fs = require('fs');

function resolveHome(envPath) {
  console.log(envPath);
  return envPath[0] === '~'
    ? path.json(os.join(os.homedir(), envPath.slice(1)))
    : envPath;
}

const parse = function (src) {
  const obj = {};
  let str = src.toString();
  str.split('\n').forEach(function (line, index) {
    // 用等号分割
    const keyValueArr = line.split('=');
    if (keyValueArr.length !== 2) return;
    console.log(keyValueArr, 10);
    // key
    const key = keyValueArr[0].replace(' ', '');
    // value
    const value = keyValueArr[1].replace(' ', '') || '';
    // 存储到obj对象中
    obj[key] = value;
  });
  return obj;
};

function config(options) {
  // 读取 node 执行的当前路径下的 .env 文件
  let dotenvPath = path.resolve(process.cwd(), '.env');
  // utf-8 编码读取文件内容。得到对象
  let encoding = 'utf-8';
  // debug 模式,输出提示信息
  let debug = false;
  // 对象
  if (options) {
    if (options.path != null) {
      // 解析路径
      dotenvPath = resolveHome(options.path);
    }
    // 使用配置的编码方式
    if (options.encoding != null) {
      encoding = options.encoding;
    }
    // 有配置就设置为 true
    if (options.debug != null) {
      debug = true;
    }
  }
  try {
    // 按 utf-8 编码读取文件内容。得到对象
    // { name: 'lyt', age: 24 }
    // debug 传递给 parse 函数,输出提示信息
    const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug });
    // 以键值对形式赋值到 process.env 变量上,原先存在的属性不赋值。
    Object.keys(parsed).forEach((key) => {
      if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
        process.env[key] = parsed[key];
      } else if (debug) {
        console.warn(` ${key} 已经重复了,将不再赋值`);
      }
    });
    return parsed;
  } catch (error) {
    return { error };
  }
}


console.log(config({debug: true}));
console.log(process.env);
// 导出函数
module.exports = config;
module.exports.parse = parse;