微前端中子应用依赖不同React版本时如何避免冲突?
最近在用single-spa搭建微前端架构,但遇到子应用依赖不同React版本的问题。比如主应用用的是React 18,而某个子应用还用着React 17,运行时老是报错说版本不兼容,Warning: React version mismatch。
我已经按照文档在子应用bootstrap里用了window.React = require('./node_modules/react'),但切换路由时依然会闪现错误。尝试过用npm resolutions和Yarn的resolutions都没搞定,有没有什么可靠的办法让子应用完全隔离依赖?
以下是子应用的bootstrap代码:
export function bootstrap() {
// 尝试过用iframe隔离但影响交互
// 也试过webpack externals配置
console.log('子应用启动时React版本:', React.version);
}
主应用配置里已经设置了loadChildren: () => import('./subapp'),但打包后发现两个React版本都被包含进去了,该怎么彻底分开呢?
根本解法是:把子应用打包成独立的 umd 包,并且把 react、react-dom 都设为 external,确保它运行时用的是自己那一份依赖,而不是主应用的。
改一下就行。
首先,在子应用的 webpack 配置里加:
然后在子应用入口 bootstrap 前,先动态注入对应版本的 React 17:
主应用那边别用 () => import('./subapp') 直接引入,那样会把子应用打进来一起跑。要用动态 import + script 标签方式异步加载整个子应用的 js 文件(比如 subapp.entry.js),让它自己走上面那套流程。
最后提醒一点:不同 React 版本的 Fiber 树不能共存,所以绝对不能让两个版本同时被同一个 ReactDOM 操作。必须保证子应用有自己的 container 和独立的 render/unmount 生命周期。
这套方案我们线上跑了快两年了,只要每个子应用管好自己的依赖,完全没问题。
复制这个方案:用 webpack 的 ModuleFederation + share scope 隔离依赖,别自己手动挂 window.React。
主应用 webpack 配置加上:
子应用那边也加 MF 插件,但注意不要加 name 和 remotes,只共享:
关键点是子应用把 requiredVersion 设为 false,这样它就不会强制用主应用的 React,而是用自己的。singleton 关掉才能真正隔离。
然后在子应用入口文件最前面加上:
这招叫运行时模块劫持,确保子应用所有 import React 都走自己的实例。
最后 build 子应用时加个前缀避免 chunk 冲突:
搞定之后就能混着用了,我们线上三个子应用分别用 React 16/17/18 都跑得好好的。别信 iframe 那套,通信太麻烦。这套配置复制过去基本就能跑。