关于 Vue2 项目迁移至 Vue3 的几点注意事项

举报
SHQ5785 发表于 2024/04/26 14:11:56 2024/04/26
【摘要】 一、前言    1 月 2 日消息,Vue.js 作者尤雨溪发文声称,Vue 2 已于 2023 年 12 月 31 日结束生命周期(EOL),目前 Vue 2 已经无法接收到新功能及修复补丁,还在使用 Vue 2 的开发团队应迁移至最新的 Vue 3 版本。    Vue 2.0 最初发布于 2016 年,至今已经有 7 年历史,尤雨溪表示,2.0 版本是 Vue 成为主流框架历程中的一...

一、前言

    1 月 2 日消息,Vue.js 作者尤雨溪发文声称,Vue 2 已于 2023 年 12 月 31 日结束生命周期(EOL),目前 Vue 2 已经无法接收到新功能及修复补丁,还在使用 Vue 2 的开发团队应迁移至最新的 Vue 3 版本。
    Vue 2.0 最初发布于 2016 年,至今已经有 7 年历史,尤雨溪表示,2.0 版本是 Vue 成为主流框架历程中的一个重要里程碑,“不过随着 Vue 3 的成熟,如今是时候淘汰 Vue 2 了”。

根据公司战略要求,公司项目需进行升级改造,对于前端项目,计划由Vue2升级至Vue3,考虑到存量系统项目体量较大,故需结合两者特点制定可行性迁移方案。

二、Vue3 新特性

当前 Vue 最新稳定版本是 v3.4.21。具有如下新特性:

  1. 增加代码可维护性
    Vue2 使用的是 options API ,代码逻辑比较分散,可读性差,可维护性差。Vue3 使用的composition API 逻辑分明,可维护性高,更友好的支持TS。在 template 模板中支持多个根节点,支持jsx语法。

笔者自身体验是独立使用 Vue2 开发应用项目的时候,不管怎么去组织代码,总是无法避免在 datatemplatemethods 中上下反复横跳,这种弊端在项目规模上来之后会更加明显。而且由于 vue-cli 是基于 Webpack 开发的,当项目规模上来后,每执行一下,调试环境就要 1 分钟时间甚至更长时间,这也是大部分复杂项目的痛点之一。

Vue3Composition API 带来的代码组织方式更利于封装代码,维护起来也不会上下横跳。

但是,Vue3 也不是没有问题,由于新的响应式系统用了 Proxy,会存在兼容性问题。也就是说,如果应用系统被要求兼容 IE11,就应该选择 Vue2。而且,Vue 团队也已经放弃 Vue 3 对 IE11 浏览器的支持。

其实,官方原来是有计划在 Vue3 中支持 IE11,但后来由于复杂度和优先级的问题,这个计划就搁置了下来。

不过,随着前端的快速发展,会发现浏览器和 JavaScript 本身已经有了巨大发展。大部分的前端项目都在直接使用现代的语言特性,而且微软本身也在抛弃 IE,转而推广 Edge。所以 Vue 官方在重新思考后,决定让 Vue 3 全面拥抱未来,把原来准备投入到 Vue 3 上支持 IE11 的精力转投给 Vue 2.7

那么 Vue 2.7 会带来什么内容呢?

Vue 2.7 会移植 Vue3 的一些新特性,让开发者在 Vue2 的生态中,也能享受 Vue3 的部分新特性。在 Vue3 发布之前,Vue2 项目中就可以基于 @vue/composition-api 插件,使用 Composition API 语法,Vue2 会直接内置这个插件,在 Vue2 中默认也可以用 Compositon API来组合代码。

在这里插入图片描述

  1. 提升页面渲染性能
    Vue3 在更新DOM算法上,做了优化。在 Vue2 中,每次更新diff,都是全量对比,Vue3则只对比带有标记的,这样大大减少了非动态内容的对比消耗。

  2. 加强 MVVM 双向数据绑定效率
    Vue2 双向数据绑定利用 ES5Object.definePropert() 对对象属性进行劫持,结合发布订阅模式的方式来实现的。Vue3 中使用了 es6ProxyAPI 对数据代理。
    相比于vue2.x,使用proxy的优势如下:

  • defineProperty只能监听某个属性,不能对全对象监听;
  • 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可);
  • 可以监听数组,不用再去单独的对数组做特异性操作。vue3.x 可以检测到数组内部数据元素变化。
  1. 项目可持续发展
    Vue2已于2023.12.31停止维护,EOL之后,官方就不承诺修复和提供解答,现在继续用 Vue2 存在一定的风险隐患。

