【若川视野 x 源码共读】第22期 | 项目中常用的 .env 文件原理是什么?如何实现?

137 阅读1分钟

学习链接:juejin.cn/post/708310…

git源码:git clone github.com/motdotla/do…

1、准备

克隆源码后,进入dotenv,读readme.md,按要求新建.env文件,并新建index.js文件,引入config.js文件,

NAME=若川
AGE=18
BLOG=https://lxchuan12.gitee.io
MP_WEIXIN='若川视野'
ACTIVITY="每周一起学200行左右的源码共读活动"
WEIXIN=加我微信 ruochuan12 参与

2、作用

  1. 读取 .env 文件
  2. 解析 .env 文件拆成键值对的对象形式
  3. 赋值到 process.env 上
  4. 最后返回解析后得到的对象

3、源码

1、config.js文件

(function () {
  // console.log("argv", process.argv);
  require("./lib/main").config(
    Object.assign(
      {},
      require("./lib/env-options"),
      require("./lib/cli-options")(process.argv)
    )
  );
})();
//合并options,做为main.js的config函数的参数

1、env-options.js

// ../config.js accepts options via environment variables
const options = {};
if (process.env.DOTENV_CONFIG_ENCODING != null) {
  options.encoding = process.env.DOTENV_CONFIG_ENCODING;
}

if (process.env.DOTENV_CONFIG_PATH != null) {
  options.path = process.env.DOTENV_CONFIG_PATH;
}

if (process.env.DOTENV_CONFIG_DEBUG != null) {
  options.debug = process.env.DOTENV_CONFIG_DEBUG;
}

if (process.env.DOTENV_CONFIG_OVERRIDE != null) {
  options.override = process.env.DOTENV_CONFIG_OVERRIDE;
}

module.exports = options;

2、cli-options.js

const re = /^dotenv_config_(encoding|path|debug|override)=(.+)$/

module.exports = function optionMatcher (args) {
  return args.reduce(function (acc, cur) {
    const matches = cur.match(re)
    if (matches) {
      acc[matches[1]] = matches[2]
    }
    return acc
  }, {})
}

2、main.js

const fs = require("fs");
const path = require("path");
const os = require("os");

const LINE =
  /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\'|[^'])*'|\s*"(?:\"|[^"])*"|\s*`(?:\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;

// Parser src into an Object
function parse(src) {
  const obj = {};
  // Convert buffer to string 将buffer变成字符串
  let lines = src.toString();

// Convert line breaks to same format 格式化字符串

lines = lines.replace(/\r\n?/gm, "\n"); // /r结束符 /n换行符 /gm 全局 m 多行匹配

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/gm,"/gm, "2");

//$2 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本

// 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][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 })

);

console.log("parsed", parsed);

Object.keys(parsed).forEach(function (key) {

//判断key值是否属于process.env

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;

4、感谢

今天笔记写的有点乱 但是按照了自己的理解写的 看了7期源码 很感谢若川老师 不然我可能不会看源码 通过源码学习 了解了一些很高级的内容 我不会去写的代码 有很多感想 但是今天有点忙 哎呀 接着冲 最后真的很感谢若川老师