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…

相關文章
相關標籤/搜索