Vue2升级Vue3该用什么工具?怎么选怎么操作?
公司项目还在用Vue2,想升级Vue3但怕成本太高,手动改代码太麻烦?其实Vue生态里有不少专门的工具能帮我们“无痛”迁移,从构建工具到代码自动转换,再到状态管理适配,选对工具组合能把升级难度砍半,今天就唠唠Vue2升Vue3有哪些实用工具,不同项目该咋选咋操作~
官方都给了哪些“保底”迁移工具?
Vue团队很懂开发者痛点,专门出了迁移构建(Migration Build)和代码扫描工具,先从最基础的说起:
迁移构建(@vue/compat):让新旧代码“和平共处”
如果项目特别大,直接全量替换Vue版本风险高,迁移构建就是“过渡神器”,它本质是个兼容包,装了之后Vue2和Vue3的代码能在同一个项目里跑,甚至老组件用Vue2写法、新组件用Vue3写法也不冲突。
实操步骤特简单:
- 先把
package.json
里的vue
版本改成^3.0.0
,然后装兼容包:npm install vue@3 @vue/compat
; - 在入口文件(比如
main.js
)里,原来用Vue
构造函数的地方,换成createApp
创建实例(像Vue.use()
改成app.use()
); - 如果是Webpack或Vue CLI项目,还要在
vue-loader
里配置兼容模式(比如Vue CLI的vue.config.js
里,给vue-loader
加compatConfig: { MODE: 3 }
,让代码更贴近Vue3行为)。
这样改完,项目能先跑起来,之后再慢慢替换老组件——比如把filter
(Vue3移除了)换成computed
,把$children
(Vue3不推荐用)换成refs
,每次迭代改一点,风险特别低。
代码扫描工具:自动揪出Vue2专属API
手动找代码里的Vue2 API(比如$on
、$off
、Vue.filter
这些)太费眼,官方和社区做了codemod脚本,能自动扫描+修改代码,比如社区的vue-3-codemods
,装完后用命令行跑一下,它能:
- 把
Vue.prototype.$http
自动改成app.config.globalProperties.$http
(Vue3全局属性要这么挂); - 把Vuex的
mapState/mapGetters
语法,提前改成Pinia风格(虽然不完全等价,但能减少后续迁移工作量); - 识别并标记即将废弃的API(比如
Vue.directive
要换成app.directive
)。
用法也不难:先全局装jscodeshift
和codemod工具,再用命令指定要扫描的目录,比如jscodeshift -t node_modules/vue-3-codemods/transforms/vue-prototype.js src/components
,跑完之后再手动检查下,基本能解决80%的重复劳动。
构建工具换Vite还是留Vue CLI?
Vue2时代大家常用Vue CLI(基于Webpack),但Vue3更推荐用Vite(基于ESModule),这俩咋选?得看项目情况:
选Vite:中小型项目“一步到位”
Vite最大优势是快——开发时按需编译,不用等Webpack全量打包,启动速度和热更新速度能提升好几倍,如果项目是中小型,依赖没那么复杂,直接换Vite爽翻天:
- 先装Vite和Vue3插件:
npm install vite @vitejs/plugin-vue
; - 把原来的
vue.config.js
换成vite.config.js
,配置别名、CSS预处理器这些(比如把指向src
目录,和Vue CLI保持一致); - 调整入口:原来的
index.html
在public
里,现在要放到项目根目录,里面引入main.js
改成;
- 处理依赖:如果有Webpack专属插件(比如
html-webpack-plugin
),换成Vite的插件(比如vite-plugin-html
),或者手动实现功能。
举个例子:之前用Vue CLI配的less-loader
,Vite里只要装less
就行,它会自动处理less文件,不用再写一堆loader配置,省心多了~
留Vue CLI:大型项目“缓兵之计”
如果项目特别大,直接换Vite怕踩坑,先留着Vue CLI也能过渡,步骤是:
- 把Vue CLI升级到最新版(支持Vue3的compat模式);
- 在
vue.config.js
里配置vue-loader
的兼容模式(和迁移构建配合),让老代码能跑; - 逐步把新组件用Vite开发(比如开个新分支,用Vite建子项目),等团队熟悉Vite后,再全量替换构建工具。
不过长远来看,Vite是趋势,因为Vue3的单文件组件(SFC)特性(比如)在Vite里支持更丝滑,Webpack后续更新也没那么积极了,所以能换尽量早换~
状态管理和路由咋跟着升级?
除了Vue核心,状态管理(Vuex)和路由(Vue Router)也得同步升级,不然功能会崩,这里有俩“黄金搭档”:
Vuex → Pinia:从“繁琐”到“丝滑”
Vuex4虽然能兼容Vue2和Vue3,但Vue团队更推荐用Pinia(可以理解成Vuex5的平替),Pinia优势太明显:
- 没
mutation
了!直接在action
里改状态,代码少一半; - 对TypeScript支持更友好,不用写一堆声明文件;
- 体积更小,API更简洁,学起来更快。
迁移步骤分两步走:
- 先升级Vuex到4.x(兼容Vue3),保证现有功能正常;
- 逐步替换成Pinia:装Pinia→创建store→把原来的Vuex模块(比如
user.js
)改成Pinia的defineStore
格式→替换组件里的mapState/mapActions
为useStore()
。
举个🌰:原来Vuex里的user
模块:
// Vuex写法 const user = { state: () => ({ name: '' }), mutations: { setName(state, name) { state.name = name } }, actions: { fetchName({ commit }) { ... } } }
改成Pinia后:
// Pinia写法 import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ name: '' }), actions: { setName(name) { this.name = name }, // 没mutation了,action直接改 async fetchName() { ... } } })
组件里用的时候,原来的this.$store.dispatch('fetchName')
,改成const userStore = useUserStore(); userStore.fetchName()
,逻辑更直观~
Vue Router 3→4:配置和API的小调整
Vue Router4专门适配Vue3,升级时注意这些变化:
- 创建路由实例:
new Router()
改成createRouter()
; - 路由模式:
mode: 'history'
改成history: createWebHistory()
(还要装history
库); - 导航守卫:
router.onReady()
改成router.isReady()
,全局守卫的参数也有变化(比如next()
被移除,改成返回Promise)。
实操时,先装Vue Router4:npm install vue-router@4
,然后把路由文件里的配置改成新语法,再测试导航跳转、路由传参这些功能,基本没大问题~
不同项目该咋搭工具组合?
工具不是越多越好,得看项目规模、团队技术栈、依赖情况,分享三种常见场景的工具组合:
场景1:大型遗留项目(改造成本高)
这类项目最怕“牵一发动全身”,得用“迁移构建 + codemod + 暂留Vue CLI”组合:
- 先用迁移构建(
@vue/compat
)让项目能跑在Vue3环境,老组件写法不变; - 用codemod工具自动扫描并修改Vue2专属API(比如全局属性、自定义指令钩子),减少手动工作量;
- 暂时保留Vue CLI,等核心功能稳定后,再逐步把构建工具换成Vite(期间用Vue CLI的compat模式保证兼容)。
举个真实案例:某金融项目有几百个组件,用这方法先让项目支持Vue3,再花3个月逐步替换老组件,每周迭代一个模块,测试覆盖率保持80%以上,没出大事故~
场景2:中小型项目(灵活度高)
中小型项目可以“Vite + Pinia + Vue Router4 + codemod”一步到位:
- 直接用Vite替换原来的构建工具,享受极速开发;
- 用codemod扫描代码,自动处理API变化;
- 把Vuex换成Pinia,Vue Router升级到4.x,一次性解决状态管理和路由;
- 新组件用
语法糖,老组件慢慢改,半年内完成全量迁移。
好处是周期短,能快速用上Vue3的新特性(比如Teleport
实现弹窗组件,Suspense
处理异步加载),开发体验直接起飞~
场景3:依赖旧UI库的项目
如果项目用的UI库还没升级到Vue3(比如老版Element UI),得先解决UI库兼容问题:
- 先查UI库是否有Vue3版本(比如Element UI→Element Plus,Ant Design Vue→3.x);
- 如果有,先升级UI库,再用迁移工具处理项目代码;
- 如果没有,先用迁移构建兼容Vue2写法,同时调研替代库(比如Naive UI、Vuetify 3),等UI库升级后再全量迁移。
比如之前有个项目用的是某小众UI库,团队先fork仓库自己改兼容Vue3的版本,同时用迁移构建过渡,等官方升级后再合并代码,也算曲线救国~
实操时那些“坑”咋避?
就算用了工具,也会遇到手动处理的细节问题,分享几个高频“踩坑点”和解决方法:
坑1:全局API挂载方式变了
Vue2里用Vue.prototype.$http
挂全局属性,Vue3得用app.config.globalProperties.$http
,codemod能处理大部分,但要注意:如果有插件在单独文件里挂全局属性(比如plugins/axios.js
),得手动改成app.use
的方式,不然新组件里拿不到$http
。
坑2:响应式数据API差异
Vue2的data
返回对象,Vue3用reactive/ref
,如果老组件用options API,data
还能继续用;但新组件用composition API时,得用reactive
包对象,ref
包基本类型,迁移时,老组件不用急着改,新组件统一用composition API,慢慢过渡。
坑3:自定义指令钩子函数变了
Vue2的自定义指令钩子是bind
、inserted
、update
,Vue3改成created
、mounted
、updated
,比如原来的focus
指令:
// Vue2写法 directives: { focus: { inserted(el) { el.focus() } } }
改成Vue3后:
// Vue3写法 app.directive('focus', { mounted(el) { el.focus() } // inserted换成mounted })
得手动检查所有自定义指令,把钩子函数对应上。
坑4:第三方库兼容问题
比如axios封装的拦截器,原来靠Vue.prototype
挂在全局,现在要确保在app.config.globalProperties
里正确挂载,还要测试拦截器是否生效(比如请求头带token是否正常),如果有库依赖Vue2的内部API(比如Vue.observable
),得换成Vue3的reactive
。
坑5:测试用例全报废
Vue2的测试工具是@vue/test-utils
,Vue3得用@vue/test-utils@next
,升级后,mount
组件的方式变了(比如原来的mount(Component)
要改成mount(Component, { global: { plugins: [...] } })
),还要重新配置Jest或Vitest,确保测试环境支持Vue3语法。
避坑小技巧:迁移时保持测试覆盖率,每改一个模块就跑一遍测试;用feature flag(功能开关)控制新老代码,比如给组件加个v-if="isVue3"
,逐步切换流量,发现问题能快速回滚。
Vue2升Vue3不是“all in”的冒险,而是用工具“拆分成小步”的渐进式升级,选工具时,大型项目靠迁移构建+codemod稳扎稳打,中小型项目用Vite+新生态库一步到位,还要结合UI库、测试等细节,记住核心逻辑:工具是降本的抓手,渐进式是控险的关键,最终目标是用上Vue3的性能和开发体验~要是你正在迁移,不妨先挑一个工具试起来,比如先用codemod扫一遍代码,看看有多少自动能改的部分,心里就有底啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。