微前端架构在 AI 工具平台中的应用:Module Federation 的多团队协作实践
微前端架构在 AI 工具平台中的应用:Module Federation 的多团队协作实践
一、AI 工具平台的单体拆分困境
一个 AI 工具平台包含四个功能模块:智能写作助手、代码审查 Agent、知识库检索、Prompt 调试器。最初它们共享同一个 Next.js 应用,四个模块的代码在同一仓库中。随着模块各自迭代加速,问题开始显现:智能写作团队每周发布 3 次,Prompt 调试器团队每月发布 1 次,两者的发布节奏被绑在一起;智能写作引入的一个依赖升级导致 Prompt 调试器的构建失败,排查花了半天。
更棘手的是技术栈的分化。智能写作团队想用 Vue 3 的组合式 API 重构编辑器,代码审查团队坚持 React 生态,知识库团队想试验 Svelte 的性能优势。单体仓库强制统一技术栈,抑制了各模块的技术探索。
微前端架构的核心价值不在于"拆分",而在于解耦发布周期和技术栈约束。每个子应用独立构建、独立部署、独立选择技术栈,主应用只负责路由分发和共享状态。
二、Module Federation 的运行时集成架构
Webpack 5 的 Module Federation 提供了一种运行时集成方案,子应用在运行时动态加载而非构建时打包:
graph TB subgraph 主应用(Shell) S[Shell 应用<br/>路由分发 + 布局框架] S --> S1[导航栏] S --> S2[全局状态管理] S --> S3[认证/鉴权] end subgraph 远程子应用 R1[智能写作助手<br/>Vue 3 + Vite<br/>端口 3001] R2[代码审查 Agent<br/>React 18 + Webpack<br/>端口 3002] R3[知识库检索<br/>Svelte + Rollup<br/>端口 3003] R4[Prompt 调试器<br/>Next.js<br/>端口 3004] end subgraph 共享依赖 SHARED[shared libs<br/>react / vue / lodash<br/>design-tokens] end S -->|动态加载| R1 S -->|动态加载| R2 S -->|动态加载| R3 S -->|动态加载| R4 R1 -.->|共享运行时| SHARED R2 -.->|共享运行时| SHARED S -.->|共享运行时| SHARED主应用(Shell)只负责布局框架、路由分发、全局状态和认证逻辑。每个子应用独立运行在各自的端口上,开发时只需启动自己负责的子应用。共享依赖在运行时由 Module Federation 统一管理,避免 React 等库被多次加载。
三、Shell 应用与子应用的 Federation 配置
// Shell 应用 webpack.config.js // 设计意图:Shell 不包含业务逻辑,仅做路由分发和布局 const { ModuleFederationPlugin } = require('webpack').container; module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'shell', // 共享依赖——所有子应用共用同一份基础库 shared: { react: { singleton: true, // 全局只加载一份 React requiredVersion: '^18.0.0', eager: true, // Shell 立即加载 }, 'react-dom': { singleton: true, requiredVersion: '^18.0.0', eager: true, }, // 设计 Token——所有子应用共享同一套样式变量 '@ai-tools/design-tokens': { singleton: true, requiredVersion: '^1.0.0', }, }, }), ], };// 智能写作子应用(Vue 3 + Vite) vite.config.js // 设计意图:Vue 应用通过 Module Federation 暴露组件给 Shell import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import federation from '@originjs/vite-plugin-federation'; export default defineConfig({ plugins: [ vue(), federation({ name: 'writing-assistant', filename: 'remoteEntry.js', // 对外暴露的组件——Shell 通过动态导入使用 exposes: { './App': './src/App.vue', }, // 共享依赖——使用 Shell 提供的 Vue 运行时 shared: ['vue'], }), ], build: { target: 'esnext', minify: false, }, server: { port: 3001, // CORS 配置——允许 Shell 跨域加载远程入口 cors: true, }, });// Shell 应用中的路由配置 // 设计意图:通过动态 import 加载远程子应用 // React.lazy + Suspense 处理加载状态 import React, { Suspense, lazy } from 'react'; // 动态加载远程组件——路径格式: {remoteName}/{exposedModule} const WritingAssistant = lazy(() => import('writing-assistant/App')); const CodeReview = lazy(() => import('code-review/App')); const KnowledgeBase = lazy(() => import('knowledge-base/App')); // 加载失败时的降级 UI function ModuleError({ moduleName }: { moduleName: string }) { return ( <div className="module-error"> <p>{moduleName} 模块加载失败</p> {/* 保留重试按钮——网络抖动后允许手动重试 */} <button onClick={() => window.location.reload()}> 点击重试 </button> </div> ); } function AppRoutes() { return ( <div className="shell-layout"> <nav>{/* 全局导航栏 */}</nav> <main> <Suspense fallback={<div>加载中...</div>}> <Routes> <Route path="/writing/*" element={ <ErrorBoundary fallback={<ModuleError moduleName="智能写作" />}> <WritingAssistant /> </ErrorBoundary> } /> <Route path="/review/*" element={ <ErrorBoundary fallback={<ModuleError moduleName="代码审查" />}> <CodeReview /> </ErrorBoundary> } /> <Route path="/knowledge/*" element={ <ErrorBoundary fallback={<ModuleError moduleName="知识库" />}> <KnowledgeBase /> </ErrorBoundary> } /> </Routes> </Suspense> </main> </div> ); }三个关键设计决策:
singleton: true确保 React 等核心库全局只加载一份,否则每个子应用独立加载的 React 会导致 Hooks 状态不共享;- 每个远程组件被
ErrorBoundary包裹——单个子应用加载失败不影响其他模块正常工作; - 共享
design-tokens包——确保所有子应用的视觉风格统一。
四、微前端的隐性成本与适用条件
调试复杂度的指数增长。在单体应用中排查一个 Bug 只需要看一个调用栈。在微前端架构中,同一个 Bug 可能跨越 Shell → 子应用 A → 共享库 → 子应用 B 四条链路。对 Source Map 的配置要求更高,需要在 CI 中将每个子应用的 Source Map 上传到统一的错误追踪平台。
共享状态的版本兼容。Shell 和子应用各自独立迭代后,共享的全局状态结构可能不兼容。例如 Shell v2.0 的 User 对象新增了permissions字段,但子应用 v1.5 期望roles字段。需要在 Shell 层维护版本兼容映射。
不适合 3 个团队以下的项目。微前端的架构成本(配置、CI、调试)在团队数量少于 3 时超过收益。此时模块间的通信密度高于边界隔离的收益。
五、总结
微前端在 AI 工具平台中的适用策略:
- Module Federation 实现运行时集成,各子应用独立构建部署;
- Shell 应用仅做路由分发和共享状态,不包含业务逻辑;
- 每个子应用被 ErrorBoundary 隔离——单点故障不扩散;
- 共享依赖通过
singleton: true保证运行时一致性。
适用条件判断:
- 团队数量 ≥ 3,且各团队发布节奏不同;
- 存在技术栈分化需求(React / Vue / Svelte);
- 模块间交互以页面级路由切换为主,非频繁的跨模块函数调用。