對于webpack面試題的總結(jié)

前言


最近在網(wǎng)上看到的一些優(yōu)秀的webpack的面試總結(jié):
「吐血整理」再來一打Webpack面試題
淺談 webpack 性能優(yōu)化(內(nèi)附 webpack 學習筆記)
揭秘webpack plugin
webpack 的 loader 和 plugin 你真的弄懂了嗎
Webpack HMR 原理解析
根據(jù)以上文檔惫东,自己總結(jié)一份簡陋版的webpack筆記

webpack構(gòu)建流程


  1. 初始化參數(shù):從配置文件webpack.config.js和shell語句中讀取與合并,得到最終參數(shù)options赐俗。
  2. 開始編譯:用步驟1得到的參數(shù)options初始化Compiler對象朝抖,加載并配置所有插件歪赢,執(zhí)行對象的run方法。
  3. 確定入口:根據(jù)配置的entry找出所有入口文件。
  4. 編譯模塊:從入口文件出發(fā)雀哨,調(diào)用所有配置的loader對模塊進行翻譯,再找出該模塊依賴的模塊私爷,遞歸以上步驟描述雾棺,直到所有入口依賴的文件經(jīng)過了處理。
  5. 完成模塊編譯:在經(jīng)過步驟4使用Loader對所有模塊都進行翻譯過后衬浑,得到每個模塊被翻譯后的最終內(nèi)容以及其相互之間的依賴關(guān)系捌浩。
  6. 輸出資源:根據(jù)入口及模塊之間的依賴關(guān)系組裝成一個個包含多模塊的chunk,再把每個chunk轉(zhuǎn)換成一個單獨的文件加入到輸出列表工秩,此步驟為可修改輸出內(nèi)容的最后機會尸饺。
  7. 輸出完成:在確定好輸出內(nèi)容后进统,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)侵佃。

在以上過程中麻昼,Webpack 會在特定的時間點廣播出特定的事件,插件在監(jiān)聽到感興趣的事件后會執(zhí)行特定的邏輯馋辈,并且插件可以調(diào)用 Webpack 提供的 API 改變 Webpack 的運行結(jié)果抚芦。

Loader和Plugin的區(qū)別及實現(xiàn)


提到 webpack,自然離不開 loader 與 blugin迈螟。Webpack 就像一條生產(chǎn)線叉抡,要經(jīng)過一系列處理流程后才能將源文件轉(zhuǎn)換成輸出結(jié)果(loader)。這條生產(chǎn)線上的每個處理流程的職責都是單一的答毫,多個流程之間有存在依賴關(guān)系褥民,只有完成當前處理后才能交給下一個流程去處理。而插件(plugin)就像是一個插入到生產(chǎn)線中的一個功能洗搂,在特定的時機對生產(chǎn)線上的資源做處理消返。

  • Loader:用于對模塊源碼的轉(zhuǎn)換,loader描述了webpack如何處理非javascript模塊耘拇,并且在build中引入這些依賴撵颊。loader可以將文件從不同的語言(如TypeScript)轉(zhuǎn)換為JavaScript。
  • Plugin:目的在于解決loader無法實現(xiàn)的其他事惫叛,從打包優(yōu)化和壓縮倡勇,到重新定義環(huán)境變量,功能強大到可以用來處理各種各樣的任務(wù)嘉涌。

簡而言之妻熊,loader可以理解成webpack的橫向廣度,有了loader仑最,webpack才可以打包處理各種的擴展語言扔役。而plugin可以理解為webpack的縱向深度,在生命周期內(nèi)注入不同的插件來擴展更多的能力词身。

Loader

Loader 就像是一個翻譯官厅目,每個 loader 可以把源資源轉(zhuǎn)換成新的結(jié)果輸出并傳遞給下一個 loader ,但是最后一個 Loader 必須返回 JavaScript (瀏覽器只能運行js代碼法严,不支持其他擴展語言)损敷。

以處理less文件為例:

module:{ 
    rules: [  
        {    
            test: /\.less$/,    
            use: ['style-loader', 'css-loader', 'less-loader']  
        } 
    ]
}
  • less-loader: 將 less 源代碼轉(zhuǎn)化為 css
  • css-loader:處理 less-loader 輸出的 css,找出 css 中依賴的資源(@import 等)深啤,壓縮資源
  • sytle-loader:處理 css-loader 輸出的 css拗馒,把 css 轉(zhuǎn)換成腳本加載的 js 代碼插入到 DOM 中

