拒绝gogocode,vue2升级vue3,看这里

声明

请注意,笔者在写本文时,已经完成了升级改造工作,故部分错误可能无法通过截图呈现,不过笔者会尽可能用语言描述清楚

一次失败的尝试

由于所要改造项目是公司运行六七年的老项目了,内容之大之重可以想象,纯靠人力的话,光是想想就头大

所谓遇事不决先百度,像这类迁移工具必定是有人已经做过了的,于是发现了gogocode

首先,使用npm安装该工具

npm install gogocode-cli -g

接着进行语法转换

在项目根目录执行如下命令

// src是要转换的源
gogocode -s ./src -t gogocode-plugin-vue -o ./src-out

然后静静等待它转换完成

image.png

下一步,对相关依赖做升级,gogocode也提供了相关指令

gogocode -s package.json -t gogocode-plugin-vue -o package.json

这一步执行之后,使用yarn重新安装依赖

yarn

这样工具帮我们处理的工作就完成了,我们先来跑一下lint看看,如下有3k+

image.png

此时,我已经有点打退堂鼓了

先不急,咱们先来看看它转出来的效果

首先,它对package.json转换后,vue的版本是3.0.0。我为什么要特意强调这个呢?

因为这说明了两个问题:

1.现在vue3.3了,它却还在用3.0,这说明大概率它已经鲜有维护更新了

2.3.3的语法与3.0大概率会存在出入,也就是说,它的转换结果未必可信

现在,我们再来看具体的sfc文件的转换

  • props

我们知道,vue3.3props已经被扁平化了,是不需要通过特定的props属性进行传递的,但gogocode对这一部分并未处理

image.png
  • attrs

attrs也有类似的问题

image.png
  • style样式

工具对源码转换后,会导致style标签内的样式错乱,具体来说应该是它无法识别css代码中的注释导致的

  • 格式

除了上述的语法转换问题外,还有其他的,此处不再一一阐述。其实真正让我决定放弃的是,它转换出来感觉有点乱,且对源码的侵入性太大

比如eventBus,修改后,无法和原来一样调用,需要先导入,再使用,且必须手动传入组件实例,伪代码如下

import {$on,$emit,$off} from '../xx/utils'

$on(instance,key,callback)

这成功给笔者造成了将近一千个error,因为项目里用到了400多次

image.png

具体来说,每一个文件都会触发相对路径必须在绝对路径之后引入变量未被使用这两个error

半自动化

现在,笔者打算自己手动修正。不过在开始前,先说原则,原则就是,能不修改原来代码的就尽量不修改,能保证原有调用格式的就尽量保证原来的使用方式

loaders

一些通用的调整,可以通过webpackloader来自动化

  • filters

vue3中已经剔除了filters选项,需要将其移动到methods

image.png

不过,代码有点多,咱这文章毕竟也不是卖钱的小册,所以就只讲一下思路,这也是最重要的:

首先,通过正则提取出script标签的内容部分,然后将其ast化,在通过节点树找到export default部分并将其提取出来转换成对象

转对象的时候,由于部分代码可能是export default外部的,比如

const yyy = 'spp'
export default {
    data(){
        return xxx:yyy
    }
}

这部分直接去解析会报错,因此需要进行try...catch并在捕获到错误时递归

function parse(){
    try{
        ...
    }catch(err){
        if(err){
            parse()
        }
    }
}

接着判断对象中是否存在filters属性,如果有,就对该属性做遍历,将其key提取到methods中,形式大概是这样

export default {
    methods:{
        filtersKey:filtersValue
    }
}

这个filtersValue对应的就是原来的过滤函数,要把它生成到script标签中,具体来说,是import语句和export之间

function filtersValue(){
    ...
}

下一步,就是去template模板中查找使用过滤函数的地方进行替换。这利用正则可以很轻松的完成

image.png
  • props

vue2中可以这样声明props

export default {
    props:{
        xxx:'some value'
    }
}

vue3中会报错。因此需要对此进行转换。具体来说,就是找到props对象,分别对它的key对应的值进行识别。如果是对象或函数则不处理,如果是基本数据类型,则转换成如下形式

{
    type:'原值所对应的数据类型',
    default:'some value'
}

这里比较容易出错的点是关于字符串类型的获取,需要手动拼接上引号

image.png

完整代码如下

image.png
  • bus通信

众所周知,vue3中已经剔除了eventBus,无法再通过new实例的方式来实现跨级通信

但第三方插件又无法保证this指向,一般需要手动传入

但前文我们说过,要尽可能保证原调用方式不变

因此,需要在loader中提取并添加

image.png

这里的注意点在于loader的执行时机,必须要保证它在源代码被转换之前。否则添加的this与回调函数内的this大概率不是一个。如下,是经过转换后的代码,在回调中使用的this其实并不是实际传入的this

var this1 = this
this.$bus.$on(key,this,()=>{
    this1.xxx = 'spp'
})

fixed

还有一些是可以在全局去做兼容的,它们的目的是与改造前的代码行为尽可能保持一致

  • bus通信

