前言
在写了个webpack插件,1722行代码,无感升级到vue3😎一文中已经介绍了其实现思路
但距离真实接入项目却差了很多,以代码量做比较,最终的代码行数为3604行,比之前足足翻了一倍有余
这并不是最糟心的,最糟心的是当本地运行项目正常后,在云效流水线遇到的问题...
正文
- 描述
当在云效流水线构建后,会出现两类问题,一是直接报错,如下
要么是不报错了,但是要构建一个来小时
而笔者本地,经过多次掐表,时间在三分到三分20秒之间浮动
- 问题排查
报错的问题,笔者找到了云效官方,他们看过构建日志后给出的解决方式是
对此,我的看法是
那就先解决自己力所能及的,即流水线构建时间过长的问题
首先,写一个class,用它来log出文件的处理时间,笔者在项目中传入的是两分钟
然后在适当的位置调用
重新跑流水线,发现大多数文件处理耗时都超过了两分钟
但这些在本地只需要五六秒即可
除此之外,还有一个重复处理的问题
- 问题分析与修复
这其实是正常的,因为一个sfc会被vue-loader拆分成三个子请求,带上本身的那一次,也就是四次,这是众所周知且可以接受的事情🤔
但同时也是可以做文章的地方...
首先,我们都知道有一个叫thread-loader的库,他可以批量处理loader请求,引入如下
不可否认的是,它确实起到了一定的作用,在为数不多的成功次数中,它的构建时长平均减少了3分之一左右,但仍然在不可接受的范围内
所以针对一个文件的多次处理,可以尝试增加缓存
但这与thread-loader陷入了鱼和熊掌的尴尬处境
故只能想别的办法......
事实上,如果在webpack运行之初优先执行patch-vue3的转换任务,就可以做到只编译处理一次
显然,beforeResolve钩子最为合适
在钩子内,扫描出所有的.vue文件
将它们分成不同的批次
使用流的方式写入文件
再使用Promise.all做批量
这样就做到了一个文件只处理一次,同时又实现了并发
- 结果
改造后,在无缓存的情况下,一次构建大约需要3-4分钟
其他
在上流水线之前,还修复了许多在接入项目时的问题,在此一并列出...
钩子丢失
- 描述
在前文的实现中,钩子通过hooks对象注册,并挂载到global对象上,但并不是每次都能正确运行钩子回调,会存在找不到的情况从而导致部分页面无法被转换
- 原因
webpack在每次执行transform起始,global会被初始化,导致前一次挂载的hooks对象丢失
- 解决
将hooks列表序列化为字符串形式
然后通过参数传递给loader
上下文缺失
- 描述
前文的实现没有考虑到上下文存在的情况,也就是下边这种写法
const level0 = ...
export default{
methods:{
xxxx(h){
const level1 = ...
return h('div',level0,level1)
}
}
}
- 解决
在处理xxxx之前,将level0和level1收集起来
当遇到Identifier节点类型时做相应的处理
不支持render slot
- 描述
这个严格意义上并不算bug,而是从一开就没打算处理的语法,因为项目中用到的只有不到10个文件,它大致是如下这种写法
export default{
methods:{
xxxx(h){
return h('div',{
slot:'slotName',
domProps:{
innerHTML:'默认值'
}
})
}
}
}
- 解决
收集-匹配-转换