最近開了一個讀者回饋表單郵箱,無論是對文章的感想或是對部落格的感想,有什麼想回饋的都可以發郵箱跟我說:i_kkkp@163.com

Vue 2/3 共存开发的思路

前言

2023 年 12 ⽉ 31 ⽇后,功能仍然可⽤,但不再提供更新,包括
• 安全更新
• 浏览器兼容

Evan 宣布 Vue 3 的第一个 RC将于 7 月中旬发布。这篇文章建议库/插件作者开始迁移对 Vue 3 的支持。但是由于 API 和行为发生了很大变化,是否有可能使我们的库同时支持 Vue 2 和 3 ?

通用代码

最简单的方法是编写适用于两个版本的通用代码 ,无需任何额外的修改,就像人们对Python 2 和 3所做的那样。简单并不意味着容易。编写此类组件需要避免Vue 3 中新引入的内容 以及Vue 2 中弃用的内容 。换句话说,您不能使用:

  • 合成API
  • .sync .native修饰语
  • 过滤器
  • 3rd 方供应商对象

使用分支

核心团队成员对此问题的回复建议使用不同的分支来分隔对每个定位版本的支持。我认为这对于现有和成熟的库来说是一个很好的解决方案,因为它们的代码库通常更稳定,并且版本目标优化可能需要它们具有更好的代码隔离。

这样做的缺点是您需要维护两个代码库,这会使您的工作量增加一倍。对于小型库或想要支持两个版本的新库来说,进行两次错误修复或功能补充是不理想的。我不建议在项目一开始就使用这种方法。

构建脚本

在VueUse中,编写了一些构建脚本,以便在构建时从目标版本的 API 导入代码。之后,我需要发布两个标签vue2 vue3来区分不同版本的支持。有了这个,我可以编写一次代码并使库支持两个 Vue 版本。它的问题是我需要在每个版本上构建两次并引导用户安装相应的插件版本(@vue/composition-api对于Vue 2则需要手动安装)。

Vue 2/3 共存开发的思路

同时⽀持 Vue 2/3 项⽬

Vue 2/3 项⽬存在的可能场景

渐进式迁移: 如果有一个较大的 Vue 2 项目,但是想要逐步迁移到 Vue 3,可以选择在项目中同时引入 Vue 3,然后逐步将 Vue 2 组件迁移到 Vue 3。

依赖库和插件兼容性: 如果项目依赖于一些 Vue 2 的插件或库,而这些插件或库还没有升级到 Vue 3,可能需要同时使用 Vue 2 和 Vue 3 以确保兼容性。

新功能采用 Vue 3: 可能希望项目中使用 Vue 3 来利用其新功能和性能优势,同时保留 Vue 2 用于旧的组件或功能。

项⽬融合者: 公司内部基于体验要求,需要 Vue 2/3项⽬呈现在同⼀⻚⾯中

内部组件资产维护者: 需要在 Vue 2/3 的项⽬都⽀持,且能⼒必须⼀致

⽼项⽬应⽤开发者: 需要⽤到⼀个第三⽅图表组件,但只有 Vue 3 版本,⽽⾮ Vue 2 版本

解决⽅案

1. Vue 2/3 项⽬共存

vue-5

直接通过 Vue 3 的 createApp 创建⼀个 Vue 3 的根实例,然后通过 Vue 2 的 mount ⽅法挂载到 Vue 2 的根实例上,这样就可以在 Vue 2 的项⽬中使⽤ Vue 3 的组件。

相关的代码仓库贴在这里,大家自取:vue5

vue-5

// Vue 3 项⽬
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#vue3')
// Vue 2 项⽬
import Vue from 'vue2'
import App from './App.vue'

new Vue({
  render: h => h(App as any),
}).$mount('#vue2')

这一个思路重要的是我们采用配置vite.config.ts解决不同模块的编译问题:编写了一些构建脚本,以便在构建时从目标版本的 API 导入代码。之后,我需要发布两个标签vue2 vue3来区分不同版本的支持。但是它的问题其实是需要在每个版本上引导用户安装相应的插件版本。这对于开发者处理包冲突问题并不是很友好。

import path from 'path'
import { defineConfig } from 'vite'
import Vue2 from '@vitejs/plugin-vue2'
import Vue3 from '@vitejs/plugin-vue'
import Inspect from 'vite-plugin-inspect'
import compiler from 'vue2/compiler-sfc'

const src = path.resolve(__dirname, 'src')

export default defineConfig({
  plugins: [
    Vue3({
      include: [/vue3[/\\].*\.vue$/],
    }),
    Vue2({
      include: [/vue2[/\\].*\.vue$/],
      compiler: compiler as any,
    }),
    Inspect(),
  ],
})

这样我们属于是将Vue2和Vue3单独做成了两个独立的包,然后在vite.config.ts中配置了不同的编译规则,这样就可以在同一个页面中使用Vue2和Vue3。

2. JessicaSachs/petite 方案

先来简单介绍一下petite

Petite是一个为Vue组件作者构建的主观GitHub模板。 它设置了开发、文档和测试通用SFC组件所需的工具,并与Vue 2.7运行时向后兼容。

这是通过一些运行时辅助函数和一个非常主观的单体库结构实现的。

Petite设置了Vite、Volar、Linting、Vitepress、TypeScript和Testing,这样您就可以选择编写Vue 3风格的代码,同时轻松保持对Vue 2.x用户的向后兼容性。

而这也意味着您将在 npm 上发布软件包的两个版本,而不是为了支持 Vue 2 或 Vue 3 而中断主要版本。

这样做的缺点是您的用户在升级和更改导入时需要安装新版本。 好处是您可以更轻松地编写向后兼容的代码并为用户提供定期升级。此外,您还可以拆分仅 Vue 2 和仅 Vue 3 的依赖项。

如果您在通用代码中使用lodash,您将需要在工作区根目录中运行后pnpm build,每个包 ( lib-vue3、lib-vue2) 应独立部署。

3. vue-bridge 方案

4. vue-demi 方案

仓库实例:vue-demi

Vue Demi是一个开发实用程序,允许您为 Vue 2 和 3 编写通用 Vue 库。无需担心用户安装的版本。

当您要创建 Vue 插件/库时,只需安装vue-demi为依赖项并从中导入与 Vue 相关的任何内容即可。像往常一样发布你的插件/库,你的包将变得通用!

{
  "dependencies": {
    "vue-demi": "latest"
  }
}
import Vue, { reactive, ref } from 'vue-demi'

在底层,它使用了postinstallnpm hook。安装所有包后,脚本将开始检查已安装的 Vue 版本,并将导出重定向到基于本地 Vue 版本。使用 Vue 2 时,@vue/composition-api如果未安装,它也会自动安装。

所需要注意的有关于库/组件的点:

库/组件

  • 单仓库 - 多个包构建
  • 依赖管理
  • alias 别名配置
    • npm 包名
    • 构建工具配置

Vue 2 应⽤中引⼊ Vue 3 组件

会有组件互操作的限制

  • context 共享
  • scoped slots
  • 事件

Vue 2 应⽤中引⼊ Vue 3 组件的思路

  • Vue 3 可以有多个全局实例
  • 前提:Vue 2 升级到 2.7、Vue CLI 移除部分过时插件
  • 互操作层:Custom Elements
  • 构建⼯具:Vite
Vue Components 和 Web 组件Custom Elements 2023-11-24-随笔

評論