React+Vite微前端:无需重建容器,动态管理MFE远程URL
动态管理微前端Remote地址的解决方案
要实现容器应用一次构建、多环境部署,核心思路是把MFE的Remote地址从构建时硬编码改为运行时动态获取,以下是几种实用方案:
方案1:运行时通过全局变量注入环境变量
步骤1:在容器应用的入口HTML中添加占位脚本
修改index.html,加入全局环境变量的占位符,后续部署时用实际环境值替换:
<!DOCTYPE html> <html lang="en"> <head> <!-- 其他头部内容 --> <script> // 定义全局环境变量占位符 window.mfeEnv = { ABC_BASE_URL: '%ABC_BASE_URL%', XYZ_BASE_URL: '%XYZ_BASE_URL%' }; </script> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body> </html>
步骤2:部署时替换占位符
根据部署环境,用脚本或部署工具替换占位符:
- 如果用Docker部署,可以在启动脚本中执行:
sed -i "s/%ABC_BASE_URL%/$ABC_BASE_URL/g" /usr/share/nginx/html/index.html sed -i "s/%XYZ_BASE_URL%/$XYZ_BASE_URL/g" /usr/share/nginx/html/index.html - 如果用Nginx,可以通过
sub_filter模块动态替换:server { location / { sub_filter '%ABC_BASE_URL%' '$env:ABC_BASE_URL'; sub_filter '%XYZ_BASE_URL%' '$env:XYZ_BASE_URL'; sub_filter_once off; root /usr/share/nginx/html; } }
步骤3:动态注册Remote模块
不在vite.config.js中硬编码remotes,而是在应用入口文件中动态注册:
// src/main.jsx import React from 'react'; import ReactDOM from 'react-dom/client'; import { registerRemote } from '@originjs/vite-plugin-federation/src/utils'; import App from './App'; // 从全局变量获取MFE地址 const mfeUrls = { 'fe-mfe-abc': `${window.mfeEnv.ABC_BASE_URL}/assets/remoteEntry.js`, 'fe-mfe-xyz': `${window.mfeEnv.XYZ_BASE_URL}/assets/remoteEntry.js`, }; // 批量注册Remote模块 async function initRemotes() { await Promise.all( Object.entries(mfeUrls).map(([name, entry]) => registerRemote({ name, entry, scope: name, module: './App' // 对应MFE暴露的模块名,按需调整 }) ) ); } // 先初始化Remote,再渲染应用 initRemotes().then(() => { ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode> ); });
方案2:通过静态配置文件动态加载
步骤1:创建配置模板文件
在容器应用的public目录下创建config.template.json:
{ "mfeRemotes": { "fe-mfe-abc": "%ABC_BASE_URL%/assets/remoteEntry.js", "fe-mfe-xyz": "%XYZ_BASE_URL%/assets/remoteEntry.js" } }
步骤2:部署时生成实际配置文件
和方案1类似,部署时替换占位符生成config.json:
cp public/config.template.json public/config.json sed -i "s/%ABC_BASE_URL%/$ABC_BASE_URL/g" public/config.json sed -i "s/%XYZ_BASE_URL%/$XYZ_BASE_URL/g" public/config.json
步骤3:加载配置并注册Remote
在入口文件中fetch配置文件,动态注册模块:
// src/main.jsx import React from 'react'; import ReactDOM from 'react-dom/client'; import { registerRemote } from '@originjs/vite-plugin-federation/src/utils'; import App from './App'; async function initApp() { // 加载配置文件 const configRes = await fetch('/config.json'); const config = await configRes.json(); // 注册Remote模块 await Promise.all( Object.entries(config.mfeRemotes).map(([name, entry]) => registerRemote({ name, entry, scope: name, module: './App' }) ) ); // 渲染应用 ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode> ); } initApp();
方案3:构建产物替换占位符(极简方案)
如果不想修改代码结构,可以直接在vite.config.js中用自定义占位符,构建后替换:
步骤1:配置Vite的remotes占位符
// vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import federation from '@originjs/vite-plugin-federation'; export default defineConfig({ plugins: [ react(), federation({ name: 'container', remotes: { 'fe-mfe-abc': '__ABC_BASE_URL__/assets/remoteEntry.js', 'fe-mfe-xyz': '__XYZ_BASE_URL__/assets/remoteEntry.js', }, shared: ['react', 'react-dom'], }), ], });
步骤2:构建后替换占位符
构建完成后,用脚本替换产物中的占位符:
sed -i "s/__ABC_BASE_URL__/$ABC_BASE_URL/g" dist/assets/*.js sed -i "s/__XYZ_BASE_URL__/$XYZ_BASE_URL/g" dist/assets/*.js
内容的提问来源于stack exchange,提问作者Muhammad Faraz Ali
相关产品推荐
相关产品推荐

