粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • devlearn

    • 开发教程
    • 实践:利用ArrayBuffer实现预览指定目录下的所有文件的内容
    • 在linux-deepin上使用deepin-wine5完美运行腾讯会议/QQ/微信等此类应用
    • eslint插件开发教程
    • ServerLess之云函数实践-天气API
    • 移动端阻止弹窗下层页面被滑动
    • 小技巧:for of中获取index
    • Git常用的一些基本操作
    • 向页面注入js实现为图片和文字元素添加透明蒙层
    • 实践:使用jsencrypt配合axios实现非对称加密传输的数据
    • 封装dotenv库实现类似Vite加载环境变量的行为
    • 30行代码实现合并指定目录下的所有文件的内容
    • 马上中秋了,把鼠标指针变为小玉兔
    • Node中require与fs.readFile读取JSON文件的对比
    • 使用免费的七牛云OSS(10G)搭建个人的在线图床
    • 分享封装的一些七牛云OSS操作方法
    • 本地配置SSH免密远程登录服务器
    • 工具方法汇总
    • 腾讯云Serverless实践-Node.js服务部署
    • 腾讯云Serverless实践-静态网站托管
    • 为什么'\x1B'.length === 1?\x与\u知识延伸
    • Vite插件开发纪实:vite-plugin-monitor(上)
    • Vite插件开发纪实:vite-plugin-monitor(中)
    • Vite插件开发纪实:vite-plugin-monitor(下)
    • 解决Vite-React项目中js使用jsx语法报错的问题
    • webpack 项目接入Vite的通用方案介绍
    • webpack 项目接入Vite的通用方案介绍-草稿
    • 优雅的处理挂载window上的函数可能不存在的情况
    • Mac上抓包秒通关羊了个羊

封装dotenv库实现类似Vite加载环境变量的行为

vuePress-theme-reco 粥里有勺糖    2018 - 2023

封装dotenv库实现类似Vite加载环境变量的行为

粥里有勺糖 2021-06-20 技术笔记技术教程

# 封装dotenv库实现类似Vite加载环境变量的行为

# dotenv的作用

将.env文件中的环境变量加载到 process.env 中

# 简单使用示例

安装依赖

yarn add dotenv
1

编写 .env 文件

# 数据库相关内容
DB_USER=test
DB_PWD=123456
DB_PORT=3306
1
2
3
4

test.js

const dotenv = require('dotenv')

const res = dotenv.config()

console.log(res);

console.log(process.env.DB_PORT);
1
2
3
4
5
6
7

运行结果

注意.env文件需在项目的根目录中(终端执行指令的目录)

图片

# Vite中读取.env文件的规则

这里直接贴图原文档内容 (opens new window),不做过多赘述

图片

很详细的叙述了Vite加载额外环境变量的规则

# 循序渐进的实现

# 指定存放环境变量文件

  1. 首先通过process.cwd(),获取终端执行命令的路径
console.log(process.cwd())
1

图片

  1. dotenv.config的参数定义
export interface DotenvConfigOptions {
  /**
   * You may specify a custom path if your file containing environment variables is located elsewhere.
   */
  path?: string;

  /**
   * You may specify the encoding of your file containing environment variables.
   */
  encoding?: string;