在前文loader中虽然解决了eventBus的this指向问题,但还没有找到可替代的包

幸运的是,笔者在之前实现的web-localstorage-plus中实现了该功能

首先,使用web-localstorage-plus提供的接口来代替bus功能

image.png

接着将其挂载到app.config.globalProperties上,这是vue3中提供的类似Vue.prototype挂载方式

image.png

又不幸的是,web-localstorage-plus目前其实并不支持接收this参数,且回调函数也不支持传递多个参数

因此,还需要对这两个接口进行重写。如下,接受参数二并将其挂载到第三个函数参数上,然后在触发on注册的监听函数时手动使用call修改其this指向,并将参数使用展开运算符传递以支持多个参数传递

image.png
  • vue-router

在笔者的业务中,对单点登录进行了校验,并在无权限时跳转到指定的页面,伪代码如下

// 获取权限
this.$router.onReady(...)
// 校验权限
this.$router.beforeEach(...)

这两行代码有两个问题

一个是vue-router4.x中已经废弃了onReady,需要改成isReady代替

image.png

另一个问题是,当页面刷新或执行window.open时,其表现与vue-router3.x不一致

vue-router3.x中刷新并不会触发beforeEach钩子,但vue-router4.x中会触发

这就导致,会触发权限的重新获取,而此时beforeEach钩子执行时还拿不到权限数据导致跳转到noAuth页面

因此,需要对beforeEach钩子进行重写。如下,我们在页面刷新或window.open被执行时向本地设置缓存,并在beforeEach钩子中判断是否存在缓存标记,存在则什么都不做,否则正常跳转路由

image.png
  • $children

vue3中已经剔除了$children接口,需要自己手动实现一份查找逻辑。如下,只需要按指定的格式进行递归即可

image.png
  • $filters

对于注册的全局过滤器,现在统一调整到app.config.globalProperties

image.png
  • view-ui-plus

之前默认注册到全局的loading现在已经没有了,需要根据业务需求做调整

image.png

其他

剩下的,就是需要手动调整的其他语法了

  • vue-router

1-h函数

vue4.x版本中应该已经不支持render函数了,由于笔者公司项目有且仅有这一处对组件的使用,故修改成了默认方式

image.png

实际上,更准确的写法应该是这样

image.png

2-注册方式

4.x中已经不需要使用new关键字了,取而代之的是createRouter接口。另外,mode属性也被history替代了

import { createRouter, createWebHashHistory } from 'vue-router';
export default createRouter({
  history: createWebHashHistory(),
  routes:[...]
})
  • vuex

1-注册方式

vue-router类似,通过createStore替换。

import { createStore } from 'vuex';
export default createStore({...})

2-日志引入

它的日志插件的导入方式要改成下边这样

import { createLogger } from 'vuex';
  • view-ui-plus

对于js模块中使用的消息提示需要手动按需导入

import { Message } from 'view-ui-plus'

Message.error('...')
  • h函数

h函数的变动大致有四个

1-props与attrs

现在不需要在显示的指定这两个属性了,可以直接平铺传递

h('div',{
  //props:{
  //  xxx:'spp'
  //}
  xxx:'spp'
})

2-事件绑定

现在也已经剔除了on属性,而需要改成onEventType的形式

h('div',{
  //on:{
  //  click:()=>{}
  //}
  onClick(){}
})

3-slots

插槽需要改成函数形式

h('div',{
    //slot:'slotName'
    slotName(){}
})

4-组件渲染

现在使用h函数渲染组件有两种方式,笔者采用的方式如下

首先将要导入的组件挂载到全局

import { LoadingBar } from 'view-ui-plus';

app.component('LoadingBar', LoadingBar);

然后借助vue3提供的resolveComponent来执行导入

import { resolveComponent } from 'vue';
h(resolveComponent('LoadingBar'))
  • $set

基于proxyv3已经不需要$set或$delete了,现在直接进行修改即可

  • slot

v3中的插件必须使用template,且写法有变更,如下,现在可以合写成一个了

<template 
  //slot="createTime" 
  //slot-scope="scope"
  v-slot="scope"
>
  ...
</template>
  • 三方组件库

这种每个人的不一样,笔者就不贴了,只说下笔者的处理方式

1-找vue3版本

有些组件库是支持vue3版本的,这部分直接yarn即可

2-修改源码

如果没有v3版本,就利用patch-pkg自己修改源码做兼容

3-copy源码

对于比较复杂的库,笔者是找到其源代码copy了一份,然后在项目中引入并修改

  • vue-loader

项目启动后,页面元素之间的间隙会失效,配置如下

image.png

测试问题修复

  • vue-router传参

4.x已经不支持传递对象形式了

image.png

因为拿到的是字符串,并且这个字符串还没法通过JSON.parse进行解析

image.png

但是又没法一个一个调整,毕竟有一百多处都在使用

image.png

所以还是老规矩,从源码修改。这只需要分两步

第一步,重写push

image.png

第二步,重写query属性

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容