Module Federation 多团队协作应该怎么拆边界?
Module Federation 真正解决的不是“把页面拆开”这么简单,而是让多个团队可以按业务节奏独立交付,同时仍然像一个产品一样运行。协作做得好,订单、用户、支付团队各自发布 Remote,Host 只管入口、导航、登录态和公共约束;协作做得差,就会变成一堆互相引用的远程包。
比较稳的做法是先定团队边界,再定模块边界。业务 Remote 应该围绕领域能力暴露,例如 order/OrderList、user/ProfilePanel,不要把一个团队内部的按钮、Hook、工具函数随手暴露出去。平台团队负责运行时、共享依赖、发布规范和监控模板,业务团队负责页面、接口适配和降级方案。这个分工慢一点,但能避免后期每次升级 React、路由或 UI 库都要开跨团队大会。
jsnew ModuleFederationPlugin({ name: 'order', filename: 'remoteEntry.js', exposes: { './OrderList': './src/pages/OrderList', './OrderRoutes': './src/routes' }, shared: { react: { singleton: true, requiredVersion: '^18.2.0' }, 'react-dom': { singleton: true, requiredVersion: '^18.2.0' }, '@company/ui': { singleton: true, requiredVersion: '^3.4.0' } } })
这段配置里的重点不是 exposes 写了什么,而是只暴露稳定能力。OrderList 可以被 Host 或其他业务组合,OrderRoutes 可以被主应用挂载;但订单团队内部的筛选组件如果还在频繁改,就不应该成为远程契约。共享依赖也要写清版本范围,尤其是 React、路由、状态库和设计系统,否则本地没问题,线上可能因为重复实例导致 Hook 报错或样式错乱。
追问
团队之间应该共享组件还是共享页面?
优先共享业务页面或稳定业务能力,不要一开始就共享过细的组件。共享组件复用率更高,但调用方会依赖你的 Props、样式和交互细节,维护成本也会上升。页面级 Remote 的边界更粗,团队能独立测试和发布,适合组织规模变大后的协作。边界是:如果一个能力频繁跟业务规则一起变化,就让负责该业务的团队拥有它;如果它是按钮、表格、弹窗这类通用能力,才进入设计系统。
Remote 的接口契约怎么管才不会互相拖累?
把 Remote 暴露出来的模块当成公共 API 管理,而不是随手导出的文件。建议为每个暴露模块维护类型声明、变更日志和兼容策略,破坏性变更必须走大版本。TypeScript 可以用 d.ts 包或独立 contract 包同步给调用方,但不要让调用方直接依赖 Remote 的源码路径。踩坑最多的是改了 Props 名称却只测了本团队页面,Host 在运行时才炸。
多团队独立发布时如何避免线上互相影响?
Remote 发布要有版本化地址、健康检查和回滚入口,Host 不应该永远指向一个不可追踪的最新文件。可以让环境配置中心返回当前可用的 remoteEntry URL,并保留上一版地址作为快速回滚。取舍在于固定版本更稳定但发布链路更重,动态版本更灵活但需要更强监控。生产环境至少要监控 remoteEntry 加载失败和关键页面白屏率。
公共依赖到底该不该全部 singleton?
不是所有依赖都应该 singleton。React、React DOM、路由实例、状态容器这类有运行时上下文的库,通常需要 singleton;日期库、工具函数、小型纯函数库可以让各 Remote 自带,减少版本协调。过度 singleton 会让平台团队成为依赖升级瓶颈,任何一个 Remote 的版本要求都可能卡住全局。边界是:如果重复加载会破坏上下文或明显增加体积,就共享;如果只是几十 KB 且没有全局状态,独立携带反而省心。
协作流程里最容易被忽略的坑是什么?
最容易忽略的是“本地联调成功不等于线上协作成功”。本地常常跑的是最新源码,线上加载的是 CDN 上的 remoteEntry,两者版本和缓存策略可能完全不同。另一个坑是只约定技术配置,不约定故障责任:Remote 挂了以后 Host 显示什么、谁收到告警、多久回滚,都要提前写清。Module Federation 能让团队独立,但它不会自动替你建立协作秩序。
结论很简单:Module Federation 的多团队协作要先管契约,再谈复用。模块暴露越克制,依赖策略越清楚,发布和回滚越可观测,团队越能真正独立交付。