三、Vue2 安全保障

对于Vue3来说,并不是所有的Vue2特性被废弃,例如选项式API仍然支持。但同时存在非兼容性改变,对于这部分非兼容性改变,升级迁移过程中就是不得不做的改造工作。关于非兼容性改造,详参官网文档《非兼容性(或称之为破坏性)改变》。

那么,是否必须由Vue2升级至Vue3呢?

对于暂时无法迁移的用户,尤雨溪表示,用户可以更新到 Vue 2 的最终版本(2.7.16),或购买 Vue 2 的扩展支持,从而保证相关框架依然能够获得一定的安全性。

在这里插入图片描述

也就是说,如果不升级至Vue3,Vue2框架潜在的漏洞问题是无法得到修复的,存在一定的安全风险漏洞。当然,对于严重安全漏洞,Vue2还是会继续修复的。这也就不难理解为何规模稍微大点、管理审慎的公司会考虑做框架升级改造。

四、迁移方案

通过工具+手动升级

思路:
第一版可以先从基础进行迁移。完成框架整体升级到Vue3(可运行)之后可以进行细化。

步骤:
第一步: 先把Vue2 框架整体替换成 Vue3,因为目前 Vue3兼容 Options API 写法,这样代码结构可以先不用更改,后期可以逐步修改(因为涉及到所有页面和组件)。之后新增的页面和组件按照 Vue3 新增的 composition API 结构来写。

第二步: 把 Vue3 中已经不再支持的 API 和语法进行修改替换。包括 Vue3 已经不再支持过滤器filterv-model 用法也改变等。

第三步: 把项目使用到的第三方插件和UI框架(Element)替换成Vue3版本,对应用法可能也需要修改。可通过 package.json 进行检索修改。

对于这一步升级有以下几点比较麻烦:

  • 项目中依赖库并不支持vue3
  • vue2vue3的一些破坏性更改;
  • 项目中依赖组件库(ElementUI等)的破坏性更改;
  • 对一些新特性的尝试(vite,ts,pinia)等 公司项目迁移造成稳定性破坏(极其重要);

第四步: 确保项目代码语法编译无误后,需要检查代码中的业务是否正确,避免对公司项目迁移造成稳定性破坏(极其重要)。

第五步: 使用 TypeScript 重构 JS 代码,TypeScriptJavaScript 多了静态类型检查,也增加了一些新的语法,是给项目锦上添花。但是这一步会比较耗时(因为相当于修改把JS代码都要过一遍),但是项目中可以同时存在JS 和 TS,所以可以逐步替换。

使用自动化工具:
通过使用目前比较好用的开源工具可以完成第一步和第二步的转换(及框架转换废弃属性检测),目前使用比较多的就是 gogocode

GoGoCode 是一个基于 ASTJavaScript/Typescript/HTML 代码转换工具,可以用它来构建一个代码转换程序自动化完成如框架升级、代码重构、多平台转换等工作。
当前 GoGoCode 支持解析和操作类型的代码为:JavaScript(JSX)、Typescript(TSX)、HTMLVue

对于工具改造代码,存在很多未知性,项目业务代码中有些比较复杂的(例如表单联动,规则校验等等)可能会对原来的逻辑有影响,需要逐一人工比对和测试。

4.1 迁移辅助工具 @vue/compat 库

使用自动化升级工具进行 Vue 的升级。
小项目不用多说,从 Vue2 升级到 Vue3 之后,对于语法的改变之处,挨个替换写法就可以。但对于复杂项目,需要借助自动化工具来帮我们过渡。

首先是在 Vue 3 的项目里,有一个 @vue/compat 的库,这是一个 Vue 3 的构建版本,提供了兼容 Vue 2 的行为。这个版本默认运行在 Vue 2 下,它的大部分 API 和 Vue 2 保持了一致。当使用那些在 Vue3 中发生变化或者废弃的特性时,这个版本会提出警告,从而避免兼容性问题的发生,帮助开发者很好地迁移项目。并且通过升级的提示信息,@vue/compat 还可以很好地帮助开发者学习版本之间的差异。

