<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從源碼出發(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)紅,但是在目前來說,很多公司老項(xiàng)目都還是用webpack體系進(jìn)行打包,面試的時候,往往也是會提一嘴,你做過什么優(yōu)化,webpack的一些原理和知識點(diǎn)好像還是必備, 早在兩年前我就寫過一篇文章《前端開發(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部分單獨(dú)抽離在?webpack-cli?模塊中,接下來我們就帶著源碼一點(diǎn)點(diǎn)來探索,webpack的核心工作流程。
          注:本文下載的

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

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

          1.2 啟動webpack都做了什么

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

          接下來我們關(guān)注點(diǎ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對于文件打包不是必需的,因?yàn)樗皇翘幚砻钚袇?shù),我們也可以自行設(shè)計(jì)cli來處理參數(shù),比如我們常見的 Vue/React框架也是沒有使用webpack-cli

          啟動流程總結(jié)

          84176eff853d99a9ffc6cbbaac36357b.webpwebpack啟動流程.png

          內(nèi)部的運(yùn)行機(jī)制

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

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

          一、初始化參數(shù)

          (1)從配置文件解析配置項(xiàng),開始載入?Webpack?核心模塊,傳入配置選項(xiàng),這部分工作由?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對象上(通過單例模式保證同樣的模塊只有一個實(shí)例)
          (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)換成一個單獨(dú)的文件加入到輸出列表

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

          其實(shí)這個是一個偽命題,,單從字面上是不能判斷執(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é)果。在實(shí)際(從右到左)執(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ù)的方式,如果你有更多的疑問也可以一一通過源碼去查閱理解。

          三、簡談項(xiàng)目中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)化的依賴項(xiàng)。

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

          一、編譯提效

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

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

          二、打包提效

          通常我們發(fā)布項(xiàng)目的時候打包也是也超級長的等待時間,我們可以回憶上面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核心特性,和簡談項(xiàng)目中webpack優(yōu)化,如果你對webpack一些特性有想了解的,也可以通過帶著問題和目標(biāo),去“順藤摸瓜”式的去粗讀源碼,了解更多相關(guān)知識點(diǎn),百尺竿頭更進(jìn)一步!

          瀏覽 53
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中国美女一级片 | 欧美日韩电影一区 | 香蕉国产精品视频 | 黄色成人在线网站 | 怕怕怕免费视频 |