項目中常用的loader

  • file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件 (處理圖片和字體)
  • url-loader:與 file-loader 類似溯街,區(qū)別是用戶可以設(shè)置一個閾值诱桂,大于閾值會交給 file-loader 處理洋丐,小于閾值時返回文件 base64 形式編碼 (處理圖片和字體)
  • image-loader:加載并且壓縮圖片文件
  • svg-inline-loader:將壓縮后的 SVG 內(nèi)容注入代碼中
  • babel-loader:把 ES6 轉(zhuǎn)換成 ES5
  • ts-loader: 將 TypeScript 轉(zhuǎn)換成 JavaScript
  • awesome-typescript-loader:將 TypeScript 轉(zhuǎn)換成 JavaScript,性能優(yōu)于 ts-loader
  • sass-loader:將SCSS/SASS代碼轉(zhuǎn)換成CSS
  • less-loader: 將 less 源代碼轉(zhuǎn)化為 css
  • css-loader:加載處理CSS挥等,支持模塊化友绝、壓縮、文件導(dǎo)入等特性
  • style-loader:處理 css-loader 輸出的 css肝劲,把 css 轉(zhuǎn)換成腳本加載的 js 代碼插入到 DOM 中
  • eslint-loader:通過 ESLint 檢查 JavaScript 代碼
  • tslint-loader:通過 TSLint檢查 TypeScript 代碼
  • cache-loader: 可以在一些性能開銷較大的 Loader 之前添加迁客,目的是將結(jié)果緩存到磁盤里

那么,實現(xiàn)一個loader
要求:把項目 txt 文件中的蔣梨花全部替換為梨花醬
1) 在config.js中配置項目中 .txt 結(jié)尾的文件使用我們的 demo-loader

// webpack.config.js
module:{  
    rules: [    
        {        
            test: /\.txt$/,        
            use: ['demo-loader'],        
            options: {            
                name: '梨花醬' // 將要變更的通過配置項傳入        
            }      
        }  
    ]
}

2)創(chuàng)建一個包含蔣梨花的txt文件辞槐,并引用(webpack不會處理未引用的文件)

// test.txt
你好掷漱,我是蔣梨花

// app.js (入口文件引用)
const text = require(./text.txt)
console.log(test)

3)編寫 loader

// demo-loader.js
const loaderUtils = require('loader-utils') 
// 接收options配置
module.exports = function(source) {    
    const options = loaderUtils.getOptions(this)    
    source = source.replace(/蔣梨花/g, options.name)    
    return `module.exports = ${JSON.stringify(sorce)}`    
    // 最終需要返回一段可執(zhí)行的js腳本
}


Plugin

plugin是運行在webpak打包過程中的某段邏輯,它主要的作用是根據(jù)webpack提供的一些hooks來進行一些額外的操作榄檬,使 webpack 更加靈活擴展卜范。

plugins: [    
    new HtmlWebpackPlugin()  
]

我們通過 new 來使用這個插件,可以看出插件的本質(zhì)是一個構(gòu)造函數(shù)鹿榜。
首先了解兩個概念:Compiler 和Compilation

compiler 對象代表了完整的 webpack 環(huán)境配置海雪。這個對象在啟動 webpack 時被一次性建立,并配置好所有可操作的設(shè)置舱殿,包括 options喳魏,loader 和 plugin。當在 webpack 環(huán)境中應(yīng)用一個插件時怀薛,插件將收到此 compiler 對象的引用∶灾#可以使用它來訪問 webpack 的主環(huán)境枝恋。

compilation 對象代表了一次資源版本構(gòu)建。當運行 webpack 開發(fā)環(huán)境中間件時嗡害,每當檢測到一個文件變化焚碌,就會創(chuàng)建一個新的 compilation,從而生成一組新的編譯資源霸妹。一個 compilation 對象表現(xiàn)了當前的模塊資源十电、編譯生成資源、變化的文件叹螟、以及被跟蹤依賴的狀態(tài)信息鹃骂。compilation 對象也提供了很多關(guān)鍵時機的回調(diào),以供插件做自定義處理時選擇使用罢绽。

在 webpack 啟動后畏线,它會執(zhí)行 new xxxPlugin(options) 來初始化插件實例。在初始化對象后良价,會去調(diào)用 xxxPlugin.apply(compiler) 并傳入 compiler 對象寝殴。插件獲得 compiler 對象后蒿叠,可以通過
compiler.plugin('事件名', 回調(diào)函數(shù)) 的方式進行監(jiān)聽 webpack 廣播出來的事件了。

項目中常用的plugin

  • html-webpack-plugin: 在打包結(jié)束后蚣常,?動生成?個 html ?文件抓歼,并把打包生成的js 模塊引?到該 html 中
  • clean-webpack-plugin: 刪除(清理)構(gòu)建目錄
  • mini-css-extract-plugin: 提取 CSS 到一個單獨的文件中
  • terser-webpack-plugin: 支持壓縮 ES6 (Webpack4)
  • webpack-merge: 提取公共配置,減少重復(fù)配置代碼
  • HotModuleReplacementPlugin: 模塊熱更新(啟用 HMR 很容易衣屏,且在大多數(shù)情況下不需要任何配置集币。)

那么,實現(xiàn)一個plugin
1) 在配置文件中泌射,使用插件

