04 | 升级:Vue 2项目如何升级到Vue 3?

你好,我是大圣,欢迎进入课程导读篇的第四讲。

在上一讲,我带你了解了Vue 3 的新特性。对于Vue 3 相比于 Vue 2 有哪些优势这个问题,相信你已经了解得很清楚了。那么在这一讲,我来教你如何把Vue 2 的项目升级到Vue 3。

把Vue 2 的项目升级到Vue 3,也是小圣一直关心的问题,今天早晨小圣还问我,既然Vue 3 如此优秀,是不是应该赶紧把项目都升级到Vue 3?

首先不要着急,并不是所有项目都适合升级。就像苹果出了新款手机,哪怕新特性被人们说得天花乱坠,但是,是不是把老手机换掉,也需要斟酌,毕竟升级总是需要成本的。

应不应该从Vue 2 升级到Vue 3

应不应该升级?这个问题不能一概而论。

首先,如果你要开启一个新项目,那直接使用Vue 3 是最佳选择。后面课程里,我也会带你使用Vue 3 的新特性和新语法开发一个项目。

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

而 Vue 3 的Composition API带来的代码组织方式更利于封装代码,维护起来也不会上下横跳。Vite则带来了更丝滑的调试体验,一步步跟着专栏完成你的第一个 Vue 3 项目,你会感受到Vue 3 的魅力。

Vue 3 的正式版已经发布有一年了,无论是辅助工具,还是周边库都已经非常完善了,足以胜任大型的项目开发。并且,现在也有越来越多的公司正在尝试和体验Vue 3。所以新项目可以直接拥抱Vue 3 的生态,这也是现在很多团队在做的尝试。

而且对于Vue 2,官方还会再维护两年,但两年后的问题和需求,官方就不承诺修复和提供解答了,现在继续用 Vue 2 其实是有这个隐患的。

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

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

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

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

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

后面,我会带你学的<script setup>语法,也会在Vue 2中得到支持。当然,如果我们想用更精简的方式去组织代码,也是没问题的,因为Vite中也正式支持了Vue 2。

综上所述,我们用下图来回答这一讲开头的问题,要不要使用Vue 3,还是要“因地制宜”,在不同的场景下,我们选择合适的方式即可。

Vue 3 不兼容的那些写法

通过前面的分析,在选择Vue 2 还是Vue 3 这个问题上,相信你现在已经有了自己的取舍。如果最后你依然决定要升级Vue 3,那我就先带你了解一下 Vue 3 不支持的那些写法、之后为你讲解它的生态现状,最后,我们再进入到实操升级的环节。

了解一下 Vue 3 不兼容的那些具体语法,除了可以帮你在升级项目后,避免写的代码无法使用,还会让你更好地适应Vue 3。详细的兼容性变更,官方有一个迁移指南,我在这里就不一一给出了。同样,也为了避免八股文的形式,我在这里介绍几个重要的变更,后面项目中用到一些写法的时候,我再详细地告诉你。即使现在说太多细节,可能你也记不住。

这一部分内容,主要是针对有Vue 2 开发经验的,希望更快地适应Vue 3 的同学。在全面实战Vue 3 之前,你不必完整阅读官方的指南,因为Vue 3 的大部分 API 都是对 Vue 2 兼容的。

首先,我们来看一下 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中,就不再支持filter、$on、$off、$set、$delete等API。不过这都不用担心,后面我会告诉你怎么去实现类似这些API的功能。

在 Vue 3 中,v-model 的用法也有更改。在后面讲到组件化,也就是我们需要深度使用v-model的时候,我会再细讲。 其实 Vue 3 还有很多小细节的更新,比如slot和slot-scope两者实现了合并,而directive注册指令的API等也有变化。你现在记不住这些也不要紧,我们会在后面的实战项目里逐渐掌握这些内容。

Vue 3 生态现状介绍

在 Vue 生态中,现在所有官方库的工具都全面支持 Vue 3 了,但仍然有一些生态库还处于候选或者刚发布的状态。所以,升级Vue 3 的过程中,除了 Vue 3 本身的语法变化,生态也要注意选择。有一些周边的生态库可能还存在不稳定的情况,开发项目的时候我们时刻关注项目的GitHub 即可。

Vue-cli4 已经提供内置选项,你当然可以选择它支持的 Vue 2。如果你对 Vite 不放心的话,Vue-cli4 也全面支持 Vue 3,这还是很贴心的。

vue-router 是复杂项目必不可少的路由库,它也包含一些写法上的变化,比如从 new Router变成 createRouter;使用方式上,也全面拥抱 Composition API 风格,提供了 useRouter 和useRoute 等方法。

Vuex 4.0 也支持 Vue 3,不过变化不大。有趣的是 Vue 官方成员还发布了一个 Pinia,Pinia 的 API 非常接近 Vuex5 的设计,并且对 Composition API 特别友好,更优雅一些。在课程后续的项目里,我们会使用更成熟的 Vuex4。

