使用create-react-app创建的单页应用(SPA)是在build时注入环境变量的。一旦build成静态文件便不能动态提供环境变量了。
比如build一个单页应用的docker image,可以在build时提供环境变量。但是已经build完成,使用docker run运行的时候不能再传递环境变量。
本文主要解决在运行时提供环境变量的问题。
原理:通过一段shell脚本将指定将env转换为config.js文件,该文件和build好的static文件serve在同一目录下,在应用中引用config.js文件,通过window._env获取环境变量。shell脚本通过docker image的entrypoint执行。服务使用go构建的一个简单服务器,比nginx轻量很多。
- 将如下
env.sh
文件拷问到项目目录下,在entrypoint(docker run)时执行,作用是将环境变量转出config.js
#!/bin/sh
if [ $CONFIG_VARS ]; then
# clear
echo -n > ${CONFIG_FILE_PATH}/config.js
SPLIT=$(echo $CONFIG_VARS | tr "," "\n")
echo "window._env = {" >> ${CONFIG_FILE_PATH}/config.js
for VAR in ${SPLIT}; do
VALUE=$(printenv ${VAR})
echo " ${VAR}: \"${VALUE}\"," >> ${CONFIG_FILE_PATH}/config.js
done
echo "}" >> ${CONFIG_FILE_PATH}/config.js
fi
# disable broswer cache
sed -i "s/config.js?v=[0-9]*/config.js?v=$(date +'%s')/g" /srv/http/index.html
# for macOS
# sed -i "" "s/config.js?v=[0-9]*/config.js?v=$(date +'%s')/g" /srv/http/index.html
# exec CMD
exec "$@"
例如
# 传入
CONFIG_VARS=ABC,XYZ
ABC=helloabc
XYZ=HELLOXYZ
# 转换为
window._env = {
ABC: "helloabc",
XYZ: "HELLOXYZ",
}
- 编写Dockerfile,使用goStatic当做静态文件服务器(比nginx轻量)。build完成只有几MB.
FROM node:11 AS builder
COPY . /app
WORKDIR /app
RUN yarn install
RUN yarn run build
FROM wlchn/gostatic:latest
ENV CONFIG_FILE_PATH /srv/http
COPY --from=builder /app/build /srv/http
COPY ./env.sh /env.sh
# Ensure convert envs to window._env
ENTRYPOINT ["sh", "/env.sh"]
# start server. listen on 8043(in container) by default.
CMD ["/goStatic"]
- 在项目中引用config.js
<script type="text/javascript" src="/config.js?v="></script>
- 使用环境变量,通过
window._env
获取
let _env = process.env;
// check if there is env exits in local, otherwise using window._env
if (_env.ENV_ABC) {
_env = window._env;
}
// so you can use env like _env.ENV_ABC
- 转换示例
# pass envs like:
CONFIG_VARS=ABC,XYZ
ABC=helloabc
XYZ=HELLOXYZ
# you coud get config.js
window._env = {
ABC: "helloabc",
XYZ: "HELLOXYZ",
}
# in your app, you can use like
console.log(_env.ABC)
console.log(_env.XYZ)