关于基于patch-vue3升级的项目在阿里云效流水线构建失败的排查日志

282 阅读3分钟

前言

写了个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:'默认值'
        }
      })
    }
  }
}
  • 解决

收集-匹配-转换