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