面试官:项目中常用的 .env 文件原理是什么?如何实现?

1. 前言

大家好,我是若川。持续组织了5个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。

本文仓库 https://github.com/lxchuan12/dotenv-analysis.git,求个star^_^[1]

源码共读活动

每周一期,已进行到19期。于是搜寻各种值得我们学习,且代码行数不多的源码。dotenv 主文件仅118行[2],非常值得我们学习。

阅读本文,你将学到:

1. 学会 dotenv 原理和实现
2. 学会使用 fs模块 获取文件并解析
3. 等等

2. 环境准备

# 推荐克隆我的项目,保证与文章同步
git clone https://github.com/lxchuan12/dotenv-analysis.git
# npm i -g yarn
cd dotenv-analysis/dotenv && yarn i
# VSCode 直接打开当前项目
# code .
# 我写的例子都在 examples 这个文件夹中,可以启动服务本地查看调试
# 在 dotenv-analysis 目录下
node examples/index.js# 或者克隆官方项目
git clone https://github.com/motdotla/dotenv.git
# npm i -g yarn
cd dotenv && yarn i
# VSCode 直接打开当前项目
# code .

如果需要对源码进行调试,可以看我的这篇文章:新手向:前端程序员必学基本技能——调试JS代码,这里就不再赘述了。

3. dotenv 的作用

dotenv[3]

Dotenv 是一个零依赖模块,可将 .env 文件中的环境变量加载到 process.env 中。

如果需要使用变量,则配合如下扩展包使用。

dotenv-expand[4]

众所周知,.env 文件在我们项目中非常常见,在 vue-clicreate-react-app 中都有使用。

vue-cli .env[5]

create-react-app .env[6]

4. .env 文件使用

我们项目中经常会用到.env 文件写法:

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

单从这个文件来看,我们可以知道有如下功能需要实现:

  1. 读取 .env 文件

  2. 解析 .env 文件拆成键值对的对象形式

  3. 赋值到 process.env 上

  4. 最后返回解析后得到的对象

5. 简单实现

根据分析问题,我们最终可以简单把代码实现如下:

const fs = require('fs');
const path = require('path');const parse = function parse(src){const obj = {};// 用换行符 分割// 比如/*** NAME=若川* AGE=18* MP_WEIXIN=若川视野* BLOG=https://lxchuan12.gitee.io* ACTIVITY=每周一起学200行左右的源码共读活动* WEIXIN=加我微信 ruochuan12 参与*/src.toString().split('\n').forEach(function(line, index){// 用等号分割const keyValueArr = line.split('=');// NAMEkey = keyValueArr[0];// 若川val = keyValueArr[1] || '';obj[key] = val;});// { NAME: '若川', ... }return obj;
}const config = function(){// 读取 node 执行的当前路径下的 .env 文件let dotenvPath = path.resolve(process.cwd(), '.env');// 按 utf-8 解析文件,得到对象// { NAME: '若川', ... }const parsed = parse(fs.readFileSync(dotenvPath, 'utf-8'));// 键值对形式赋值到 process.env 变量上,原先存在的不赋值Object.keys(parsed).forEach(function(key){if(!Object.prototype.hasOwnProperty.call(process.env, key)){process.env[key] = parsed[key];}});// 返回对象return parsed;
};console.log(config());
console.log(process.env);// 导出 config parse 函数
module.exports.config = config;
module.exports.parse = parse;

6. 继续完善 config 函数

简版的 config 函数还缺失挺多功能,比如:

可由用户自定义路径
可由用户自定义解析编码规则
添加 debug 模式
完善报错输出,用户写的 env 文件自由度比较大,所以需要容错机制。

根据功能,我们很容易实现以下代码:

function resolveHome (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');// utf8let encoding = 'utf8';// debug 模式,输出提示等信息let debug = false;// 对象if (options) {if (options.path != null) {// 解析路径dotenvPath = resolveHome(options.path)}// 使用配置的编码方式if (options.encoding != null) {encoding = options.encoding}// 有配置就设置为 trueif (options.debug != null) {debug = true}}try {// 按 utf-8 解析文件,得到对象// { NAME: '若川', ... }// debug 传递给 parse 函数 便于const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug });// 键值对形式赋值到 process.env 变量上,原先存在的不赋值Object.keys(parsed).forEach(function(key){if(!Object.prototype.hasOwnProperty.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 };}
};

dotenv 源码中,parse 函数主要是一些正则和单双引号、跨平台等细致处理。这里就暂时不阐述,读者朋友可以查看dotenv 源码[7]

7. 总结

鉴于文章不宜过长,文章只比较深入的分析了 config 函数。parse 函数目前没有深入分析。

一句话总结 dotenv 库的原理。fs.readFileSync 读取 .env 文件,并解析文件为键值对形式的对象,将最终结果对象遍历赋值到 process.env

我们也可以不看 dotenv 源码,根据 api 倒推,自己来实现这样的功能。最终看看和  dotenv 源码本身有什么差别。这样也许更能锻炼自己。或者用 ts 重构它。

本文同时也给我们启发:围绕工作常用的技术包和库值得深入学习,做到知其然,知其所以然

值得一提的是:dotenv 源码使用的是 flow 类型。vue2 源码也是用的 flow。vue3 源码改用 ts了。

最后可以持续关注我@若川。欢迎加我微信 ruochuan12 交流,参与 源码共读 活动,每周大家一起学习200行左右的源码,共同进步。

参考资料

[1]

本文仓库 https://github.com/lxchuan12/dotenv-analysis.git,求个star^_^: https://github.com/lxchuan12/dotenv-analysis.git

[2]

dotenv 主文件仅118行: https://github.com/motdotla/dotenv/blob/master/lib/main.js

[3]

dotenv: https://github.com/motdotla/dotenv

[4]

dotenv-expand: https://github.com/motdotla/dotenv-expand

[5]

vue-cli .env: https://cli.vuejs.org/zh/guide/mode-and-env.html#%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F

[6]

create-react-app .env: https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used

[7]

dotenv 源码: https://github.com/motdotla/dotenv/blob/master/lib/main.js


5ebb88e7842f5ce29ac366751857a03a.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,最近组织了源码共读活动,帮助3000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

325f75f3e76e1c1353e4ce2c3cfa2731.png

识别方二维码加我微信、拉你进源码共读

今日话题

略。分享、收藏、点赞、在看我的文章就是对我最大的支持~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275046.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

梯度下降法和随机梯度下降法

