likes
comments
collection
share

process.env环境变量动态替换方案踩坑记录

作者站长头像
站长
· 阅读数 14

这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

前言

今天早上阅读几年前写的一段代码时,突然对其是否生效产生了怀疑,这段代码如下:

process.env环境变量动态替换方案踩坑记录

令我困惑的是:这里动态获取 process.env 上的属性是否生效?

先说结论:

这个项目使用的是 react@16.13,采用基于 webpackreact-app-rewired 脚手架工具构建,这种动态取值写法是生效的

我的困惑

在我印象中,在项目中使用 process.env 上的环境变量不能使用这种动态取值写法,必须使用下面这种写法

// 我印象中的正确写法
const baseURL = process.env.REACT_APP_XXX_BASICPATH

并且,不能对 process.env 进行解构

// 我印象中的错误写法
const { REACT_APP_XXX_BASICPATH } = process.env

必须用 process.env.REACT_APP_XXX_BASICPATH 这种写法的原因:

webpack 在打包构建项目时,会分析源代码中的 process.env.XXX 所有的这种写法,并且用 webpack 编译时的 process.env 相应的值去替换源代码。

例如:

const baseURL = process.env.REACT_APP_XXX_BASICPATH

webpack 编译替换后的结果:

// 这是示例,实际上代码还会被 webpack 压缩
const baseURL = 'https://xxx.com/xxx/'

代码验证

1.react 项目

使用 process.env.XXX 写法

process.env环境变量动态替换方案踩坑记录

经过 webpack 编译打包后的代码如下,其中 process.env.REACT_APP_APPID 被替换成了一个确定的字符串

process.env环境变量动态替换方案踩坑记录

直接打印 process.env

process.env环境变量动态替换方案踩坑记录

编译打包后代码中的 process.env 被替换成了一个对象

process.env环境变量动态替换方案踩坑记录

如果使用动态属性取值呢

process.env环境变量动态替换方案踩坑记录

编译打包后代码中的 process.env 被替换成了一个对象,同时动态取值的写法也被转换了

process.env环境变量动态替换方案踩坑记录

经过上面这几种情况的验证,已初步证明 process.env 环境变量支持常规写法、动态取值写法、解构写法

为了排除这个 react 项目特殊性的原因,下面使用了一个 vue2 的项目经验验证,还是使用 webpack。

2.vue 项目

直接打印 process.env

process.env环境变量动态替换方案踩坑记录

编译打包后代码中的 process.env 同样被替换成了一个对象

process.env环境变量动态替换方案踩坑记录

使用 process.env.XXX 写法

process.env环境变量动态替换方案踩坑记录

其中 process.env.VUE_APP_VERSION_SHOW 被替换成了一个确定的字符串

process.env环境变量动态替换方案踩坑记录

使用动态属性取值

process.env环境变量动态替换方案踩坑记录

process.env 同样被替换成了一个对象,同时动态取值的写法也被转换了

process.env环境变量动态替换方案踩坑记录

3.结论

这里我验证用的 react、vue 项目对于 process.env 的环境取值的编译时替换技术的处理逻辑是一致的与 react 还是 vue 框架无关。

猜测可能与项目采用的构建打包工具 webpack、rollup、parcel 还是 vite 有关。

DefinePlugin

尝试验证

在 webpack 构建工具中处理环境变量编译时替换是用的 webpack.DefinePlugin 插件,使用代码验证跟踪如下

使用的是 webpack@4.46.0

webpack.config.js 配置文件

process.env环境变量动态替换方案踩坑记录

源码

process.env环境变量动态替换方案踩坑记录

打包编译结果及执行结果

process.env环境变量动态替换方案踩坑记录

与上面 vue 项目中验证结果对比发现纯粹使用 webpack.DefinePlugin 有如下限制:

  1. 源码中 process.env 不能被插件正确替换
  2. 源码 process.env[XXX] 动态取值写法不能被插件替换
  3. 源码对 process.env 的解构写法不能被插件替换

process.env环境变量动态替换方案踩坑记录

综上,上面 webpack.DefinePlugin 验证的结果说明文章开头我对 webpack 项目中环境变量的动态替换规的困惑和记忆中的写法是对的,那 “这里动态获取 process.env 上的属性是否生效?” 是怎么一回事呢?🤔🤔🤔。

新写法验证

于是继续翻阅 webpack.DefindPlugin 官方文档,直到发现这段话

process.env环境变量动态替换方案踩坑记录

可能是插件的用法和 react、vue 脚手架中的用法不一致,于是修改 webpack.config.js 继续验证

process.env环境变量动态替换方案踩坑记录

打包编译结果及执行结果

process.env环境变量动态替换方案踩坑记录

可见,这个验证结果与文章开头 react、vue 项目中遇到的编译后结果完全一致。

环境变量替换过程

这里我还进一步分析了 react、vue 项目中环境变量在编译时替换的具体过程,如下:

这里 react、vue 项目的构建都是以 webpack 为例,vite 等其他构建工具不同

  1. 构建命令:create-react-app 或 @vue/cli 构建命令执行

  2. 解析配置:根据命令参数解析本地 .env.test / .env.prod 文件

  3. 读取配置:dotenv 读取本地 .env 配置文件

  4. 挂载:将解析结果挂到 proces.env 对象上

  5. 传入插件:process.env 对象被传入 webpack.DefindPlugin 插件

  6. 替换:webpack.DefindPlugin 插件替换源码中的环境变量相关代码

总结

关于前端项目的环境变量替换问题,这其实属于是一个项目工程化的问题,在以 webpack 为基础的构建工具项目中基本都是采用 webpack.DefinePlugin 和 dotenv 这一完整成熟的方案。

经过一系列的代码测试验证和重新翻阅文档,总算是对开头我的困惑进行了一个解答。

另外,也让我对这个环境变量动态替换方案的细节有了更深的认识。

参考资料