vue3中使用vue2组件简单实现

2,016 阅读1分钟

1.说明

vue2项目由vite+js搭建

vue3项目由vite+ts搭建

使用federation去完成二者之间的交互

2.步骤

1.使用vite搭建vue2项目

  • 创建项目名称及选择开发语言

npm init vite@latest

  • vite创建的项目默认支持vue3,安装vue2及相关插件

npm install vue -S

npm install vue-template-compiler

npm install vite-plugin-vue2 --dev

相关版本如下

  • 修改vite.config.js
import { createVuePlugin } from 'vite-plugin-vue2'

export default {
  plugins: [createVuePlugin()]
}
  • 修改main.js及页面
import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#app')
<template>
<div>vite+vue2</div>
</template>
  • npm run dev启动项目即可

2.vue2项目配置vite-plugin-federation

  • 安装@originjs/vite-plugin-federation

npm i @originjs/vite-plugin-federation

  • 创建Button组件并配置federation
....
import federation from "@originjs/vite-plugin-federation";
.....
federation({
  name: 'vue2App',//远程模块名称
  filename: 'remoteEntry.js',//远程模块入口文件,本地模块可通过vite.config.ts的remotes引入
  exposes: {//远程模块对外暴露的组件列表,远程模块必填
      './Button': './src/components/Button.vue',
  },
}),
<template>
<div>
  <button>哈哈哈哈哈哈哈</button>
</div>
</template>
  • npm run build 打包vue2项目
  • vue2中vite.config.js完整配置
import { createVuePlugin } from 'vite-plugin-vue2'
import federation from "@originjs/vite-plugin-federation";
// import topLevelAwait from 'vite-plugin-top-level-await'

export default {
  plugins: [
    createVuePlugin(),
    federation({
      name: 'vue2App',//远程模块名称
      filename: 'remoteEntry.js',//远程模块入口文件,本地模块可通过vite.config.ts的remotes引入
      exposes: {//远程模块对外暴露的组件列表,远程模块必填
        './Button': './src/components/Button.vue',
      },
      // shared: ["vue"],//本地模块和远程模块共享的依赖。开启需放开topLevelAwait
    }),
    // topLevelAwait({
    //   // The export name of top-level await promise for each chunk module
    //   promiseExportName: '__tla',
    //   // The function to generate import names of top-level await promise in each chunk module
    //   promiseImportName: i => `__tla_${i}`
    // }),
  ],
  build: {
    polyfillModulePreload: false,
    assetsInlineLimit: 40960,
    target: 'es2020',
    minify: false,
    cssCodeSplit: false,
    rollupOptions: {
      output: {
        minifyInternalExports: false
      }
    }
  }
}

3.使用vite+ts搭建vue3项目

此处不在赘述,参考官网cn.vuejs.org/guide/quick…

4.vue3项目配置vite-plugin-federation

  • 安装federation并配置
......
import federation from "@originjs/vite-plugin-federation";
......

    federation({
      name: "vite-host",
      filename: "remoteEntry.js",
      remotes: {
        remote1: "http://127.0.0.1:5174/dist/assets/remoteEntry.js",
      },
      // shared: ["vue"]
    }),
......
  • vite.config.js完整配置
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(), 
    vueJsx(),
    federation({
      name: "vite-host",
      filename: "remoteEntry.js",
      remotes: {
        remote1: "http://127.0.0.1:5174/dist/assets/remoteEntry.js",
      },
      // shared: ["vue"]
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    target: 'es2022',
    minify: false,
    cssCodeSplit: true,
    rollupOptions: {
      output: {
        minifyInternalExports: false
      }
    }
  },
})
  • 使用vue2组件
<script setup lang="ts">
import { vue2ToVue3 } from './Vue2ToVue3';
import Button from 'remote1/Button';
const Vue2Button =  vue2ToVue3(Button, 'vue2Button')
</script>
<template>
  <div id="vue2Button"></div>
  <vue2-button />
</template>

<style scoped>
</style>
  • Vue2ToVue3
import Vue2 from './Vue2.js' // 2.6.14版本的vue源码
function bindSlotContext (target = {}, context) {
  return Object.keys(target).map(key => {
    const vnode = target[key];
    vnode.context = context;
    return vnode;
  });
}

export 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项目,即可看见效果

3.结尾

只是简单的实现了vue3引入vue2简单的Button组件,具体实践中使用会有什么问题,还不清楚