其他生态诸如 Nuxt、组件库Ant-design-vue、Element 等等,都有 Vue 3 的版本发布。我开发维护的 Element3 是一个教育项目,我们在组件化章节会详细介绍。除此之外,我们项目中也会使用 Element3 来作为组件库。并且在进阶开发篇,我们会自己设计一个类似风格的组件库。

使用自动化升级工具进行Vue的升级

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

首先是在 Vue 3 的项目里,有一个 @vue/compat 的库,这是一个 Vue 3 的构建版本,提供了兼容 Vue 2 的行为。这个版本默认运行在 Vue 2 下,它的大部分 API 和 Vue 2 保持了一致。当使用那些在 Vue 3 中发生变化或者废弃的特性时,这个版本会提出警告,从而避免兼容性问题的发生,帮助你很好地迁移项目。并且通过升级的提示信息,@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,官方文档也写得很详细,就不在这里赘述了。

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

图片

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

关于AST的细节,在课程后面的 Vue 3 生态源码篇中,我会带你手写一个迷你版的 Vue 3 Compiler,那时你会对 AST 和它背后的编译原理有一个更深的认识。

总结

我们来总结一下你今天都学到了什么吧。首先,我带你明确了什么时候该升级 Vue 3,什么时候该继续使用 Vue 2的兼容版本。现在,Vue 3 的官方生态在整体都比较稳定,新的项目完全可以直接选择 Vue 3。并且,对于那些需要长期维护的项目,其实也很有必要进行升级。不过,Vue 2 很快会停止更新,如果你的项目需要兼容 IE11,那就需要继续使用 Vue 2.7。这样,在保持好项目的兼容性的前提下,还可以体验到 Composition API 带来的便利。

然后,在升级Vue的过程中,我们可以利用官方和社区的工具,帮助我们高效地升级。我们可以使用compat来给出提醒,项目中设置@vue/compat作为 vue 的别名,这样内部就会把所有和 Vue 2 的语法相关的升级信息提示出来,逐个替换即可,或者直接使用 gogocode 进行自动化批量替换。

最后,我想说的是,全面拥抱 Vue 3 也算是一次离开舒适圈的挑战,这带来的不只是新框架的体验,同时也可能是更好的潜力与更好的待遇。课程导读篇也到此结束了,在课程的下一篇,我们会开始实战一个 Vue 3 的项目,与此同时,我也会手把手带你通过实战学会 Vue 3。

思考题

你可以分享一下,在你的项目里,有没有需要升级的地方?有的话,又在什么地方呢?

欢迎你在留言区跟我交流讨论,也推荐你把这一讲推荐给你自己的朋友、同事。我们下一讲见!

