Module Federation shared 配置如何处理依赖版本冲突?
shared 配置的作用,是让多个独立构建的应用在运行时协商依赖,尽量复用同一个包,而不是每个 remote 都带一份 React、Vue 或 UI 组件库。它不是简单的“去重开关”,而是一套运行时共享作用域机制:应用启动时初始化 shareScope,容器把自己可提供的依赖和版本注册进去,消费方再按 requiredVersion、singleton、strictVersion 等规则选择。理解这点,才能知道版本冲突为什么有时只是 warning,有时会直接炸。
追问
singleton 到底什么时候必须开?
singleton 适合那些进程里只能有一个实例的库,比如 React、react-dom、Vue、路由实例相关库和某些全局状态库。不开 singleton 时,不同 remote 可能各自加载一份 React,轻则包体变大,重则 Hooks 报错或上下文不互通。取舍是 singleton 会提升一致性,但也会让高版本覆盖低版本的问题更集中。边界很简单:工具函数库、日期库、小型纯函数包不一定要 singleton,框架运行时通常要。
jsshared: { react: { singleton: true, requiredVersion: '^18.2.0' }, 'react-dom': { singleton: true, requiredVersion: '^18.2.0' } }
requiredVersion 和 strictVersion 有什么区别?
requiredVersion 表达“我希望拿到什么版本范围”,strictVersion 表达“不满足就不要勉强运行”。默认情况下版本不完全满足时,Webpack 可能给 warning 并选择一个可用版本,业务还能跑但风险需要自己承担。打开 strictVersion 后问题暴露更早,适合设计系统、核心 SDK 这类兼容性要求高的依赖。取舍是严格版本更安全,但发布节奏会变慢,多个团队必须同步升级。
eager 为什么经常导致报错?
eager 会把共享依赖放进初始包同步加载,适合极少数启动前必须存在的依赖,但多数场景不该开。常见报错是“Shared module is not available for eager consumption”,本质是消费方太早同步读取共享依赖,而共享作用域还没初始化完。边界是:如果你只是想减少一次异步请求,不要用 eager 解决,先看拆包和预加载。踩坑最多的是 host 和 remote 都 eager react,最后不仅没省体积,还让初始化顺序更难控制。
多个 remote 依赖不同 React 版本怎么办?
最稳的做法是把 React 这类基础依赖纳入团队级版本基线,要求所有应用在同一兼容范围内发布。短期无法统一时,可以让个别历史 remote 独立打包自己的 React,但不要让它和 host 共享组件上下文。取舍是独立打包牺牲体积,换取隔离和稳定;强行共享牺牲稳定,换取表面上的去重。真正危险的是半共享状态:组件能渲染,但 Context、路由或 Hooks 在边界处出现偶发问题。
shared 配置应该怎么治理?
不要每个团队各写一份 shared,最好抽成公共配置或由构建插件统一生成。依赖升级时先在测试环境验证 shareScope 实际选择了哪个版本,而不是只看 package.json。可以在启动时打印关键共享依赖版本,线上采样上报,方便定位“某个租户加载了旧 remote”的问题。治理边界是别把所有包都纳入共享,shared 越多,版本协商面越大,发布时的隐性耦合也越多。