本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
这是
面试官问系列,链接: juejin.cn/post/704505… 。
环境准备
dotenv的作用
dotenv是一个零依赖模块,可将.env文件中的变量加载到proess.env中。
如果要需要使用变量,则配合以下扩展包使用。
众所周知,.env文件在项目中很常见,vue-cli和create-react-app中都有使用。
.env文件使用
// .env
APP_ENV=PRODUCT
ARTICLE_URL=xxx.com
ARTICLE_NAME='面试官:项目中常用的 .env 文件原理是什么?如何实现?'
从文件来看,我们需要做如下功能需要实现:
- 读取.env文件
- 解析.env文件内容为键值对的对象形式
- 赋值到process.env 上
- 最后返回解析后得到的对象
初版实现
const fs = require('fs')
const path = require('path')
const parse = function parse(src) {
const obj = {}
// 用换行符 分割
// 比如
/**
* APP_ENV=PRODUCT
* ARTICLE_URL=xxx.com
* ARTICLE_NAME='面试官:项目中常用的 .env 文件原理是什么?如何实现?'
**/
src.toStirng().split('\n').forEach(function(line, index) {
// 使用等号分割
const keyValueArr = line.split('=')
// APP_ENV
key = keyValueArr[0];
// PRODUCT
value = keyValueArr[1] || '';
obj[key] = value;
});
// { APP_ENV: 'PRODUCT', ... }
return obj;
}
const config = function() {
// 读取node执行的当前路径的 .env 文件
let dotenvPath = path.resolve(process.cwd(), '.env');
// 按utf-8 解析文件,得到对象
constparsed = parse(fs.readFileSync(dotenvPath, 'utf-8'));
// 键值对形式赋值到process.env 变量上,原先存在的不赋值
Object.keys(parsed).forEach(function(key) {
if (!Object.prototype.hasOwnProperty.call(process.key)) {
process.env[key] = parsed[key];
}
});
// 返回对象
return presed;
};
console.log(config())
console.log(process.env)
// 导出 config & parse 函数
module.exports.config = config;
module.exports.parse = parse;
完善config函数
- 可由用户自定义路径
- 可由用户自定义解析编码规则
- 添加debug模式
- 完善报错容错机制
function resloveHome(envPath) {
return envPath[0] === '~' ? path.join(os.homeDir(), envPath.slice(1)) : envPath
}
const config = function (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) {
dotnevPath = resloveHome(options.path)
}
if (options.encoding !== null) {
encoding = options.encoding
}
if (options.debug !== null) {
debug = true
}
}
try {
// TODO `, { debug }` ?
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }))
// 键值对的形式赋值到 process.env 变量上,原先存在的不赋值
Object.keys(parsed).forEach(function(key) {
if (!Object.prototype.getOwnProperty.call(process.env, key)) {
process.env[key] = parsed[key]
} else if (debug) {
console.log(`"${key}" is already defined in `process.env` and will not be overwritten`)
}
});
// 返回对象
return parsed;
} catch (e) {
return { error: e }
}
}
parse相关源码:dotenv源码
总结
一句话总结dotenv库的原理,用fs.readFileSync读取.env文件,并将文件内容解析为键值对的形式,最终将结果遍历赋值给process.env上。
dotenv源码使用的是flow类型。vue2源码也是用flow,vue3源码改用ts了。
此文章为2024年07月Day1源码共读,生活在阴沟里,也要记得仰望星空。