CI环境下cache-loader的局限性以及修复方式

背景:

想把node_modules/.cache目录上传到一个中心化仓库,而后在CI过程构建的时候,能够拉下来重复利用。可是实践中,虽然.cache的确拉下来了,业务代码也一点没变,可是缓存就是没有生效。探究其缘由,最后发现是cache-loader的基于时间(mtime)的缓存验证机制带来的问题。vue

cache-loader如何工做

cache-loader做为webpack的loader,会在pitch和loader两个阶段分别作一些事情:node

  1. pitch阶段:校验缓存文件是否可用webpack

  2. loader阶段:判断当前loader的文件是否须要从新生成缓存git

pitch和loader与DOM的capture和pop很像,假设有这样一个loader配置:github

代码块
loader: ['cache-loader', 'vue-loader']复制代码

那么pitch阶段的处理流程是:cache-loader -> vue-loader,而loader阶段的处理流程是:vue-loader -> cache-loader。而且,在这两个阶段能够经过一个共享的data对象来传递消息web

pitch阶段

根据当前正在处理的文件,读取.cache目录中对应的cache文件,这个文件主要主要有两部份内容:缓存

  1. 当前正在处理的文件所依赖的文件bash

  2. 当前正在处理的文件,在上一次loader过程当中的产物spa

其中第1点用来判断当前文件的缓存是否依然有效,若是判断有效,那么就直接复用第2点的内容。code

loader阶段

在这个阶段,咱们要判断当前文件是否须要从新生成缓存,判断逻辑很简单:

若是pitch阶段的判断当前文件的缓存失效了,那么loader阶段就要去生成缓存。

局限性

在CI环境中,屡次部署之间是隔离的,也就是说node_modules中的全部文件每次都会从新生成,因此node_modules/.cache目录天然就丢失了。

那咱们天然会想到一个办法:在编译后把node_modules/.cache存到云上,而后在下次编译的时候再来下来。的确,这个方案是没问题的,

可是在实施的过程当中,却遇到了一个问题:上述先存再拉的流程确实执行了,可是cache-loader仍是会从新生成缓存,并无利用上。

基于这个现象去看了cache-loader代码后发现,在cache-loader的pitch阶段,它的“判断当前文件的缓存是否依然有效”的方法是:基于文件最后修改时间(mtime)来判断。

简单的来讲就是:咱们虽然从云上拉下来了上一次编译产生的缓存文件,与yarn从新安装的node_modules里的文件,存在mtime不一致问题,致使判断为“缓存失效”。

找到问题的缘由后,翻了翻cache-loader的issues,发现你们也在吐槽只支持mtime判断这件事,可是cache-loader不打算推出新的判断方式,而是推荐你们等webpack5的多级缓存功能。

基于这个事实,咱们只能去二次开发cache-loader,让它支持新的对比方式,从而解决上述问题。

cache-loader提供了自定义compare方法的接口,可是这个接口回调的参数没法让咱们去获取文件hash,因此至关因而个摆设。

同时这个compare接口也已经上线了,再去改compare接口的回调参数,是一个breaking change,也不太现实。

新的对比方式

咱们天然想到判断文件是否发生变更的方法:hash对比。由于hash不会随时间地点变化,它能够完美解决上述问题。具体方案是:

在pitch阶段使用hash对比判断缓存是否有效,若是缓存无效或没有缓存,接着在loader阶段读取文件并生成hash存入到缓存中。

具体代码:github.com/fxxjdedd/ca…

相关文章
相关标签/搜索