文章轉(zhuǎn)載自公眾號:墨箏
前言
我們在使用 webpack 的時候經(jīng)常會用到 webpackbar
或者 progress-bar-webpack-plugin
之類的 webpack 插件通過進度條等方式來展示 webpack 的構(gòu)建進度,以提升構(gòu)建過程中的反饋體驗。對于不同的插件來說,它們只是進度條的 UI 展示形式不同而已,但最核心的 webpack 構(gòu)建的實時進度的數(shù)據(jù)來源卻是一致的,均由 webpack 內(nèi)部的 ProgressPlugin
這個插件提供。下面我會結(jié)合源碼來講解該插件是如何計算 webpack 的構(gòu)建進度并將進度數(shù)據(jù)暴露給第三方的進度條插件。在閱讀下文之前可以試著問下自己:如果是你,你會如何計算 webpack 的構(gòu)建進度。
構(gòu)建進度的計算
該插件主要根據(jù) webpack 的構(gòu)建階段來定義當(dāng)前進度值。webpack 的構(gòu)建過程分為很多不同的階段,在每個階段 webpack 都暴露了對應(yīng)的事件鉤子。ProgressPlugin
正是通過這些事件鉤子對每個階段都定義了一個基礎(chǔ)進度值,代碼如下所示:
上述代碼中的 interceptHook
方法可以先忽略,這個后續(xù)會提到。
通過上述代碼你會發(fā)現(xiàn) ProgressPlugin
給 compiler
中的每個鉤子都設(shè)置了一個指定的進度值。但這些進度值還不夠細致到反映 webpack 的詳細構(gòu)建過程,中間還差了 0.06 到 0.69 以及 0.69 到 0.95 兩個階段的數(shù)值。webpack構(gòu)建的具體執(zhí)行過程主要在 compilation
中,這兩個階段的數(shù)值由 compilation
的鉤子填充。
0.06~0.69
update 方法的調(diào)用由 compilation 的鉤子觸發(fā),如下所示:
這個階段的主要工作是 module
,entry
以及 dependencies
的處理和構(gòu)建。換個角度從 ProgressPlugin
給該階段設(shè)置的進度值來看,這部分工作也是 webpack 最耗時的地方。
0.69~0.95
從上述代碼中可以看出這個間隔段就完全是根據(jù) compilation 的 hooks 來計算和指定當(dāng)前的構(gòu)建進度值,從hook 的描述中可以看出這個階段主要是 module
, chunk
以及assets
等資源的優(yōu)化工作。
基本上整個 webpack 構(gòu)建過程的進度值就是根據(jù)上述中的 compiler
和 compilation
的 hooks 來設(shè)置的。
進度數(shù)據(jù)的透出
webpack 的構(gòu)建進度確定之后剩下的任務(wù)就是將進度數(shù)據(jù)透出給第三方的進度條插件進行展示。要完成該任務(wù)需要ProgressPlugin
完成兩件事情,一是提供回調(diào)函數(shù)的切入口;二是需要能在對應(yīng)的 hook 節(jié)點執(zhí)行該回調(diào)函數(shù)進行進度的百分比值的傳入。以下是這兩點的實現(xiàn)原理
回調(diào)函數(shù)
ProgressPlugin
定義了 handler 函數(shù)來作為回調(diào)函數(shù)切入,代碼如下所示:
hook 劫持
hook 劫持的實現(xiàn)非常簡單,主要利用 webpack hook 原生提供的intercept
方法,前文中提到的interceptHook
方法只是對于 intercept 方法的封裝,示例代碼如下:
結(jié)語
webpack 構(gòu)建的進度條實現(xiàn)原理就是如此簡單,給每個構(gòu)建階段對應(yīng)的 hook 設(shè)置一個進度值,然后通過 handler 回調(diào)和 hook 劫持切入到構(gòu)建環(huán)節(jié)將進度信息傳入回調(diào)函數(shù),最終第三插件通過 handler 獲取到進度值后將其展示出來。 webpack 的很多其他功能其實也沒有想象中的那么復(fù)雜和高大上,通過閱讀其源代碼了解其實現(xiàn)原理后,你很可能會一拍大腿,大嘆一聲原來如此,這本身就是一件挺有意思的事兒。
以上就是W3Cschool編程獅
關(guān)于webpack 構(gòu)建進度條 ProgressPlugin 源碼剖析的相關(guān)介紹了,希望對大家有所幫助。