web components 不是模块联邦的替代方案,它不处理依赖版本、不参与 shared scope 协商、无 singleton 控制能力,无法自动对齐 react/vue 等跨应用依赖版本。

Web Components 本身不支持模块联邦意义上的“运行时依赖协商”或“跨应用共享 React/Vue 实例”,拿它直接套用 Module Federation 的思路会踩坑。
Web Components 不是模块联邦的替代方案
很多人看到 customElements.define() 和 import('./remote.js') 都能加载代码,就默认 Web Components 天然支持模块联邦。但关键区别在于:Web Components 是浏览器原生封装机制,不处理依赖版本、不参与 shared scope 协商、不提供 singleton 控制能力。
- React/Vue 组件跨应用复用时,若两个微应用用了不同版本的
react,Web Components 无法自动对齐——它只管把自定义标签渲染出来,内部逻辑仍各自打包各自的 React -
shared: { react: { singleton: true } }这类配置在 Webpack Module Federation 中生效,但在纯 Web Components 场景下完全无效 - 没有
remoteEntry.js加载流程,也就没有初始化时的init(sharedScope)步骤,依赖冲突只能靠人工规避
HTML 模块联邦 ≠ Web Components + import()
所谓“HTML 微模块联邦”,常被误解为直接在 HTML 中写 <script type="module" src="https://cdn.com/mfe-b.js"></script> 然后用 <my-button></my-button>。这看似解耦,实则隐藏三个硬伤:
- 资源加载无优先级控制:
<script></script>是并行加载,无法像 Module Federation 那样通过eager: true强制提前加载核心依赖(如lit或react) - 样式隔离靠 Shadow DOM,但全局 CSS 变量、字体、图标字体等仍可能冲突,且无法像
shared: { 'antd': { singleton: true } }那样统一注入 - 没有运行时错误兜底:远程模块加载失败时,
<my-button></my-button>就是空白节点,Module Federation 至少能抛出Container not available错误供捕获
真要基于 Web Components 做联邦共享,必须补足缺失层
如果坚持用 Web Components 构建微前端,又想获得类似 Module Federation 的依赖治理能力,得自己实现三件事:
- 手动管理依赖生命周期:用
import('https://cdn.com/react@18.2.0.js')+window.React检查 +Object.assign(window, { React })注入,模拟singleton - 暴露可协商的版本接口:远程模块需提供
__MFE_VERSIONS__ = { react: '^18.2.0', lit: '^3.0.0' }全局变量,主应用加载前做比对 - 封装加载器代替原生
<script></script>:用import('./loader.js').then(m => m.loadRemote('mfe-b')),支持 fallback、timeout、retry,接近get('./Component')的语义
这些补丁加起来,代码量和维护成本远超直接用 Webpack Module Federation;而一旦项目里已有 React/Vue,再绕一圈用 Web Components 包一层,反而增加抽象层级和调试难度。
真正容易被忽略的是:Web Components 解决的是“封装粒度”问题,Module Federation 解决的是“依赖拓扑”问题。两者目标不同,强行合并时,最容易卡在版本协商失败却无日志提示,或者 Shadow DOM 内部调用的 useState 来自不同 React 实例导致 Hook 报错——这种错误不会出现在构建阶段,只会在用户点击按钮后才触发。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











