本文共 3601 字,大约阅读时间需要 12 分钟。
在一个 Vue3 项目中使用 Vue2 组件可能会遇到一些挑战。本文将分享从 Vue2 迁移到 Vue3 的实践经验,重点描述在模块联邦(Module Federation)下集成 Vue2 组件的过程及相关问题。
在项目初期,我们需要通过模块联邦来实现 Vue2 组件与 Vue3 项目的无缝集成。以下是关键配置步骤:
// vue2-app/vue2.config.jsmodule.exports = { plugins: [ new ModuleFederationPlugin({ name: 'vue2App', filename: 'remoteEntry.js', library: { type: 'var', name: 'vue2App' }, exposes: { './vue2': './node_modules/vue/dist/vue', './Button': './src/components/Button' } }) ]}
// vue3-app/webpack.config.jsmodule.exports = { plugins: [ new ModuleFederationPlugin({ name: 'vue3App', filename: 'remoteEntry.js', remotes: { vue2App: 'vue2App@http://localhost:3001/remoteEntry.js' } }) ]}
在 Vue3 项目中集成 Vue2 组件的关键在于实现两者的无缝对接。以下是具体实现方法:
在 Vue3 组件中直接使用 Vue2 组件可能会遇到问题。例如:
这种方式不适用。需要通过手动创建 DOM 节点来实现组件挂载。
在 utils.js
中,创建一个通用函数来挂载 Vue2 组件:
// utils.jsexport function vue2ToVue3(WrapperComponent, wrapperId) { let vm; return { mounted() { const slots = bindSlotContext(this.$slots, this.__self); vm = new Vue2({ render: createElement => { return createElement(WrapperComponent, { on: this.$attrs, attrs: this.$attrs, props: this.$props, scopedSlots: this.$scopedSlots }, slots); } }); vm.$mount(`#${wrapperId}`); }, props: WrapperComponent.props, render() { vm && vm.$forceUpdate(); } };}
在 Vue3 组件中使用挂载函数:
Vue3 App
utils.js
中的 bindSlotContext
函数用于将 Vue 组件的插槽上下文传递给挂载的 Vue2 组件:
// utils.jsfunction bindSlotContext(target = {}, context) { return Object.keys(target).map(key => ({ vnode: target[key], vnode.context = context }));}
一个典型的 Vue2 组件可能如下:
确保 Vue2 组件通过模块联邦正确暴露:
// src/components/Button.vueexport default { methods: { click() { this.$emit('btnClick'); this.$emit('onBtnClick'); } }};
Uncaught Error: Shared module is not available for eager consumption
这种错误通常发生在模块加载过程中。解决方案是:
// bootstrap.jsimport { createApp } from 'vue';import App from './App.vue';import router from './router';createApp(App) .use(router) .mount('#app');
在项目根目录下创建以下 .env
文件:
# .env.developmentNODE_ENV = 'development'VUE_APP_API_ENV = 'dev'
# .env.productionNODE_ENV = 'production'VUE_APP_API_ENV = 'prod'
cross-env NODE_ENV=development yarn serve
在 Vue2 组件库中使用 Element UI 的话,在 Vue3 项目中需要切换到 Element Plus:
// package.json{ "dependencies": { "element-plus": "^2.0.0" }}
对于自定义或封装的组件,可以按照以下方式使用:
// utils.jsexport function vue2ToVue3(WrapperComponent, wrapperId) { let vm; return { mounted() { const slots = bindSlotContext(this.$slots, this.__self); vm = new Vue2({ render: createElement => { return createElement(WrapperComponent, { on: this.$attrs, attrs: this.$attrs, props: this.$props, scopedSlots: this.$scopedSlots }, slots); } }); vm.$mount(`#${wrapperId}`); }, props: WrapperComponent.props, render() { vm && vm.$forceUpdate(); } };}
模块联邦在 Vue3 项目中集成 Vue2 组件确实可行,但存在诸多不便之处。建议在有精力完成优化的情况下,将 Vue2 组件库迁移到 Vue3。
对于现有项目,若无法立即迁移,可以通过以下方式维护:
通过以上方法,可以在现有项目中实现 Vue2 组件与 Vue3 项目的无缝集成,但建议未来有条件时进行全面迁移。
转载地址:http://gbffk.baihongyu.com/