1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        從源碼出發(fā)探索理解 webpack 核心特性

        共 5397字,需瀏覽 11分鐘

         ·

        2023-01-11 14:51

        本文為稀土掘金技術(shù)社區(qū)首發(fā)簽約文章,14天內(nèi)禁止轉(zhuǎn)載,14天后未獲授權(quán)禁止轉(zhuǎn)載,侵權(quán)必究! 前言

        webpack作為模塊打包工具,在前端界可以說是惡棍天使一般的存在,前端人對它大多數(shù)對它都是咬牙切齒的,以至于后面出現(xiàn)vite,以及剛剛出爐號稱比webpack快700倍的Turbopack,日薄西山的webpacK儼然已經(jīng)成為過氣網(wǎng)紅,但是在目前來說,很多公司老項目都還是用webpack體系進(jìn)行打包,面試的時候,往往也是會提一嘴,你做過什么優(yōu)化,webpack的一些原理和知識點好像還是必備, 早在兩年前我就寫過一篇文章《前端開發(fā)中常用的webpack優(yōu)化和相關(guān)原理》,那會還是webpack4,后來2020年10月10號左右,webpack5橫空出世,截止到今天2022年10月,webpack已經(jīng)更新到V5.75,再次重新去“順藤摸瓜”式的去粗讀源碼,溫故知新,當(dāng)然大家也可以帶著下面的問題思考:

        • 1、webpack的構(gòu)建流程是怎么樣的?
        • 2、webpack-cli對于文件打包是必須的嗎?
        • 3、webpack中l(wèi)oader先執(zhí)行還是plugin先執(zhí)行?
        • 4、webpack中 loader 的鏈?zhǔn)秸{(diào)用與執(zhí)行順序是怎么樣的?
        • 5、 module.rules的loader的加載和傳遞流程是怎么樣的呢?
        • 5、 webpack優(yōu)化新的思考
        一、webpack的核心工作過程中的關(guān)鍵環(huán)節(jié)怎么樣的?

        1.1 梳理前置知識

        webpack4(2018年2月)開始它的CLI部分單獨抽離在?webpack-cli?模塊中,接下來我們就帶著源碼一點點來探索,webpack的核心工作流程。
        注:本文下載的

        webpack源碼版本為"version": "5.75.0"
        webpack-cli源碼版本為"version": "4.10.0"

        通過 上篇文章《前端工程化基建探索(3)定制腳手架模板——前端新建項目的“反卷利器”》我們對cli腳手架有個基礎(chǔ)知識儲備,現(xiàn)在閱讀起源碼來,也稍微更有方向感,我們從github下載webpack源碼到本地,直奔主題。

        1.2 啟動webpack都做了什么

        查看webpack啟動文件,我們可以看到它首先做了一些判斷是否安裝了webpack-cli,如果不安裝webpack-cli,程序運行就結(jié)束。03c9609f9aa8b0f6b174cd86004aa19b.webp這里我們重點關(guān)注?runCli?函數(shù),調(diào)用它會執(zhí)行?webpack-cli?中bin目錄下的cli.js?文件,后面的工作就交給webpack-cli?處理了。

        接下來我們關(guān)注點轉(zhuǎn)移到webpack-cli?源碼,webpack-cli的啟動文件,打開webpack-cli/bin/cli.js

            #!/usr/bin/env?node

        "use?strict";

        const?importLocal?=?require("import-local");
        const?runCLI?=?require("../lib/bootstrap");

        if?(!process.env.WEBPACK_CLI_SKIP_IMPORT_LOCAL)?{
        ??//?Prefer?the?local?installation?of?`webpack-cli`
        ??if?(importLocal(__filename))?{
        ????return;
        ??}
        }

        process.title?=?"webpack";

        runCLI(process.argv);

        最終它去執(zhí)行await cli.run(args),用來處理命令行參數(shù)

        e2fd30d2246a5b9fabf842fc8f60fef6.webpimage.png

        然后我們?nèi)タ纯?require("./webpack-cli")?里面的?run()?函數(shù),這個run函數(shù),足足有700多行代碼(看完燒腦),總的來說是處理命令行,并通過調(diào)用webpack的核心函數(shù),構(gòu)建compiler 對象,最后再執(zhí)行整個構(gòu)建流程。

        8001a142df68530fcdcd985422d85bc4.webpimage.png

        結(jié)論:webpack-cli對于文件打包不是必需的,因為它只是處理命令行參數(shù),我們也可以自行設(shè)計cli來處理參數(shù),比如我們常見的 Vue/React框架也是沒有使用webpack-cli

        啟動流程總結(jié)

        84176eff853d99a9ffc6cbbaac36357b.webpwebpack啟動流程.png

        內(nèi)部的運行機制

        48ec6c3f63036dd8ca83b050e386e6a6.webp
        (圖片來源:點擊圖片即可直達(dá))

        1.3 整理一下Webpack 核心工作過程中的關(guān)鍵環(huán)節(jié)

        一、初始化參數(shù)

        (1)從配置文件解析配置項,開始載入?Webpack?核心模塊,傳入配置選項,這部分工作由?webpack-cli?處理

        二、 開始編譯

        (1)?run():編譯的入口方法
        (2)?run觸發(fā)compile,接下來就是開始構(gòu)建options中模塊
        (3) 構(gòu)建compilation對象。該對象負(fù)責(zé)組織整個編譯過程,包含了每個構(gòu)建環(huán)節(jié)所對應(yīng)的方法對象內(nèi)部保留了對compile對象的引用,并且存放所有modules, chunks,生成的assets以及最后用來生成最后JS的template。(4) compile中觸發(fā)make事件并調(diào)用addEntry
        (5) 找到入口js文件,進(jìn)行下一步的模塊綁定

        三、 構(gòu)建模塊

        (1) 解析入口js文件,通過對應(yīng)的工廠方法創(chuàng)建模塊,保存到compilation對象上(通過單例模式保證同樣的模塊只有一個實例)
        (2) 對module進(jìn)行build了。包括調(diào)用loader處理源文件,使用?acorn生成AST并且遍歷AST,遇到requirt等依賴時,創(chuàng)建依賴?Dependency加入依賴數(shù)組。
        (3)?module已經(jīng)build完畢,此時開始處理依賴的module?異步的對依賴的module進(jìn)行build,如果依賴中仍有依賴,則循環(huán)處理其依賴

        四、 完成模塊編譯

        (1) 調(diào)用seal方法封裝,逐次對每個module和?chunk進(jìn)行整理,生成編譯后的源碼,合并,拆分。每一個chunk對應(yīng)一個入口文件。
        (2) 開始處理最后生成的js

        五、 輸出資源

        根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個個包含多個模塊的?Chunk,再把每個?Chunk?轉(zhuǎn)換成一個單獨的文件加入到輸出列表

        (1)所有的module,chunk仍然保存的是通過一個個require()聚合起來的代碼,需要通過Template產(chǎn)生最后帶有_webpack_require()的格式
        (2)MainTemplate:處理入口文件的module,?ChunkTemplate:處理非首屏,需異步加載的module
        (3)注意這里開始輸出生產(chǎn)的?assets,插件有機會最后修改assets

        六、 輸出完成

        在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)。(1)不同的dependencyTemplates,如CommonJs,AMD... (2)生成好的js保存在compilation.assets中 (3)通過emitAssets將最終的js輸出到outputpath

        二、解析通過源碼webpack的中的一些疑問

        2.1 webpack中l(wèi)oader先執(zhí)行還是plugin先執(zhí)行?

        其實這個是一個偽命題,,單從字面上是不能判斷執(zhí)行順序的,大家都知道plugin?負(fù)責(zé)webpack除了模塊化打包外其他多樣性的構(gòu)建任務(wù)處理。545a6470fb5e4331dda5603d5a24957a.webp,我們從源碼上可以看到,當(dāng)創(chuàng)建了?Compiler?對象過后,Webpack?就開始注冊我們配置中的每一個插件,這樣webpack在往后的生命周期里,都可以觸發(fā)對應(yīng)的plugin?插件鉤子。

        loader用于處理不同的文件類型,在編譯靜態(tài)資源個環(huán)節(jié)。我們繼續(xù)查閱源碼,創(chuàng)建完Compilation?對象過后,觸發(fā)了一個叫作?make?的鉤子,make的工作就是根據(jù)entry配置找到入口模塊,開始依次遞歸出所有依賴,形成依賴關(guān)系樹,buildModule?方法進(jìn)行模塊構(gòu)建,這里執(zhí)行具體的?Loader,處理特殊資源加載。

        dcd94485e1dda9ddc64f9fda06589021.webpimage.png

        2.2 webpack中 loader 的鏈?zhǔn)秸{(diào)用與執(zhí)行順序是怎么樣的?

        在webpack官網(wǎng)上有一句話:

        “ loader 總是從右到左被調(diào)用。有些情況下,loader 只關(guān)心 request 后面的?元數(shù)據(jù)(metadata),并且忽略前一個 loader 的結(jié)果。在實際(從右到左)執(zhí)行 loader 之前,會先?從左到右?調(diào)用 loader 上的?pitch?方法”
        對于以下?use?配置:

            module.exports?=?{
        ??//...
        ??module:?{
        ????rules:?[
        ??????{
        ????????//...
        ????????use:?['a-loader',?'b-loader',?'c-loader'],
        ??????},
        ????],
        ??},
        };

        將會發(fā)生這些步驟:

            |-?a-loader?`pitch`
        ??|-?b-loader?`pitch`
        ????|-?c-loader?`pitch`
        ??????|-?requested?module?is?picked?up?as?a?dependency
        ????|-?c-loader?normal?execution
        ??|-?b-loader?normal?execution
        |-?a-loader?normal?execution

        module.rulesloader的加載和傳遞流程是怎么樣的呢?這里我們可以查閱源碼lib/rules/RuleSetCompiler.js

        這里列舉了一兩個通過源碼查閱,來理解技術(shù)的方式,如果你有更多的疑問也可以一一通過源碼去查閱理解。

        三、簡談項目中webpack優(yōu)化

        webpack優(yōu)化,一提到這個問題,大家用心玩過webpack的人都能道個一二三,但是怎么樣系統(tǒng)的思考優(yōu)化,或許很少人會去總結(jié)。

        3.1 怎么去量化優(yōu)化指標(biāo)?

        一切以結(jié)果為導(dǎo)向,優(yōu)化到底優(yōu)化了什么,怎么樣量化(可視化、數(shù)據(jù)化),這個作為職場人重要的職業(yè)技能,優(yōu)化,通常來說我們可以從時間空間兩個維度去考量:

        (1)時間:比如編譯和打包過程中的耗時情況,你從3分鐘提速到1分鐘,這是一個很好的時間參數(shù)優(yōu)化,所以我們可以選擇一些基于時間的分析工具或插件,來幫我們統(tǒng)耗時情況,當(dāng)然你也可以自己卷一個工具,NPM上成熟的工具已經(jīng)有很多例如:?speed-measure-webpack-plugin

        (2) 空間:這里通常指的就是輸出的代碼體積,你從10M壓縮到1M,這是一個很巨大體積優(yōu)化,我們可以通過產(chǎn)物內(nèi)容分析工具webpack-bundle-analyzer

        8709a1cbc034404da5a3f9412e818351.webpimage.png

        可以直觀分析打包出的文件包含哪些,大小占比如何,壓縮后的大小。找到那些冗余的、可以被優(yōu)化的依賴項。

        3.2 定位優(yōu)化方向

        一、編譯提效

        我們可以從開發(fā)場景,體驗了Vite的絲滑后,webpack開發(fā)編譯等待是個難受的,多的時候得3-5分鐘,才能看到編譯成功,要提升這一階段的構(gòu)建效率,大致可以分為三個方向

        1. 減少執(zhí)行編譯的模塊。
        2. 提升單個模塊構(gòu)建的速度。
        3. 并行構(gòu)建以提升總體效率。

        二、打包提效

        通常我們發(fā)布項目的時候打包也是也超級長的等待時間,我們可以回憶上面webpack的構(gòu)建流程中的環(huán)節(jié),大概可以分為兩個方向:

        1. 以提升當(dāng)前任務(wù)工作效率為目標(biāo),壓縮代碼,壓縮JS、css、圖片等靜態(tài)資源
        2. 以提升后續(xù)環(huán)節(jié)工作效率為目標(biāo),比如分模塊打包(Split Chunks),搖樹(Tree Shaking

        以上都有很成熟的插件和文章去執(zhí)行webpack的優(yōu)化了,這里就不再細(xì)做班門弄斧了。

        總結(jié)

        本文主要是簡單從幾個小角度探索源碼出發(fā)理解webpack核心特性,和簡談項目中webpack優(yōu)化,如果你對webpack一些特性有想了解的,也可以通過帶著問題和目標(biāo),去“順藤摸瓜”式的去粗讀源碼,了解更多相關(guān)知識點,百尺竿頭更進(jìn)一步!

        瀏覽 53
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲中文字幕无码爆乳av| 香蕉视频国产| 松岛枫在线视频| 中国丰满妇BBwBBwHD| 456成人| 日韩欧美123| 中文字幕有码在线观看| 蜜桃传媒AV| 午夜成人在线视频| 91玖玖|