WebComponents是浏览器原生的封装机制,不处理依赖版本与共享协商;模块联邦的核心是运行时依赖协商和单例控制。两者目标不同,强行用WebComponents替代模块联邦会导致依赖冲突和缺少错误兜底,需自行实现依赖管理。
微前端架构中,Web Components 与模块联邦是经常被混淆的两个概念。许多人认为它们都能实现“跨应用共享”,所以换个封装形式似乎就能通用。但实际上,二者所解决的问题处于完全不同的层面。
先看一个冷知识:Web Components 是浏览器原生的封装机制,它只负责将自定义标签渲染出来,内部逻辑各自独立运行。而模块联邦的核心能力在于运行时依赖协商,例如两个微应用各自打包了 React,联邦可以通过 shared 配置强制只加载一个实例。Web Components 则完全不处理这类问题。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
因此,直接将 Web Components 套用 Module Federation 的思路,容易踩坑。
很多人看到 customElements.define() 和 import('./remote.js') 都能加载代码,就默认两者等同。但关键区别在于:Web Components 不处理依赖版本、不参与 shared scope 协商、更没有 singleton 控制能力。
react,Web Components 无法自动对齐——它只负责渲染自定义标签,内部逻辑仍各自打包各自的 React。shared: { react: { singleton: true } } 这类配置,在 Webpack Module Federation 中生效,但在纯 Web Components 场景下完全无效。remoteEntry.js 加载流程,也就没有初始化时的 init(sharedScope) 步骤,依赖冲突只能靠人工规避。所谓“HTML 微模块联邦”,常被误解为直接在 HTML 里写 ,然后用 。这看似解耦,实则隐藏三个硬伤:
是并行加载,无法像 Module Federation 那样通过 eager: true 强制提前加载核心依赖(比如 lit 或 react)。shared: { 'antd': { singleton: true } } 那样统一注入。 就是空白节点,Module Federation 至少能抛出 Container not available 错误供捕获。如果坚持用 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' } 全局变量,主应用加载前做比对。:用 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 报错——这种错误不会出现在构建阶段,只会在用户点击按钮后才触发。