  /**
   * You may turn on logging to help debug why certain keys or values are not being set as you expect.
   */
  debug?: boolean;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以看出通过path参数指定环境变量的路径

测试代码如下

const dotenv = require('dotenv')
const baseDir = process.cwd()

const res1 = dotenv.config({path:`${baseDir}/.lalala`})
const res2 = dotenv.config({path:`${baseDir}/.lalala2`})
const res3 = dotenv.config({path:`${baseDir}/.不存在`})

console.log(res1);
console.log(res2);
console.log(res3);
console.log(process.env.TEST_ENV);
1
2
3
4
5
6
7
8
9
10
11

输出内容分别如下

{ parsed: { TEST_ENV: 'test1' } }
{ parsed: { TEST_ENV: 'test2' } }
{
  error: 'xxx'
}
test1
1
2
3
4
5
6

可以看出当指定文件存在时,解析的内容会在结果的parsed属性中

不存在时,解析结果只包含错误信息error

当指定了path参数后,执行多个donEnv.config方法,只会自动加载第一个的解析结果到process.env中去

# 加载读取的环境变量

这个步骤简单,直接遍历parsed属性的内容,将其添加到process.env属性上即可

function load(parseEnvObj) {
  const { parsed } = parseEnvObj
  if (parsed && parsed instanceof Object) {
    Object.getOwnPropertyNames(parsed).forEach((k) => {
      process.env[k] = parsed[k]
    })
  }
}
1
2
3
4
5
6
7
8

测试

const baseDir = process.cwd()

const res1 = dotenv.config({ path: `${baseDir}/.lalala` })
const res2 = dotenv.config({ path: `${baseDir}/.lalala2` })
const res3 = dotenv.config({ path: `${baseDir}/.不存在` })

load(res1);
load(res2);
load(res3);
console.log(process.env.TEST_ENV); // test2
1
2
3
4
5
6
7
8
9
10

# 实现Vite的读取规则

function loadEnv() {
    const baseDir = process.cwd()
    // .env
    load(dotenv.config({ path: `${baseDir}/.env` }))
    // .env.local
    load(dotenv.config({ path: `${baseDir}/.env.local` }))
    // .env.[mode]
    load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}` }))
    // .env.[mode].local
    load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}.local` }))
}
1
2
3
4
5
6
7
8
9
10
11

简单封装成一个函数,直接调用loadEnv

mode的设置可以通过cross-env (opens new window)库设置,如下所示

package.json

{
    "scripts": {
        "dev": "cross-env NODE_ENV=development node ./tests/test.js",
    },
}
1
2
3
4
5

# 限制环境变量前缀

简单修改后的代码,添加了前缀的过滤

function load(parseEnvObj, prefix = '') {
    const { parsed } = parseEnvObj
    if (parsed && parsed instanceof Object) {
        Object.getOwnPropertyNames(parsed).forEach((k) => {
            if (k.indexOf(prefix) === 0) {
                process.env[k] = parsed[k]
            }else{
                process.env[k] = undefined
            }
        })
    }
}
function loadEnv(options = {}) {
    const { prefix = '' } = options
    const baseDir = process.cwd()
    // .env
    load(dotenv.config({ path: `${baseDir}/.env` }), prefix)
    // .env.local
    load(dotenv.config({ path: `${baseDir}/.env.local` }), prefix)
    // .env.[mode]
    load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}` }), prefix)
    // .env.[mode].local
    load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}.local` }), prefix)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

测试

.env内容

# 数据库相关内容
DB_USER=test
DB_PWD=123456
DB_PORT=3306

SUGAR_USER=sugar
1
2
3
4
5
6
loadEnv()
console.log(process.env.DB_USER); // test
console.log(process.env.SUGAR_USER); // sugar
1
2
3
loadEnv({prefix:'SUGAR'})
console.log(process.env.DB_USER); // undefined
console.log(process.env.SUGAR_USER); // sugar
1
2
3

# 最终版

// 读取配置的环境变量
const dotenv = require('dotenv')

function load(parseEnvObj, prefix = '') {
  const { parsed } = parseEnvObj
  if (parsed && parsed instanceof Object) {
      Object.getOwnPropertyNames(parsed).forEach((k) => {
          if (k.indexOf(prefix) === 0) {
              process.env[k] = parsed[k]
          }else{
              process.env[k] = undefined
          }
      })
  }
}
function loadEnv(options = {}) {
  const { prefix = '' } = options
  const baseDir = process.cwd()
  // .env
  load(dotenv.config({ path: `${baseDir}/.env` }), prefix)
  // .env.local
  load(dotenv.config({ path: `${baseDir}/.env.local` }), prefix)
  // .env.[mode]
  load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}` }), prefix)
  // .env.[mode].local
  load(dotenv.config({ path: `${baseDir}/.env.${process.env.NODE_ENV}.local` }), prefix)
}

module.exports = loadEnv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 使用

const loadEnv = require('modulePath')
loadEnv()
// or
loadEnv({prefix:'xx'})
1
2
3
4

# TODO

下一次分享一下Vite中这部分的源码实现逻辑

Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34