共享依赖与避坑:shared / singleton / 何时别用微前端

本节目标

Module Federation 最易翻车的就是「共享依赖」。如果 remote 和 host 都打包了 React,浏览器会加载两份 React——不仅体积翻倍,更严重的是两份 React 各有各的上下文(Context/Hooks 状态),组件间状态不通、报错频发。

shared 配置就是解决这个:声明「这些依赖由一方提供、各方复用同一份」。

// host 和 remote 的 webpack.config.js 都配 shared
new ModuleFederationPlugin({
  // ...
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
  }
})

singleton: true 的意思是「全局只允许一份 React」——无论谁先加载,后续方复用这同一份,避免双实例。requiredVersion 约定版本范围,版本差太多会告警。

常见翻车点清单:

  1. React 双实例:没配 singleton,状态不互通、Hooks 报错 → 必配 shared.singleton。
  2. remote 先发、host 缓存了旧 remoteEntry:host 拉的是 CDN 缓存的旧地址 → 给 remoteEntry 加版本查询或「改 URL / 加 ?v=N」绕缓存。
  3. 循环依赖:A 消费 B、B 又消费 A → 运行时死锁,重构边界。
  4. 公共依赖版本不一致:remote 用 lodash@4、host 用 lodash@5,shared 协商失败 → 统一版本或 shared 锁定。

最后回到第一课的灵魂一问:什么时候别用微前端?

名词解释

shared(共享依赖):Module Federation 里声明「哪些依赖由应用间共用同一份」,避免每个应用都打包一份(如 React 被打包两次)。

singleton(单例):shared 的一个选项,强制「该依赖全局只有一份实例」,防止双 React 导致状态不通、Hooks 报错。

版本协商(Version Negotiation):remote 和 host 对 shared 依赖版本不一致时,Module Federation 按 requiredVersion 尝试匹配,匹配不上会告警或回退,常需手动对齐版本。

课后练习

练习 1:只写 shared: ['react'] 不写 singleton 够吗?

答案:不够稳。只列名字时 Module Federation 仍可能加载多份 React(不同构建各自带一份),只是「允许共享」。要彻底避免双实例必须加 singleton: true,这是生产环境必选项。

练习 2:微前端能解决「团队沟通差」吗?

答案:不能,反而放大。微前端解决的是「技术/部署层面的自治」,但接口契约、版本对齐、依赖共享仍需团队约定。组织问题不能靠架构甩锅——契约不清,微前端只会让 bug 分布得更散。

总结

Module Federation 的避坑核心就一句:shared 必配 singleton,否则双 React 状态不通。再加三道防线——remoteEntry 防缓存(改 URL/加 ?v=N)、避免循环依赖、统一公共依赖版本。最后把第一课的结论钉死:微前端是「独立部署诉求」的解法,没有这诉求就别上。八节课走完,你已能从「为什么」到「qiankun 接入」再到「Module Federation 共享」完整选型落地了。