如何通过Docker Compose在运行时为React的config.ts动态传环境变量?
解决方案:React应用运行时动态配置API URL(单镜像多环境)
你遇到的核心问题是:REACT_APP_* 这类环境变量是构建阶段被Webpack注入的,一旦打包成Docker镜像,这些值就固定了,没法在运行时修改。要实现单镜像适配多环境,必须把配置逻辑从构建时移到运行时,以下是具体步骤:
1. 重构配置文件,改为运行时读取
修改你的config.ts,让它从全局window对象读取配置(而非构建时的环境变量):
export interface AppConfig { apiUrl: string; } // 从全局变量读取,同时设置默认值兜底 export const config: AppConfig = { apiUrl: (window as any).__APP_CONFIG__?.apiUrl || 'http://default-api.example.com' };
2. 编写容器启动脚本,动态生成配置
创建一个entrypoint.sh脚本,用来在容器启动时根据环境变量生成全局配置脚本:
#!/bin/sh # 生成全局配置脚本,注入到静态文件目录 cat > /usr/share/nginx/html/config.js <<EOF window.__APP_CONFIG__ = { apiUrl: "${API_URL:-http://default-api.example.com}" }; EOF # 启动Nginx服务(假设用Nginx托管静态文件) nginx -g 'daemon off;'
给脚本添加执行权限:
chmod +x entrypoint.sh
3. 调整Dockerfile,打包单镜像
用多阶段构建打包React应用,同时把启动脚本加入镜像:
# 构建阶段:编译React应用 FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . # 这里用默认值构建,运行时会被覆盖 RUN npm run build # 运行阶段:用Nginx托管静态文件 FROM nginx:alpine # 复制编译后的静态文件 COPY --from=builder /app/build /usr/share/nginx/html # 复制启动脚本 COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # 设置容器启动入口 ENTRYPOINT ["/entrypoint.sh"]
4. 用Docker Compose分环境传参
创建不同环境的Compose配置文件,传入对应环境的API URL:
开发环境(docker-compose.dev.yml)
version: '3.8' services: react-app: build: . ports: - "3000:80" environment: - API_URL=http://dev-api.example.com
UAT环境(docker-compose.uat.yml)
version: '3.8' services: react-app: build: . ports: - "3001:80" environment: - API_URL=http://uat-api.example.com
生产环境(docker-compose.prod.yml)
version: '3.8' services: react-app: build: . ports: - "80:80" environment: - API_URL=http://prod-api.example.com
启动对应环境的容器:
# 开发环境 docker-compose -f docker-compose.dev.yml up -d # UAT环境 docker-compose -f docker-compose.uat.yml up -d # 生产环境 docker-compose -f docker-compose.prod.yml up -d
5. 在React应用中使用动态配置
在需要调用API的地方,直接导入config.ts的配置即可:
import { config } from './config'; // 示例:调用API fetch(`${config.apiUrl}/users`) .then(res => res.json()) .then(data => console.log(data));
关键补充:在index.html中引入配置脚本
修改public/index.html,把生成的config.js放在React bundle之前加载,确保全局变量在应用启动前就存在:
<!DOCTYPE html> <html lang="en"> <head> <!-- 其他头部内容 --> <!-- 先加载全局配置脚本 --> <script src="%PUBLIC_URL%/config.js"></script> </head> <body> <div id="root"></div> </body> </html>
这个方案的核心是:容器启动时动态生成全局配置脚本,React应用运行时读取这个脚本的变量,实现了单镜像适配多环境,不需要为每个环境重新构建镜像。
内容的提问来源于stack exchange,提问作者user26582282
相关产品推荐
相关产品推荐