在下面的代码中,首先把项目依赖的 Vue 版本换成 Vue 3,并且引入 @vue/compat

"dependencies": {
-  "vue": "^2.6.12",
+  "vue": "^3.2.19",
+  "@vue/compat": "^3.2.19"
   ...
},
"devDependencies": {
-  "vue-template-compiler": "^2.6.12"
+  "@vue/compiler-sfc": "^3.2.19"
}

然后给 vue 设置别名 @vue/compat,也就是以 compat 作为入口,代码如下:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.resolve.alias.set('vue', '@vue/compat')
    ......
  }
}

这时就会在控制台看到很多警告,以及很多优化的建议。参照建议,挨个去做优化即可。

@vue/compat 提供了很多建议后,开发者需要慢慢做修改。但从另一个角度看,“偷懒”是优秀程序员的标志,社区就有能够做自动化替换的工具,比较好用的就是“阿里妈妈”出品的 gogocode,官方文档也写得很详细,就不在这里赘述了。

自动化替换工具的原理很简单,和 VueCompiler 优化的原理是一样的,也就是利用编译原理做代码替换。利用 babel 分析 Vue 2 的源码,解析成 AST,然后根据 Vue 3 的写法对 AST 进行转换,最后生成新的 Vue 3 代码。

对于替换过程的中间编译成的 AST,可以理解为用 JavaScript 的对象去描述这段代码,这和虚拟 DOM 的理念有一些相似,基于这个对象去做优化,最终映射生成新的 Vue 3 代码。

五、迁移注意事项

5.1 升级和兼容性

首先,需要确保项目依赖项都与Vue3兼容。一些依赖库可能需要更新才能与Vue3协同工作。在升级过程中,可能还需要进行一些代码调整以适应Vue3的新变化。因此,在升级之前,建议先确保项目在最新版本的Vue2中运行正常。

5.2 组件的改变

Vue3对组件系统进行了许多改进。现在,组件默认是按组合(Composition)编写的,而不是按选项(Options)。这意味着在Vue3中,需要使用setup函数来定义组件的状态和属性。如果正在将一个使用Vue2的旧组件迁移到Vue3,那么这将是一个重大的改变。当然,对于选项式API,Vue3目前还是支持的,后期是否废弃不得而知。

解决方法:
setup函数用于新创建的组件,以及需要使用组合API的任何现有组件。对于那些不需要组合API的组件,可以选择不使用setup函数,并继续使用旧的选项API。

5.3 Composition API

Vue3引入了组合API,它是一个更灵活、更强大的方式来组织和复用组件逻辑。然而,这并不意味着组合API可以完全替代选项API。在某些情况下,可能需要同时使用两种API。

解决方法:
对于需要使用组合API的组件,确保理解了它的工作方式,并正确地将其应用于项目代码。同时,对于那些仍然需要使用选项API的组件,确保正确地进行了转换。

5.4 Vue Router

Vue Router是Vue.js的官方路由库。在Vue 3中,Vue Router也得到了更新。如果正在使用Vue Router2,那么需要了解一些重要的改变。

解决方法:
确保阅读了Vue Router 4的文档,并理解了新API的工作方式。特别是要注意createRouter函数和新的导航守卫的变化。如果遇到了任何问题,可以查看Vue Router的迁移指南以获取帮助。

5.5 Vuex

Vuex是Vue.js的状态管理库。如果正在使用Vuex 2,那么你需要了解一些重要的改变。

解决方法:
确保阅读了Vuex 4的文档,并理解了新API的工作方式。特别是要注意createStore函数和新的模块系统的变化。如果遇到了任何问题,可以查看Vuex的迁移指南以获取帮助。

5.6 其他库和插件

如果项目还使用了其他库或插件,例如Vuetifyvue-tables,确保这些库或插件已经更新到与Vue3兼容的版本。

解决方法:
查看这些库或插件的文档,并检查是否已经发布了与Vue3兼容的版本。如果有必要,你可以考虑迁移到替代库或自行编写必要的功能。

