如何在基于Webpack 5的React微前端中调用Vue组件
问题:React微前端壳应用调用Vue组件报错
我刚开始学习微前端,用npx create-mf-app创建了React壳应用Micro-Shell-App,又用同样命令创建了Vue微前端项目SectionPart。想在React壳应用中调用Vue组件,但遇到以下错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
项目目录结构

相关代码片段
MyComponent.vue
<template> <div> <h2>Hello, {{ name }}!</h2> </div> </template> <script> export default { data() { return { name: 'World' }; } }; </script>
SectionPart的webpack.config.js
// some imports module.exports = (_, argv) => ({ output: { publicPath: "http://localhost:3003/", }, resolve: { extensions: [".tsx", ".ts", ".vue", ".jsx", ".js", ".json"], }, devServer: { port: 3003, historyApiFallback: true, }, module: { rules: [ { test: /\.vue$/, loader: "vue-loader", }, { test: /\.tsx?$/, use: [ "babel-loader", { loader: "ts-loader", options: { transpileOnly: true, appendTsSuffixTo: ["\\.vue$"], happyPackMode: true, }, }, ], }, { test: /\.(css|s[ac]ss)$/i, use: ["style-loader", "css-loader", "postcss-loader"], }, ], }, plugins: [ new VueLoaderPlugin(), new ModuleFederationPlugin({ name: "SectionPart", filename: "remoteEntry.js", remotes: { }, exposes: { "./MyComponent":"./src/components/MyComponent.vue", }, shared: require("./package.json").dependencies, }), new HtmlWebPackPlugin({ template: "./src/index.html", }), new Dotenv() ], });
Micro Shell App的webpack.config.js
// some imports module.exports = (_, argv) => ({ output: { publicPath: "http://localhost:3000/", }, resolve: { extensions: [".tsx", ".ts", ".jsx", ".js", ".json"], }, devServer: { port: 3000, historyApiFallback: true, }, module: { rules: [ { test: /\.m?js/, type: "javascript/auto", resolve: { fullySpecified: false, }, }, { test: /\.(css|s[ac]ss)$/i, use: ["style-loader", "css-loader", "postcss-loader"], }, { test: /\.(ts|tsx|js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader", }, }, { test: /\.vue$/, loader: "vue-loader", exclude: /node_modules/ } ], }, plugins: [ new ModuleFederationPlugin({ name: "Micro_Shell_App", filename: "remoteEntry.js", remotes: { section:"SectionPart@http://localhost:3003/remoteEntry.js" }, exposes: {}, shared: { ...deps, react: { singleton: true, requiredVersion: deps.react, }, "react-dom": { singleton: true, requiredVersion: deps["react-dom"], }, }, }), new HtmlWebPackPlugin({ template: "./src/index.html", }), new VueLoaderPlugin(), new Dotenv() ], });
壳应用的App.jsx
import React from "react"; import ReactDOM from "react-dom"; import MyComponent from "section/MyComponent" const App = () => ( <MyComponent /> ); ReactDOM.render(<App />, document.getElementById("app"));
解决方案
错误核心是Vue组件不能直接在React中当作React组件渲染:Vue组件输出的是Vue实例选项对象,而React期望接收符合React规范的组件(字符串/类/函数)。需要通过适配层将Vue组件包装为React可识别的组件。
步骤1:在Vue远程应用中导出适配后的组件
在SectionPart项目中创建包装文件src/exposes/MyComponentWrapper.js:
import Vue from 'vue'; import MyComponent from '../components/MyComponent.vue'; // 导出Vue组件选项,供React侧包装使用 export default MyComponent;
修改SectionPart的webpack.config.js中exposes配置:
exposes: { "./MyComponent": "./src/exposes/MyComponentWrapper.js", },
步骤2:在React壳应用中添加Vue到React的适配组件
在Micro-Shell-App中安装依赖(如果未安装):
npm install vue
创建React包装组件src/components/VueToReact.jsx:
import React, { useEffect, useRef } from 'react'; import Vue from 'vue'; export default function VueToReact({ component: VueComponent, ...props }) { const containerRef = useRef(null); const vueInstanceRef = useRef(null); useEffect(() => { if (!containerRef.current || !VueComponent) return; // 挂载Vue实例到容器 vueInstanceRef.current = new Vue({ el: containerRef.current, render: h => h(VueComponent, { props }) }); // 组件卸载时销毁Vue实例 return () => { if (vueInstanceRef.current) { vueInstanceRef.current.$destroy(); vueInstanceRef.current = null; } }; }, [VueComponent, props]); return <div ref={containerRef} />; }
步骤3:在React壳应用中使用适配后的组件
修改App.jsx:
import React from "react"; import ReactDOM from "react-dom"; import VueToReact from './components/VueToReact'; import MyComponent from "section/MyComponent" const App = () => ( <VueToReact component={MyComponent} /> ); ReactDOM.render(<App />, document.getElementById("app"));
额外注意事项
- 确保两个应用的Vue版本一致,避免冲突。可以在
shared配置中共享Vue:
在SectionPart的webpack.config.js的shared中添加:
在React壳应用的shared: { ...require("./package.json").dependencies, vue: { singleton: true, requiredVersion: require("./package.json").dependencies.vue } }webpack.config.js的shared中添加:shared: { ...deps, react: { singleton: true, requiredVersion: deps.react }, "react-dom": { singleton: true, requiredVersion: deps["react-dom"] }, vue: { singleton: true, requiredVersion: deps.vue } } - 重启两个应用的开发服务器,确保webpack重新编译。
内容的提问来源于stack exchange,提问作者Emre Sert
相关产品推荐
相关产品推荐

