如何在Dockerfile中获取Docker环境变量(React/JS/Webpack场景)
嘿,我来帮你理清楚这个问题!你遇到的核心矛盾是:Docker构建阶段(RUN命令执行时),虽然环境变量在容器的env命令和node控制台能看到,但webpack构建时却拿不到。咱们一步步拆解解决:
问题根源分析
首先,你的Dockerfile里用eval env > ./.env来生成.env文件,其实这一步是多余的——因为在Docker的RUN执行阶段,process.env已经能直接获取到通过ARG和ENV设置的变量了。问题出在你的env.js和webpack配置的组合上,另外你可能混淆了构建阶段变量和运行阶段变量的差异。
解决方案步骤
1. 简化Dockerfile,去掉冗余的.env生成
先修改你的Dockerfile,删掉生成.env的步骤,直接让webpack读取构建阶段的process.env:
ARG MY_VAR ENV NODE_ENV production ENV MY_VAR $MY_VAR COPY . . # 直接使用构建阶段的环境变量执行构建,不需要生成.env RUN NODE_ENV=development npm install && \ npm run build && \ npm prune --production
2. 调整env.js,直接读取process.env(无需依赖dotenv)
你的env.js里调用了require('dotenv').config(),这会优先加载本地的.env文件,但在Docker构建阶段,其实我们不需要这个——直接从process.env读取变量更可靠。修改env.js:
// 注释掉dotenv加载,构建阶段不需要它 // require('dotenv').config() // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be // injected into the application via DefinePlugin in Webpack configuration. var REACT_APP = /^REACT_APP_/i; function getClientEnvironment(publicUrl) { var processEnv = Object .keys(process.env) .filter(key => REACT_APP.test(key)) .reduce((env, key) => { env[key] = process.env[key]; return env; }, { 'NODE_ENV': process.env.NODE_ENV || 'development', 'MY_VAR': process.env.MY_VAR // 直接从process.env获取 }); processEnv['process.env'] = Object .keys(processEnv) .reduce((env, key) => { env[key] = JSON.stringify(processEnv[key]); return env; }, {}) return processEnv; } module.exports = getClientEnvironment;
如果本地开发时需要.env文件,你可以加个判断,只在非生产环境加载dotenv:
if (process.env.NODE_ENV !== 'production') { require('dotenv').config(); }
3. 确保webpack正确注入变量
你的webpack配置里已经用了DefinePlugin,这一步是对的——它会把变量替换成静态值注入到代码里,确保React代码能访问到。要注意的是:DefinePlugin注入的是字符串,所以JSON.stringify是必须的,你的env.js已经做了这一步,没问题。
4. 构建时传递ARG变量
当你执行docker build时,需要把MY_VAR传递进去:
docker build --build-arg MY_VAR=your_value_here -t your-image-name .
额外提醒:区分构建时和运行时变量
如果你的变量是运行时才确定的(比如容器启动时才传入),那构建阶段是拿不到的,这种情况你需要用另一种方案:
- 构建时生成一个模板HTML,容器启动时用脚本替换模板里的变量
- 或者在React应用启动时从API获取运行时变量
但从你的描述看,你需要的是构建阶段就能确定的变量,上面的方案完全适用。
内容的提问来源于stack exchange,提问作者jonnyg