总结:
Vue2迁移到Vue3可能会遇到一些挑战,但只要了解了新版本的变化并采取正确的措施,就可以成功地进行迁移。在迁移过程中,保持耐心并持续测试你的代码以确保一切正常工作是非常重要的。

5.7 差异示例

了解一下 Vue3 不兼容的那些具体语法,除了可以帮助开发者在升级项目后,避免写的代码无法使用,还会让更好地适应 Vue3。详细的兼容性变更,官方有一个迁移指南。

5.7.1 创建vue

首先,来看一下 Vue 2 和 Vue 3 在项目在启动上的不同之处。在 Vue 2 中,使用 new Vue() 来新建应用,有一些全局的配置会直接挂在 Vue 上,比如通过 Vue.use 来使用插件,通过 Vue.component 来注册全局组件,如下面代码所示:

Vue.component('el-counter', {
  data(){
    return {count: 1}
  },
  template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
let VueRouter = require('vue-router')
Vue.use(VueRouter)

上述代码注册了一个 el-counter 组件,这个组件是全局可用的,它直接渲染一个按钮,并且在点击按钮的时候,按钮内的数字会累加。

然后注册路由插件,这也是 Vue 2 中使用 vue-router 的方式。这种形式虽然很直接,但是由于全局的 Vue 只有一个,所以当在一个页面的多个应用中独立使用 Vue 就会非常困难。

看下面这段代码,在 Vue 上先注册了一个组件 el-counter,然后创建了两个 Vue 的实例。这两个实例都自动都拥有了 el-couter 这个组件,但这样做很容易造成混淆。

Vue.component('el-counter',...)
new Vue({el:'#app1'})
new Vue({el:'#app2'})

为了解决这个问题,Vue 3 引入一个新的 API ,createApp,来解决这个问题,也就是新增了 App 的概念。全局的组件、插件都独立地注册在这个 App 内部,很好的解决了上面提到的两个实例容易造成混淆的问题。下面的代码是使用 createApp 的简单示例:

const { createApp } = Vue
const app = createApp({})
app.component(...)
app.use(...)
app.mount('#app1')
const app2 = createApp({})
app2.mount('#app2')

createApp 还移除了很多常见的写法,比如在 createApp 中,就不再支持 filteronoffsetdelete 等 API。

在 Vue 3 中,v-model 的用法也有更改。其实 Vue 3 还有很多小细节的更新,比如 slotslot-scope 两者实现了合并,而 directive 注册指令的 API 等也有变化。

vue2写法 :

import Vue from 'vue'

vue3写法 :

import { createApp } from 'vue'  //引入vue的构造函数createApp ,官网推荐
import App from './App'  //  引入主页面
const app = createApp(App) 

以上3句才能真正创建vue。

5.7.2 定义时间格式全局过滤器

vue2写法 :

Vue.filter('dateFormat', function (daraStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
   return moment(daraStr).format(pattern)
 })

vue3写法 :

// 定义时间格式全局过滤器
app.config.globalProperties.$filters = {
	dateFormat(daraStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
		return moment(daraStr).format(pattern)} 
}

5.7.3 vue2自定义组件中使用到的修饰符sync

例如::trees.sync:model.sync
v-model.sync 将表单元素的值与数据对象中的 username 属性进行双向绑定。当输入框的值发生变化时,username 属性的值也会自动更新;反之亦然。

解决办法: 直接去除sync关键字即可

例如,vue2写法定义组件:

<treeItem v-for="(model,i) in treeDataSource" 
	:key="'root_node_'+i" 
	:root="0"  
	:num="i" 
	:nodes="treeDataSource.length" 
	:trees.sync="treeDataSource" 
	:model.sync="model" ></treeItem>

vue3写法定义组件:

<treeItem v-for="(model, i) in treeDataSource" 
	:key="`root_node_${i}`" 
	:root="0" 
	:num="i" 
	:nodes="treeDataSource.length"  
	:trees="treeDataSource" 
	:model="model" ></treeItem>   

六、综述

综上所述,首先,如果要开启一个新项目,那直接使用 Vue 3 是最佳选择。
Vue2升级至Vue3过程中,需要考虑如下要点:

  • 依赖包升级
  • 非兼容性改造
  • 浏览器兼容性

七、拓展阅读

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。