前端微前端架构选型Module Federation 与 qiankun 的对比实践一、微前端的选型焦虑两种范式的根本分歧微前端架构在前端领域已不再是新鲜概念但选型仍然是团队面临的第一道难题。当前主流方案分为两大阵营以 qiankun 为代表的运行时容器方案和以 Module Federation 为代表的构建时联邦方案。某金融科技公司同时使用了两种方案——主应用用 qiankun 集成 3 个旧系统新子系统用 Module Federation 互通——结果维护两套微前端基础设施的成本远超预期。两种方案不是简单的谁更好的关系而是解决不同问题的工具。理解其底层机制差异是做出正确选型的前提。二、两种微前端范式的架构对比flowchart TB subgraph MF[Module Federation 方案] MF_HOST[宿主应用] -- MF_REMOTE[远程模块] MF_REMOTE -- MF_SHARED[共享依赖] MF_SHARED -- MF_VUE[vue3.x] MF_SHARED -- MF_REACT[react18.x] MF_HOST -.-|构建时协商| MF_SHARED end subgraph QK[qiankun 方案] QK_MAIN[主应用] -- QK_SUB1[子应用A: Vue3] QK_MAIN -- QK_SUB2[子应用B: React] QK_MAIN -- QK_SUB3[子应用C: Angular] QK_MAIN -.-|运行时加载| QK_SUB1 QK_MAIN -.-|JS 沙箱| QK_SUB2 QK_MAIN -.-|CSS 隔离| QK_SUB3 end style MF fill:#dfd,stroke:#333 style QK fill:#ffd,stroke:#333核心差异对比维度Module Federationqiankun集成时机构建时运行时隔离机制模块作用域JS 沙箱 CSS 隔离框架限制同构建工具即可无限制通信方式模块导入全局状态/CustomEvent技术栈要求推荐 Webpack 5/Rspack无要求适用场景新系统间模块共享旧系统集成三、Module Federation 的生产级配置// vite.config.ts — Module Federation 配置使用 originjs/vite-plugin-federation import { defineConfig } from vite; import vue from vitejs/plugin-vue; import federation from originjs/vite-plugin-federation; // 远程模块配置子应用 export default defineConfig({ plugins: [ vue(), federation({ name: remote-app, filename: remoteEntry.js, // 暴露给宿主应用的模块 exposes: { ./UserList: ./src/components/UserList.vue, ./OrderPanel: ./src/components/OrderPanel.vue, ./useAuth: ./src/composables/useAuth.ts, ./utils: ./src/utils/index.ts, }, // 共享依赖配置 shared: { vue: { requiredVersion: ^3.3.0, singleton: true, // 强制单例避免多版本共存 eager: false, // 懒加载共享模块 }, vue-router: { singleton: true, requiredVersion: ^4.2.0, }, pinia: { singleton: true, requiredVersion: ^2.1.0, }, }, }), ], build: { target: esnext, minify: true, cssCodeSplit: false, }, }); // 宿主应用配置 // host-app/vite.config.ts export default defineConfig({ plugins: [ vue(), federation({ name: host-app, // 引用远程模块 remotes: { remoteApp: http://localhost:3001/assets/remoteEntry.js, }, // 共享依赖与远程模块对齐 shared: { vue: { singleton: true, requiredVersion: ^3.3.0, }, vue-router: { singleton: true, requiredVersion: ^4.2.0, }, pinia: { singleton: true, requiredVersion: ^2.1.0, }, }, }), ], }); // 宿主应用中使用远程模块 // src/App.vue script setup langts // 动态导入远程模块 const UserList defineAsyncComponent(() import(remoteApp/UserList) ); const OrderPanel defineAsyncComponent(() import(remoteApp/OrderPanel) ); // 导入远程 Composable const { useAuth } await import(remoteApp/useAuth); const { user, isAuthenticated } useAuth(); /script template div classapp header v-ifisAuthenticated 欢迎, {{ user.name }} /header main Suspense template #default UserList / /template template #fallback div classloading加载远程模块中.../div /template /Suspense Suspense template #default OrderPanel / /template template #fallback div classloading加载远程模块中.../div /template /Suspense /main /div /template四、qiankun 的生产级配置// qiankun-config.ts — qiankun 微前端配置 import { registerMicroApps, start, addGlobalUncaughtErrorHandler } from qiankun; // 主应用配置 interface MicroAppConfig { name: string; entry: string; container: string; activeRule: string; props?: Recordstring, any; } const microApps: MicroAppConfig[] [ { name: vue3-sub-app, entry: //localhost:3002, container: #subapp-container, activeRule: /vue3, props: { // 传递给子应用的数据 mainAppToken: localStorage.getItem(token), }, }, { name: react-sub-app, entry: //localhost:3003, container: #subapp-container, activeRule: /react, }, ]; registerMicroApps(microApps, { // 子应用加载前 beforeLoad: [ (app) { console.log(加载子应用: ${app.name}); return Promise.resolve(); }, ], // 子应用挂载后 afterMount: [ (app) { console.log(子应用已挂载: ${app.name}); return Promise.resolve(); }, ], // 子应用卸载后 afterUnmount: [ (app) { console.log(子应用已卸载: ${app.name}); return Promise.resolve(); }, ], }); // 全局错误处理 addGlobalUncaughtErrorHandler((event) { console.error(微前端全局错误:, event); // 子应用加载失败时显示降级 UI const container document.getElementById(subapp-container); if (container) { container.innerHTML div classerror-fallback子应用加载失败请刷新重试/div; } }); // 启动 qiankun start({ // 预加载策略 prefetch: all, // JS 沙箱模式 sandbox: { strictStyleIsolation: false, // 严格样式隔离Shadow DOM experimentalStyleIsolation: true, // 实验性样式隔离scope prefix }, // 全局状态通信 // 通过 initGlobalState 实现 }); // 全局状态通信 import { initGlobalState } from qiankun; const { onGlobalStateChange, setGlobalState } initGlobalState({ user: null, token: , permissions: [], }); // 主应用监听状态变化 onGlobalStateChange((state, prev) { console.log(全局状态变更:, state); }); // 主应用设置状态如登录后 function onLoginSuccess(user, token) { setGlobalState({ user, token, permissions: user.permissions, }); } // 子应用生命周期Vue3 // vue3-sub-app/src/main.ts let app: App | null null; function render(props: { container?: HTMLElement }) { const container props.container ? props.container.querySelector(#app) : document.getElementById(app); app createApp(App); app.use(router); app.use(pinia); app.mount(container); } // 独立运行 if (!(window as any).__POWERED_BY_QIANKUN__) { render({}); } // qiankun 生命周期 export async function bootstrap() { console.log(子应用 bootstrap); } export async function mount(props: any) { console.log(子应用 mount, props); // 接收主应用传递的数据 if (props.onGlobalStateChange) { props.onGlobalStateChange((state: any) { // 同步主应用状态到子应用 Pinia const pinia app?.config.globalProperties.$pinia; if (pinia) { pinia.state.value.auth { user: state.user, token: state.token, }; } }); } render(props); } export async function unmount() { console.log(子应用 unmount); app?.unmount(); app null; }五、选型的 Trade-offs 与决策建议Module Federation 的共享依赖风险。singleton: true强制共享模块单例但版本不兼容时会导致运行时错误。建议严格对齐共享依赖的requiredVersion并在 CI 中增加版本一致性检查。qiankun 的沙箱性能开销。JS 沙箱Proxy 代理和 CSS 隔离scope 前缀会带来约 5-15% 的性能开销。对于性能敏感的应用如数据可视化大屏建议使用 Module Federation 的模块级隔离。混合使用的维护成本。同时维护两套微前端基础设施的成本远超单一方案。建议根据团队技术栈统一选择一种方案——新系统用 Module Federation旧系统集成用 qiankun避免在同一项目中混用。选型决策树需要集成异构旧系统 → qiankun新系统间模块共享 → Module Federation需要严格隔离 → qiankun需要细粒度模块共享 → Module Federation团队统一 Webpack 5 → Module Federation技术栈混杂 → qiankun。五、总结Module Federation 和 qiankun 是两种不同范式的微前端方案前者基于构建时联邦实现模块级共享后者基于运行时容器实现应用级隔离。Module Federation 适合新系统间的细粒度模块共享qiankun 适合异构旧系统的集成。选型的核心依据是业务场景而非技术偏好——需要隔离选 qiankun需要共享选 Module Federation。避免在同一项目中混用两种方案统一技术栈是降低维护成本的关键。
前端微前端架构选型:Module Federation 与 qiankun 的对比实践
前端微前端架构选型Module Federation 与 qiankun 的对比实践一、微前端的选型焦虑两种范式的根本分歧微前端架构在前端领域已不再是新鲜概念但选型仍然是团队面临的第一道难题。当前主流方案分为两大阵营以 qiankun 为代表的运行时容器方案和以 Module Federation 为代表的构建时联邦方案。某金融科技公司同时使用了两种方案——主应用用 qiankun 集成 3 个旧系统新子系统用 Module Federation 互通——结果维护两套微前端基础设施的成本远超预期。两种方案不是简单的谁更好的关系而是解决不同问题的工具。理解其底层机制差异是做出正确选型的前提。二、两种微前端范式的架构对比flowchart TB subgraph MF[Module Federation 方案] MF_HOST[宿主应用] -- MF_REMOTE[远程模块] MF_REMOTE -- MF_SHARED[共享依赖] MF_SHARED -- MF_VUE[vue3.x] MF_SHARED -- MF_REACT[react18.x] MF_HOST -.-|构建时协商| MF_SHARED end subgraph QK[qiankun 方案] QK_MAIN[主应用] -- QK_SUB1[子应用A: Vue3] QK_MAIN -- QK_SUB2[子应用B: React] QK_MAIN -- QK_SUB3[子应用C: Angular] QK_MAIN -.-|运行时加载| QK_SUB1 QK_MAIN -.-|JS 沙箱| QK_SUB2 QK_MAIN -.-|CSS 隔离| QK_SUB3 end style MF fill:#dfd,stroke:#333 style QK fill:#ffd,stroke:#333核心差异对比维度Module Federationqiankun集成时机构建时运行时隔离机制模块作用域JS 沙箱 CSS 隔离框架限制同构建工具即可无限制通信方式模块导入全局状态/CustomEvent技术栈要求推荐 Webpack 5/Rspack无要求适用场景新系统间模块共享旧系统集成三、Module Federation 的生产级配置// vite.config.ts — Module Federation 配置使用 originjs/vite-plugin-federation import { defineConfig } from vite; import vue from vitejs/plugin-vue; import federation from originjs/vite-plugin-federation; // 远程模块配置子应用 export default defineConfig({ plugins: [ vue(), federation({ name: remote-app, filename: remoteEntry.js, // 暴露给宿主应用的模块 exposes: { ./UserList: ./src/components/UserList.vue, ./OrderPanel: ./src/components/OrderPanel.vue, ./useAuth: ./src/composables/useAuth.ts, ./utils: ./src/utils/index.ts, }, // 共享依赖配置 shared: { vue: { requiredVersion: ^3.3.0, singleton: true, // 强制单例避免多版本共存 eager: false, // 懒加载共享模块 }, vue-router: { singleton: true, requiredVersion: ^4.2.0, }, pinia: { singleton: true, requiredVersion: ^2.1.0, }, }, }), ], build: { target: esnext, minify: true, cssCodeSplit: false, }, }); // 宿主应用配置 // host-app/vite.config.ts export default defineConfig({ plugins: [ vue(), federation({ name: host-app, // 引用远程模块 remotes: { remoteApp: http://localhost:3001/assets/remoteEntry.js, }, // 共享依赖与远程模块对齐 shared: { vue: { singleton: true, requiredVersion: ^3.3.0, }, vue-router: { singleton: true, requiredVersion: ^4.2.0, }, pinia: { singleton: true, requiredVersion: ^2.1.0, }, }, }), ], }); // 宿主应用中使用远程模块 // src/App.vue script setup langts // 动态导入远程模块 const UserList defineAsyncComponent(() import(remoteApp/UserList) ); const OrderPanel defineAsyncComponent(() import(remoteApp/OrderPanel) ); // 导入远程 Composable const { useAuth } await import(remoteApp/useAuth); const { user, isAuthenticated } useAuth(); /script template div classapp header v-ifisAuthenticated 欢迎, {{ user.name }} /header main Suspense template #default UserList / /template template #fallback div classloading加载远程模块中.../div /template /Suspense Suspense template #default OrderPanel / /template template #fallback div classloading加载远程模块中.../div /template /Suspense /main /div /template四、qiankun 的生产级配置// qiankun-config.ts — qiankun 微前端配置 import { registerMicroApps, start, addGlobalUncaughtErrorHandler } from qiankun; // 主应用配置 interface MicroAppConfig { name: string; entry: string; container: string; activeRule: string; props?: Recordstring, any; } const microApps: MicroAppConfig[] [ { name: vue3-sub-app, entry: //localhost:3002, container: #subapp-container, activeRule: /vue3, props: { // 传递给子应用的数据 mainAppToken: localStorage.getItem(token), }, }, { name: react-sub-app, entry: //localhost:3003, container: #subapp-container, activeRule: /react, }, ]; registerMicroApps(microApps, { // 子应用加载前 beforeLoad: [ (app) { console.log(加载子应用: ${app.name}); return Promise.resolve(); }, ], // 子应用挂载后 afterMount: [ (app) { console.log(子应用已挂载: ${app.name}); return Promise.resolve(); }, ], // 子应用卸载后 afterUnmount: [ (app) { console.log(子应用已卸载: ${app.name}); return Promise.resolve(); }, ], }); // 全局错误处理 addGlobalUncaughtErrorHandler((event) { console.error(微前端全局错误:, event); // 子应用加载失败时显示降级 UI const container document.getElementById(subapp-container); if (container) { container.innerHTML div classerror-fallback子应用加载失败请刷新重试/div; } }); // 启动 qiankun start({ // 预加载策略 prefetch: all, // JS 沙箱模式 sandbox: { strictStyleIsolation: false, // 严格样式隔离Shadow DOM experimentalStyleIsolation: true, // 实验性样式隔离scope prefix }, // 全局状态通信 // 通过 initGlobalState 实现 }); // 全局状态通信 import { initGlobalState } from qiankun; const { onGlobalStateChange, setGlobalState } initGlobalState({ user: null, token: , permissions: [], }); // 主应用监听状态变化 onGlobalStateChange((state, prev) { console.log(全局状态变更:, state); }); // 主应用设置状态如登录后 function onLoginSuccess(user, token) { setGlobalState({ user, token, permissions: user.permissions, }); } // 子应用生命周期Vue3 // vue3-sub-app/src/main.ts let app: App | null null; function render(props: { container?: HTMLElement }) { const container props.container ? props.container.querySelector(#app) : document.getElementById(app); app createApp(App); app.use(router); app.use(pinia); app.mount(container); } // 独立运行 if (!(window as any).__POWERED_BY_QIANKUN__) { render({}); } // qiankun 生命周期 export async function bootstrap() { console.log(子应用 bootstrap); } export async function mount(props: any) { console.log(子应用 mount, props); // 接收主应用传递的数据 if (props.onGlobalStateChange) { props.onGlobalStateChange((state: any) { // 同步主应用状态到子应用 Pinia const pinia app?.config.globalProperties.$pinia; if (pinia) { pinia.state.value.auth { user: state.user, token: state.token, }; } }); } render(props); } export async function unmount() { console.log(子应用 unmount); app?.unmount(); app null; }五、选型的 Trade-offs 与决策建议Module Federation 的共享依赖风险。singleton: true强制共享模块单例但版本不兼容时会导致运行时错误。建议严格对齐共享依赖的requiredVersion并在 CI 中增加版本一致性检查。qiankun 的沙箱性能开销。JS 沙箱Proxy 代理和 CSS 隔离scope 前缀会带来约 5-15% 的性能开销。对于性能敏感的应用如数据可视化大屏建议使用 Module Federation 的模块级隔离。混合使用的维护成本。同时维护两套微前端基础设施的成本远超单一方案。建议根据团队技术栈统一选择一种方案——新系统用 Module Federation旧系统集成用 qiankun避免在同一项目中混用。选型决策树需要集成异构旧系统 → qiankun新系统间模块共享 → Module Federation需要严格隔离 → qiankun需要细粒度模块共享 → Module Federation团队统一 Webpack 5 → Module Federation技术栈混杂 → qiankun。五、总结Module Federation 和 qiankun 是两种不同范式的微前端方案前者基于构建时联邦实现模块级共享后者基于运行时容器实现应用级隔离。Module Federation 适合新系统间的细粒度模块共享qiankun 适合异构旧系统的集成。选型的核心依据是业务场景而非技术偏好——需要隔离选 qiankun需要共享选 Module Federation。避免在同一项目中混用两种方案统一技术栈是降低维护成本的关键。