process.env环境变量动态替换方案踩坑记录
前言
今天早上阅读几年前写的一段代码时,突然对其是否生效产生了怀疑,这段代码如下:
令我困惑的是:这里动态获取 process.env
上的属性是否生效?
先说结论:
这个项目使用的是 react@16.13
,采用基于 webpack
的 react-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
写法
经过 webpack 编译打包后的代码如下,其中 process.env.REACT_APP_APPID
被替换成了一个确定的字符串
直接打印 process.env
编译打包后代码中的 process.env
被替换成了一个对象
如果使用动态属性取值呢
编译打包后代码中的 process.env
被替换成了一个对象,同时动态取值的写法也被转换了
经过上面这几种情况的验证,已初步证明 process.env
环境变量支持常规写法、动态取值写法、解构写法。
为了排除这个 react 项目特殊性的原因,下面使用了一个 vue2 的项目经验验证,还是使用 webpack。
2.vue 项目
直接打印 process.env
编译打包后代码中的 process.env
同样被替换成了一个对象
使用 process.env.XXX
写法
其中 process.env.VUE_APP_VERSION_SHOW
被替换成了一个确定的字符串
使用动态属性取值
process.env
同样被替换成了一个对象,同时动态取值的写法也被转换了
3.结论
这里我验证用的 react、vue 项目对于 process.env
的环境取值的编译时替换技术的处理逻辑是一致的与 react 还是 vue 框架无关。
猜测可能与项目采用的构建打包工具 webpack、rollup、parcel 还是 vite 有关。
DefinePlugin
尝试验证
在 webpack 构建工具中处理环境变量编译时替换是用的 webpack.DefinePlugin
插件,使用代码验证跟踪如下
使用的是 webpack@4.46.0
webpack.config.js
配置文件
源码
打包编译结果及执行结果
与上面 vue 项目中验证结果对比发现纯粹使用 webpack.DefinePlugin
有如下限制:
- 源码中 process.env 不能被插件正确替换
- 源码 process.env[XXX] 动态取值写法不能被插件替换
- 源码对 process.env 的解构写法不能被插件替换
综上,上面 webpack.DefinePlugin
验证的结果说明文章开头我对 webpack 项目中环境变量的动态替换规的困惑和记忆中的写法是对的,那 “这里动态获取 process.env
上的属性是否生效?” 是怎么一回事呢?🤔🤔🤔。
新写法验证
于是继续翻阅 webpack.DefindPlugin 官方文档,直到发现这段话
可能是插件的用法和 react、vue 脚手架中的用法不一致,于是修改 webpack.config.js
继续验证
打包编译结果及执行结果
可见,这个验证结果与文章开头 react、vue 项目中遇到的编译后结果完全一致。
环境变量替换过程
这里我还进一步分析了 react、vue 项目中环境变量在编译时替换的具体过程,如下:
这里 react、vue 项目的构建都是以 webpack 为例,vite 等其他构建工具不同
-
构建命令:create-react-app 或 @vue/cli 构建命令执行
-
解析配置:根据命令参数解析本地 .env.test / .env.prod 文件
-
读取配置:dotenv 读取本地 .env 配置文件
-
挂载:将解析结果挂到 proces.env 对象上
-
传入插件:process.env 对象被传入 webpack.DefindPlugin 插件
-
替换:webpack.DefindPlugin 插件替换源码中的环境变量相关代码
总结
关于前端项目的环境变量替换问题,这其实属于是一个项目工程化的问题,在以 webpack 为基础的构建工具项目中基本都是采用 webpack.DefinePlugin
和 dotenv 这一完整成熟的方案。
经过一系列的代码测试验证和重新翻阅文档,总算是对开头我的困惑进行了一个解答。
另外,也让我对这个环境变量动态替换方案的细节有了更深的认识。
参考资料
转载自:https://juejin.cn/post/7197881494261907493