// webpack.config.js   
plugins: [    
  new MyTestPlugin({       
    msg: '你好我是梨花醬' // 傳入的插件配置    
  })
]

2)編寫 plugin 插件

// MyTestPlugin.js
const { ConcatSource } = require("webpack-sources") // 用來寫入
class MyBannerPlugin {  
    constructor(options) { 
        // 獲取傳入的option信息    
        this.msg = options.msg  
    },  // 我們需要一個apply方法(為了獲取compiler)粘姜,接收compiler作為參數(shù)表示這次打包的上下文。  
    apply (compiler) {    
        const msg = this. msg    // 指定掛載的 webpack 鉤子函數(shù)    
        // 使用compiler鉤子compilation熔酷,即編譯(compilation)創(chuàng)建之后孤紧,執(zhí)行插件。    
        compiler.hooks.compilation.tap("MyTestPlugin", compilation => {      
        // compilation的 optimizeChunkAssets 鉤子拒秘,可以利用這個鉤子實現(xiàn)為每個文件插入信息      
            compilation.hooks.optimizeChunkAssets.tap("MyTestPlugin", chunks => {        
                for (const chunk of chunks) {          
                    for (const file of chunk.files) {            
                        compilation.updateAsset(file, old => {                       
                            return new ConcatSource(msg,"\n", old);            
                        });          
                    }        
                }      
            })    
        })  
    }
}
module.exports = MyTestPlugin

可以看出号显,要實現(xiàn)一個plugin需要以下幾步:

  • 首先需要聲明一個 class 構(gòu)造函數(shù)
  • 在class里面定義一個apply方法,接收compiler作為參數(shù)表示這次打包的上下文躺酒。
  • 指定掛載的webpack事件鉤子
  • 處理webpack內(nèi)部實例的特定數(shù)據(jù)
  • 功能完成后調(diào)用webpack提供的回調(diào)

具體的 compiler 鉤子 和 compilation 鉤子可以參考官方文檔:https://www.webpackjs.com/api/compilation-hooks/#optimizechunkassets


利用webpack進行優(yōu)化


  • JS壓縮webpack4.0 默認是使用 terser-webpack-plugin 這個壓縮插件押蚤,在此之前是使用 uglifyjs-webpack-plugin,兩者的區(qū)別是后者對 ES6 的壓縮不是很好羹应,同時我們可以開啟 parallel 參數(shù)揽碘,使用多進程壓縮,加快壓縮园匹。
  • CSS 壓縮:我們可以借助 optimize-css-assets-webpack-plugin 插件來壓縮 css雳刺,其默認使用的壓縮引擎是 cssnano
  • 擦除無用的 CSSoptimize-css-assets-webpack-plugin + mini-css-extract-plugin
  • 圖片壓縮: 我們就可以借助 image-webpack-loader 幫助我們來實現(xiàn)。(只要在 file-loader 之后加入 image-webpack-loader)
  • 減少圖片的HTTP請求:借助url-loader
  • webpack-merge來整合兩個配置文件共同的配置 webpack.common.js
  • 利用多線程提升構(gòu)建速度thread-loader
  • 預(yù)先編譯資源模塊DllPlugin
  • 緩存 Cache 相關(guān): babel-loader 開啟緩存裸违、terser-webpack-plugin 開啟緩存掖桦、使用 cache-loader 或者 hard-source-webpack-plugin

詳細內(nèi)容可參考:https://zhuanlan.zhihu.com/p/139498741

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市供汛,隨后出現(xiàn)的幾起案子枪汪,更是在濱河造成了極大的恐慌,老刑警劉巖怔昨,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雀久,死亡現(xiàn)場離奇詭異,居然都是意外死亡朱监,警方通過查閱死者的電腦和手機岸啡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赫编,“玉大人巡蘸,你說我怎么就攤上這事奋隶。” “怎么了悦荒?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵唯欣,是天一觀的道長。 經(jīng)常有香客問我搬味,道長境氢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任碰纬,我火速辦了婚禮萍聊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘悦析。我一直安慰自己寿桨,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布强戴。 她就那樣靜靜地躺著亭螟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骑歹。 梳的紋絲不亂的頭發(fā)上预烙,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音道媚,去河邊找鬼扁掸。 笑死,一個胖子當著我的面吹牛最域,可吹牛的內(nèi)容都是我干的也糊。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼羡宙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掐隐?” 一聲冷哼從身側(cè)響起狗热,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虑省,沒想到半個月后匿刮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡探颈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年熟丸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伪节。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡光羞,死狀恐怖绩鸣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纱兑,我是刑警寧澤呀闻,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站潜慎,受9級特大地震影響捡多,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铐炫,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一垒手、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧倒信,春花似錦科贬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竞穷,卻和暖如春唐责,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘾带。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工鼠哥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人看政。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓朴恳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親允蚣。 傳聞我的和親對象是個殘疾皇子于颖,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容