前端 Webpack 项目构建时环境变量
date
Apr 14, 2023
slug
frontend-env
status
Published
summary
tags
前端
type
Post
前端应用程序中可能需要使用环境变量(如API URL)。由于这些变量可能在不同的环境中(甚至不同项目)发生变化,因此我们就需要配置应用程序以在每个环境中调用正确的变量。
举几个场景:
- 开发环境调取开发环境的 URL,测试环境调取测试环境的 URL
- 不同的项目需要走不同的逻辑,例如:A客户需要A逻辑,B客户需要B逻辑;A公司要A样式风格,B公司要B样式风格(此场景比较频繁发生在公有云产品私有部署)。
在没有环境变量之前,我们只能通过不同分支写不同代码来处理,而有了这个环境变量之后,我们就可以通过同一套代码来处理不同的逻辑了。
环境变量
我们在项目根目录中放置下列文件来指定环境变量:
这个模式一般分为2种:
development
模式用于开发环境
production
模式用于生产环境
只在本地有效的变量
有的时候我们可能有一些不应该提交到代码仓库中的变量,尤其是当我们的项目托管在公共仓库时。这种情况下你应该使用一个
.env.local
文件取而代之。本地环境文件默认会被忽略,且出现在 .gitignore
中。.local
也可以加在指定模式的环境文件上,比如 .env.development.local
将会在 development 模式下被载入,且被 git 忽略。使用 `
dotenv
` 库来注入文件:可以注意到,其中有个
PLATFORM_ENV
环境,这里可以通过不同的value来覆盖默认的环境变量。举例我在当前执行命令中配置了 PLATFORM_ENV=companyA
,那么,会首先注入 .env.companyA
文件里配置的环境变量,也就是实现说公司A需要A逻辑,公司B需要B逻辑的需求。特定环境的构建
取不同的 dotenv 文件构建,是根据当前CI服务器所在的环境变量而定的。
比如在 Jenkins环境中注入环境变量来构建不同的产物,或者docker中注入环境变量来构建不同的产物等等。
而本地环境的话,我们也可以通过执行命令的时候来注入变量。
cross-env
解决设置所有系统的环境变量
假设有这么一个
package.json
:在执行
NODE_ENV=production webpack
命令时,Webpack 实际上会使用后面设置的值 production
,而不是继承当前 Node.js 环境中的 NODE_ENV
值。当我们在命令行中设置环境变量时,它会覆盖当前环境中的同名变量。在这个例子中,命令
NODE_ENV=production webpack
设置了环境变量 NODE_ENV
的值为 production
,会覆盖当前 Node.js 环境中的同名变量的值(即如果之前 NODE_ENV
环境变量的值为 Test
,那么它将被覆盖为 production
)。因此,Webpack 将使用后面设置的值
production
作为当前的环境模式,并使用相应的生产环境配置进行打包。在 Mac 以及 Linux 中,执行这个命令并不会报错,然后在大部分 Windows 环境下,会直接出错执行不了。因此需要使用
cross-env
这个库来解决这个问题。如下:
在客户端侧代码中使用环境变量
以上所有环境变量其实只是注入到process.env中了,只是node环境可访问,也就是说我们只能在node执行的脚本中才能使用,比如Webpack的构建等,但是客户端侧代码中是无法使用的。
我们可以通过Webpack的
EnvironmentPlugin
这个插件来注入,考虑到非所有变量都需注册,我们手动指定 REACT_APP_
前缀开头的变量才会被嵌入。接着我们就可以在应用的代码中这样访问它们:
console.log(process.env.REACT_APP_SECRET)
在构建过程中,
process.env.REACT_APP_SECRET
将会被相应的值所取代。在 REACT_APP_SECRET=secret
的情况下,它会被替换为 "secret"
。这里有个很关键的点,是在构建过程中被替换的,如果没有构建过程,则无法访问,会出现
process.env
报错。比如使用 Vite 在开发时,不构建编译JS文件,而是直接访问的话就会报错。最后附上完整代码:
运行时的环境变量
以上的环境均指构建时而非运行时,也就是说只有被node处理完的文件才可以使用这些环境变量(哪怕是客户端侧使用)。如果想在浏览器端运行时也能使用,那就需要统一挂载到window,或者使其成为一个全局变量。
然后在html中引入这个文件。