一个项目同时安装使用 vue3 vue2

3,192 阅读2分钟

先看效果:vercel vite-vue2in3.vercel.app

背景

原项目:vue-cli + vue2 spa项目,总共就 4 个页面,页面之间没什么关系;

目的:想升级 vite + vue3,但又有个页面依赖的组件很难升级 vue3,所以又保留 vue2。

可以微前端,但没必要,其本质是变成两个项目,有点重了。下面是示例项目的创建,也就是主页面为 vue3,子页面是 vue2。

创建 vite 项目

先用 create-vite 创建一个 vue3 项目

根据 vite mpa 文档修改下,添加一个二级页面 sub

此时如果 sub 页面也是 vue3 或者 vanilla 那么已经可以运行了。

为了在项目中同时使用 vue2,我们用 npm alias 来安装 vue2,pnpm add vue2@npm:vue@^2.7 。packages.json 的 dependencies 是这样:"vue2": "npm:vue@^2.7.14"

image.png

此时启动页面会报错,原因是 sub 目录下的 .vue 文件没有被正确地编译,因为此时 vite 使用 @vitejs/plugin-vue 来编译项目中的所有 .vue 文件(换句话说 sub/App.vue 被当成 vue3 编译了)。

vite 分别处理 vue2 sfc 和 vue3 sfc

安装这两个插件来处理 vue2 sfc 和 vue3 sfc

pnpm add -D @vitejs/plugin-vue @vitejs/plugin-vue

设置 @vitejs/plugin-vue 不处理 sub 目录下的 .vue 文件,而 sub 目录下的 .vue 文件需要被 @vitejs/plugin-vue2 处理。因此分别使用他们的 include、exclude 配置,如图。同时,因为默认使用 require("vue/compiler-sfc"),而此时项目中 require 会指向 vue3 的这个,需要指定一下 compiler。

// vite.config.ts
......
import vue from '@vitejs/plugin-vue'
import vue2 from '@vitejs/plugin-vue2'
import * as compiler from 'vue2/compiler-sfc'

export default defineConfig({
  plugins: [
    vue({
      exclude: ['src/sub/**'],
    }),
    vue2({
      include: ['src/sub/**/*.vue'],
      // @ts-ignore
      compiler,
    }),
......

这样就大功告吉了!启动!

......







然而并没有什么用

image.png 还是报错,但是报错变成了上图,为什么🧐?这行是 import 一个 vue3,难道变成vue2了?

进去断点不了,因为这里不是运行,还要经过 vite 处理的。这毫无疑问是 @vitejs/plugin-vue2 引起的,最终我在 @vitejs/plugin-vue2 代码里面找到这么一个逻辑:(line: 1041-1046)

image.png

这插件给 resolve.alias 加了一个 vue 的别名!不知道为什么,很离谱。

上面的报错就是由于 vue 被重定向,而 vue/dist/vue.runtime.esm.js 在本项目中实际指向 vue3,vue/dist 下面根本没有 vue.runtime.esm.js(vue2/dist 下面才有)。

那么加一个 alias,vue -> vue 自己规避一下:

// vite.config.ts
export default defineConfig({
......
  resolve: {
    alias: [
      { find: 'vue', replacement: 'vue' },
......

启动!真·大功告成!

示例代码仓库: Thy3634/vite-vue2in3 (github.com)

库中 require 的 vue 怎么办?

示例项目没安装任何依赖 vue2 的库,如果有库依赖 vue2,其 require('vue') 会取到 vue3,这毫无疑问会错误。

笔者尝试了 element-ui,直接把 node_modules/element-ui/lib 中搜索 require('vue')/require("vue") 全局替换为 require('vue2') 就好了,这可以用一个 postinstall 脚本处理下。

也可以把组件库提出来稍微改改,放在目录下,安装间接依赖,也能达到目的。