1. 梯度 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。比如函数f(x,y), 分别对x,y求偏导数,求得的梯度向量就是(∂f/∂x, ∂f/∂y)T,简称grad f(x,y)或者▽f(x,y)。对于在点(x…

一张图看程序媛阿源的2021个人年度流水账

大家好,我是若川。持续组织了5个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。本文来自读者阿源小…

案例研究:设计与方法_如何进行1小时的重新设计(案例研究)

案例研究:设计与方法速度设计简介 (Intro to Speed Designing) I’ve been an advocate of speed redesigning technique for a while. The idea is simple — decrease the hand-eye lag and make super quick decisions, seemingly without thinking. The logic behind it is…

图文并茂重新认识下递归

大家好,我是若川。持续组织了5个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。对于大部分前端(包…

unity 全息交互ui_UI向3D投影全息界面的连续发展

unity 全息交互uiThe user interface has been natural in its evolution and strategically heading towards the 3D-projection holographic interface (3D-PHI) era.用户界面在其发展过程中一直很自然,并且在战略上正朝着3D投影全息界面( 3D-PHI )时代迈进。 Si…

前端构建新世代,Esbuild 原来还能这么玩!

大家好,我是若川。持续组织了5个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。今天分享一篇esbui…

平面设计师和ui设计师_平面设计师为什么要享受所有乐趣?

平面设计师和ui设计师Graphic designers are pretty cool. We have to admit that. Be it their dressing style, their attitude and most importantly their enviable gadgets. Large Mac monitor, wacom tablet, drawing sets, swatchbooks , iPad pro with pencil, humungo…

web表单设计:点石成金_设计复杂的用户表单:12个UX最佳实践

web表单设计:点石成金It’s been a few years that I’ve been taking interest in designing complex user forms, where a lot of information is requested from users. Here are a few industries where you regularly find such flows:几年来,我一直对设计复杂…

跨平台开发框架到底哪家强?5款主流框架横向对比!

跨平台开发框架到底哪家强?目前市场上有多个专业做跨平台开发的框架,那么对开发者来说究竟哪一个框架更符合自己的需求呢?笔者特地总结对比了一下不同框架的特性。国内外笔者选择了一共5个主流的测评对象,分别是RN,Flu…

c#创建web应用程序_创建Web应用程序图标集的6个步骤

c#创建web应用程序I am not great at creating logos or icons, mainly because of the lack of practice. So when I was tasked to create an unique icon set for our web app, I wasn’t confident that things will turn out right. After researching effective and rele…

基于pnpm + lerna + typescript的最佳项目实践 - 理论篇

本文来自作者金虹桥程序员 投稿原文链接:https://juejin.cn/post/7043998041786810398本系列文章分为两篇:理论篇和实践篇 理论篇:介绍pnpm(pnpm的特点、解决的问题等)、lerna(lerna的常用命令)…

nginx 多进程 + io多路复用 实现高并发

一、nginx 高并发原理 简单介绍:nginx 采用的是多进程(单线程) io多路复用(epoll)模型 实现高并发 二、nginx 多进程 启动nginx解析初始化配置文件后会 创建(fork)一个master进程 之后 这个进程会退出 master 进程会…

ux设计工具_UX设计中的工具和实用主义

ux设计工具There’s a zillion tools for User Experience and User Interface Design. Don’t take my word for it: a simple Google search for “what are the best tools for wireframing” (to take just one aspect of UX) leads you to endless pages of “The 20 best…

幕后常驻嘉宾配音小姐姐的2021年度总结

大家好,我是若川。这是公众号幕后常驻嘉宾配音小姐姐,看完了上一个阿源小姐姐的年度总结《一张图看程序媛阿源的2021个人年度流水账》,写的年度总结投稿。点击以下音频可以查看收听往期更多音频。以下是正文~Hi,大家好呀~我是若川…

结果规格化_结果

结果规格化If you’ve seen an Instagram story involving a question and people tilting their heads, you probably were looking at the “Who Is More” Instagram filter. In this article, I will share the creative process and decision making behind this filter.如…

2021 年 JavaScript 大事记

大家好,我是 ConardLi,不知不觉中,2021 年已经接近尾声了,不知道在 2021 这一年,你收获了什么?又失去了什么呢?又到了开始做年终总结的时候了,今天,我来给 JavaScript 做…

动画 制作_您希望制作的10个醒目的徽标动画

动画 制作重点 (Top highlight)标志设计 (Logo Design) Have you ever watched paint dry? No? I didn’t think so. How about watched a turtle crossing the road? Probably not. Maybe spent an hour standing in line at the post office? Well that’s pretty likely…

使用 CSS 用户选择控制选择

IE10 平台预览 4 包括一个新的 CSS 属性的支持-ms-user-select,这使得 Web 开发者控制完全可以选择什么的文本,在其网站上更容易。如果你是看我一整天都在我的工作站,您会注意到我读计算机上时,我选择的文本。我不是只有一个人读起…

一个在校的普通前端小姐姐的2021

大家好,我是若川。这是我的源码共读群里一个大三的前端小姐姐(小曹同学)的年度总结。她写了5篇源码笔记。同时做了很多项目,获得了很多奖。而且策划和建立了学校工作室的前端训练营,40人报名参加。总之就是现在的大学生…

按钮 交互_SwiftUI中的微交互—菜单按钮动画

按钮 交互Microinteractions have become increasingly important in a world with a dizzying number of digital platforms and an ocean of content. While microinteractions used to be considered an interesting resource in the early days of digital design, in toda…