项目中常用的.env文件原理源码解析
前言
dotenv
是一个用于加载环境变量的库,在 Node.js 应用程序中可以使用它来简化对环境变量的访问。在日常开发中起到了很重要的作用。
学习目标:
- 学会 dotenv 原理和实现
- 学会使用 fs模块 获取文件并解析
资源:
源码地址:dotenv
如何使用
使用 dotenv
库,可以在应用程序中创建一个名为 .env
的文件,并在该文件中存储环境变量。然后,可以使用 dotenv
库将这些变量加载到 Node.js 应用程序中。
例如,您可以在 .env
文件中存储以下内容:
DB_HOST=localhost
DB_USERNAME=user
DB_PASSWORD=password
使用以下代码将这些变量加载到应用程序中:
require('dotenv').config();
const dbHost = process.env.DB_HOST;
const dbUsername = process.env.DB_USERNAME;
const dbPassword = process.env.DB_PASSWORD;
源码解析
阅读源码之前,可以猜测 dotenv 所做的工作有如下几点。
- 读取 .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)
if (options) {
if (options.path != null) {
dotenvPath = _resolveHome(options.path)
}
if (options.encoding != null) {
encoding = options.encoding
}
}
}
代码中定义了一个变量 dotenvPath
,并将其赋值为使用 path.resolve
函数处理后的路径。
path.resolve
函数会从右到左依次遍历参数,并返回一个绝对路径。函数的第一个参数是 process.cwd
,它返回 Node.js 进程的当前工作目录。第二个参数是字符串 '.env',它表示要在当前工作目录中查找的文件名。
之后会进行一些参数的判断,如果参数中有path这个变量,则使用_resolveHome函数处理:
function _resolveHome (envPath) {
return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath
}
os.homedir
函数返回当前用户的主目录路径。
_resolveHome 函数可用于将以波浪号开头的路径解析为主目录的实际路径。例如,如果 envPath
等于 '~/documents/file.txt',则函数将返回 '/home/user/documents/file.txt'(在基于 Unix 的系统上)或 'C:\Users\user\documents\file.txt'(在 Windows 上)。
解析文件
// 使用 `fs.readFileSync` 函数以指定的编码方式从文件系统中读取文件内容
const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }))
// 解析文件
function parse (class="lazy" data-src) {
const obj = {}
// 转为string类型
let lines = class="lazy" data-src.toString()
// 将换行符转换为相同的格式
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
来匹配字符串 lines
中的内容。
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
这个正则表达式的目的是匹配类似于环境变量的行。它可以匹配以下格式的行:
VARNAME=value
VARNAME: value
export VARNAME=value
export VARNAME: value
最后会返回一个包含所有变量的对象。
赋值操作
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 }
}
拿到解析后的对象,使用 Object.keys(parsed)
获取所有的键,然后使用forEach循环将所有的键添加到process.env 中。
总结
dotenv 的功能用一句话来概括就是:解析env文件将其变量添加到process.env中,其中解析部分主要是使用了正则表达式来匹配4种格式的键值对。
以上就是项目中常用的 .env 文件原理源码解析的详细内容,更多关于.env 文件原理的资料请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341