需求
前端项目的环境变量一般在编译阶段,通过 .env 注入,在编译时就打包好了。但是当前端项目 docker 化后,某些变量只有在 docker 镜像启动时才会注入,此时需要做到一份镜像,随处可用。基于此,就产生了不同的一些方案
方案
- 后端增加配置接口,前端加载页面时请求接口获取配置。缺点是如果配置的接口在另一个域名下就没办法了。
- 接上1,由运维编写脚本,将配置的接口代理到当前域名的某个Path中。例如当前页面域名为 a.com 配置接口在 b.com/xx/config ,则由运维将 a.com/xx/config 代理到 b.com/xx/config 中。
- 前端 docker 启动时修改 public/config.js,在页面加载时请求配置文件,config.js 中将配置挂载到 window.config 中,这样完全无需运维及后端介入,由纯前端处理环境变量注入的问题,也是我们最终使用的方案,
处理过程
项目是 NextJs + react 构建,使用到了 SSR 的特性,所以有些地方会判断 typeof window !== 'undefined'
如果你用其他的架构方式,可以去掉这些判断
编译时的环境变量
.env.example.j2
1 | NEXT_PUBLIC_API=/api/v1 |
NEXT_PUBLIC_API
为静态变量,在运行时也不会变化
NEXT_PUBLIC_URL
为动态变量,运行时会变,所以用 {{}}
包裹
每个公司的注入方式可能不一样,可以询问运维和其他项目的同学,如何获取到环境变量
之后在 docker-compose 中加入
1 | environment: |
运维会编写一份脚本,将 .env.example.j2
用环境变量替换,此时,编译时的环境变量就处理完毕了
动态注入
public 中加入文件
config.js
1 | const config = { |
将 config.js 文件复制一份,命名为 config.example.js
1 | const config = { |
这么做的原因是:
空的 config.js 保证在加载时不会 404,并且留空串方便使用时判断
config.example.js 是我们在替换完里面的变量后覆盖 config.js 用的。
声明类型
types.d.ts
1 | // docker 运行时配置文件 |
目录中添加 entrypoint.sh 脚本文件
1 |
|
使用时的函数
1 | import { GLOBAL_CONFIG } from 'pages/types'; |
dockerfile 添加代码
ENTRYPOINT ["sh", "./entrypoint.sh"]
流程
docker image 启动 ->
运行 entrypoint.sh ->
使用系统环境变量替换 config.example.js ->
将 config.example.js 替换掉 config.js ->
前端加载是请求 config.js ->
判断 config.js 是否为空串,如果为空串则使用 .env 中的变量,如果不为则使用其
结尾
有点小优化,可以在 nginx 中对 config.js 开启协商缓存,这样不怎么影响加载的耗时
该方法除了新增环境变量时会比较繁琐,使用上还是很方便的