能否通过Module Federation在React 17中挂载Vue 2应用?
Vue 2 微前端挂载到 React 17 宿主应用报错解决方案
问题背景
将 Vue CLI 5 生成的 Vue 2 应用(含2个默认路由)通过 Module Federation 挂载到 React 17 宿主应用时,已成功获取 remoteEntry.js,但挂载时触发错误:
error Error: Module "." does not exist in container. while loading "." from webpack/container/reference/@zx-mfe/vueRemote
相关配置
Vue 端 vue.config.js Module Federation 配置
module.exports = defineConfig({ transpileDependencies: true, configureWebpack: { devServer: { historyApiFallback: true }, optimization: { splitChunks: false }, plugins: [ new ModuleFederationPlugin({ name: 'vueRemote', filename: 'remoteEntry.js', exposes: { './sharedApp': './src/expose.ts' } }) ] } })
Vue 暴露文件 src/expose.ts
//app content // export default new Vue({ // router, // render: h => h(App) // }).$mount('#app') import app from './main' export default app
React 端 Module Federation 配置
new ModuleFederationPlugin({ name: "host", remotes: { "@zx-mfe/vueRemote": "vueRemote@http://localhost:8080/remoteEntry.js", }, }),
React 挂载 Vue 应用的 Loader 组件
import React from 'react'; import { ErrorBoundary } from 'react-error-boundary'; //@ts-ignore const VueApp = React.lazy(() => import("@zx-mfe/vueRemote") .then((res) => { console.log('res', res) }) .catch((error) => { console.log('error', error) })); export const VueAppLoader = () => { return ( <React.Suspense fallback="loading"> <ErrorBoundary fallback={<h2>Failed to load Vue Application</h2>}> <VueApp /> </ErrorBoundary> </React.Suspense> ) }
问题分析与解决步骤
核心问题定位
报错根源是模块引入路径不匹配:Vue 端暴露的是 ./sharedApp 子路径,但 React 端直接请求了远程模块的根路径 .,而容器中并未暴露根路径模块,导致找不到资源。
步骤1:修正 React 端的模块引入路径
将 React 组件中的 import 路径改为 Vue 端暴露的具体模块路径,并处理 Vue 实例到 React 组件的转换:
import React from 'react'; import { ErrorBoundary } from 'react-error-boundary'; //@ts-ignore const VueApp = React.lazy(() => import("@zx-mfe/vueRemote/sharedApp") .then((vueInstance) => { // 返回适配 React 的组件,通过容器挂载 Vue 实例 return { default: () => { const containerRef = React.useRef<HTMLDivElement>(null); React.useEffect(() => { if (containerRef.current && vueInstance.default) { // 挂载 Vue 实例到容器 vueInstance.default.$mount(containerRef.current); // 卸载时清理 Vue 实例,避免内存泄漏 return () => vueInstance.default.$destroy(); } }, [vueInstance.default]); return <div ref={containerRef}></div>; } }; }) .catch(() => { return { default: () => <h2>Failed to load Vue Application</h2> }; })); export const VueAppLoader = () => { return ( <React.Suspense fallback="loading"> <ErrorBoundary fallback={<h2>Failed to load Vue Application</h2>}> <VueApp /> </ErrorBoundary> </React.Suspense> ) }
步骤2:优化 Vue 端的暴露逻辑
确保暴露的是未挂载的 Vue 实例,交给 React 端控制挂载时机:
修改 src/expose.ts:
import Vue from 'vue'; import App from './App.vue'; import router from './router'; // 创建实例但不自动挂载,避免重复挂载问题 export default new Vue({ router, render: h => h(App) });
步骤3:确认 Vue 2 兼容性说明
Vue 2 完全支持通过 Module Federation 作为微前端子应用挂载到 React 宿主,核心注意点:
- 必须通过容器元素间接挂载 Vue 实例,不能直接将 Vue 实例作为 React 组件渲染
- 严格处理 Vue 实例的挂载/卸载生命周期,避免内存泄漏
- 确保两端 webpack 版本均为 5+(Vue CLI 5 已满足,React 端需对应配置)
额外优化建议
- 路由隔离:给 Vue 应用设置路由基础路径,避免与 React 宿主路由冲突
修改 Vue 端router/index.js:const router = new VueRouter({ mode: 'history', base: '/vue-subapp/', routes: [...] }); - 样式隔离:使用 Vue 的 scoped styles 或 CSS Modules,防止样式污染宿主应用
内容的提问来源于stack exchange,提问作者Verthon
相关产品推荐
相关产品推荐