精选留言

  • cwang

    2021-10-25 09:52:21

    谢谢大圣老师的讲解,我还有一个小的疑惑,我们通常创建Vue应用,一个实例(new Vue({}))就能满足我们的使用场景了,而且也认为应该只存在一个。但是在课程里老师说(Vue2和Vue3启动不同):有一个页面的多个应用的情况。所以想了解下,什么情况下会遇到这种场景呢?这个问题不是这节课的主题,但是还是很好奇,谢谢大圣老师解惑。
    作者回复

    这种场景非常少,不过我遇见过,就是有的后台管理系统是jquery的,有的模块后来的前端就像用vue开发,就会有一些部分模块使用的vue,多个模块之间就会用不同的vue实例

    2021-11-11 21:57:29

  • 。。。

    2021-10-29 15:49:32

    有几个问题需求请教下:
    1. Tree-shaking 清理代码 什么意思,什么时候用
    2. 到底什么是 Composotion api ,vue 2 的是 Options api?
    3. vue3 周边,或者说是 vue 全家桶都包括哪些vue技术
    4. AST 是什么,全称是什么
    5. 虚拟 DOM 是什么,怎么理解
    作者回复

    1. tree shaking就是打包的时候可以删掉你没有用到的模块,减小上线代码的体积
    2. 我们课程中用的全部都是componsition api,vue2中全部都是从this上取数据的方式就是options api
    3. 全家桶就是vuex vue-router 加上一个组件库
    4,ast全称是抽象语法树
    5. 虚拟dom就是用js的对象去描述一个html标签或者组件

    2021-12-13 22:07:44

  • ll

    2021-10-25 09:40:02

    全面拥抱Vue 3会有更好的待遇,敲敲黑板,重点😎
    作者回复

    那是必须的 工资驱动

    2021-10-25 17:58:57

  • 码农初上路

    2021-10-25 15:24:54

    大圣好,vue2.7最低也能支持到IE9吗?
    作者回复

    对的,Vue2基于Object.defineProperty来做,兼容不了IE8

    2021-10-25 17:51:06

  • CondorHero

    2021-10-25 11:02:40

    讲的很细,很赞👍🏻,有个小需求,希望大圣老师加上推荐阅读这样类似的章节。
    作者回复

    阅读推荐指的是文章合集吗?

    2021-10-25 17:52:37

  • 南山

    2021-10-26 10:35:21

    打卡
    目前部门的老项目用的@compositon/api包使用vue3的composition api来重构和优化,新项目直接使用vue3来开发
    开阔眼界了,使用ast语法编译来转换vue2代码,真是一劳永逸!
    作者回复

    看来是用了gogocode,是不是非常的哇塞

    2021-10-26 20:45:19

  • 淡若清风过

    2021-10-26 10:32:56

    拐了,还以为已经录制好的视频拿来卖,看来是到明年都更新不完
    作者回复

    极客时间的更新策略,也算是帮你制定了一个学习计划吧

    2021-10-26 20:45:46

  • 无双

    2021-10-25 18:24:26

    麻烦问一下,在哪有vue2的支持周期?
    作者回复

    Vue3的全球发布会上,尤雨溪ppt里,Vue2还会支持18个月

    2021-10-26 20:57:30

  • 不负

    2021-12-21 15:59:34

    讲得很全面了,就是不太理解下面这段里,一个全局组件,有多个Vue实例,不就是全局组件吗,这里的“造成混淆”是指什么?
    “我们在 Vue 上先注册了一个组件 el-counter,然后创建了两个 Vue 的实例。这两个实例都自动都拥有了 el-couter 这个组件,但这样做很容易造成混淆。”
    ```
    Vue.component('el-counter',...)
    new Vue({el:'#app1'})
    new Vue({el:'#app2'})
    ```
    作者回复

    指的是在一部分老的项目中,一个页面会有好几个Vue的实例,就是用new Vue创建好几次,会有命名混淆的问题,大部分项目都是一个Vue的实例,这是一个边缘的case

    2021-12-23 11:15:51

  • 球球

    2021-10-25 09:21:30

    vue2升级成vue3 对应用到的element ui 也要升级是吗
    作者回复

    是这样的,可以选择element-plus或者element3

    2021-10-25 18:00:37

  • Mserke

    2021-10-25 22:47:32

    思考题:有需要升级的地方,项目越来越大了,要拆分成微服务
  • Shane灬7

    2022-02-24 11:07:07

    先给大圣老师点赞,发现一个问题,“是否使用 Vue 3”那张图中的“是否要长期维护”的“是”和“否”的位置是不是反了?
    作者回复

    已经和作者确认啦:这个图应该没反哦,需要长期维护的话,就建议升级Vue3 ,因为Vue2很快官方就不在维护了,如果只是临时项目,就建议继续用Vue 2维护。

    2022-02-24 13:00:48

  • T1M

    2021-12-02 18:27:34

    打个卡----我用的ruoyi框架,准备尝试把前端升级到vue3。
  • 徐三宝

    2021-11-09 17:19:41

    老师您好,
    我们在Vue2升级Vue3时遇到了一些问题,请指点~
    1,Vue2项目中,我们会把一些数据绑定到Vue上,比如Vue.$reqList存放了请求中的异步请求,然后在axios.js的拦截器中去监听和处理,但是在Vue3中变更成了app.config.globalProperties.$reqList,但是却无法在普通的js文件中(比如axios.js)中拿到这个值。
    作者回复

    其实放在一个全局变量里获取就可以

    2021-11-11 21:44:31

  • 章剑

    2021-11-04 22:50:27

    大圣老师,我最近也在升级vue3中,总体来说compositionApi 还是比较舒服的, 但是mixin有个特性,就是引入页的同名方法可以替换mixin 的方法,在之前的vue 2框架里,这个特性能让部分逻辑更容易修改,打个比方,有一套表单提交的mixin ,其中有个逻辑是提交完表单后重置表单,正常就是调用自定义的resetform 方法,如果需要有特殊操作的话,直接在引入页重新定义一个同名方法重写这个逻辑就可以了。但是在vue3 中我就不知道怎么比较好的处理这种情况了。还请指点下
  • hyangteng

    2021-11-04 12:18:59

    请问下:vue2使用composition-api,涉及到vuex的如何处理

    例如:
    如何获取vuex中的状态
    如何提交mutation和action
    作者回复

    使用useStore

    2021-11-11 21:51:52

  • 起風了

    2021-10-26 14:52:18

    老师好,手头上有个项目,是基于vue2的ant design pro vue来迭代的,还使用了一些其他例如表格组件库等,都是vue2的. 如果要升级vue3的话,使用@vue/compat的同时,其他的那些插件或组件库也要升级vue3版本对应的?如果其他插件或组件库没有vue3版本的是不是升级就比较困难或者不可行了?
    作者回复

    @vue/compat可以处理大部分场景,但是组件库是个例外,因为很多组件库对Vnode本身的格式都做了定制,很难自动化升级, antd-vue现在也全面支持vue3了 直接换最新版本也不难的

    2021-10-26 20:44:22

  • InfoQ_cd01f1df2496

    2022-09-30 11:41:17

    这讲内容我最大的收获是vue2升级vue3,可以使用@vue/compat帮助我们更好的升级,因为它能把所有vue2相关的升级信息提示出来;再来就是可以使用gogocode帮助我们自动化的完成vue2到vue3的升级
  • 这个需求做不了

    2022-06-12 17:53:34

    老师你的element3 官方文档呢?
  • 熊能

    2022-01-23 11:20:06

    vue2.7能支持IE6么?