「offer来了」从基础配置到高级配置,16大知识点带你巩固webpack知识体系
「面試專欄」前端面試之Webpack篇
- 🧩序言
- 🎨一、基礎(chǔ)知識學(xué)習(xí)
- 🎲二、常見面試題匯總
- 🎯三、構(gòu)建和打包
- 1、前端代碼如何進行構(gòu)建和打包?
- 2、前端為何要進行打包和構(gòu)建?
- 3、webpack原理
- 🎰四、模塊相關(guān)
- 1、module chunk bundle 分別是什么意思,有何區(qū)別?
- 2、source map是什么?開發(fā)環(huán)境和生產(chǎn)環(huán)境如何使用?
- 3、如何引用一個自己編寫的庫lib(第三方模塊)
- 🧶五、loader和plugin
- 1、webpack中常見的loader有哪些
- 2、webpaack中常見的plugin有哪些
- 3、loader和plugin的區(qū)別?
- 4、是否寫過Loader?簡單描述一下編寫loader的思路?
- 5、是否寫過Plugin?簡單描述一下編寫plugin的思路?
- 🥁六、babel相關(guān)
- 1、babel和webpack的區(qū)別
- 2、babel-polyfill和babel-runtime的區(qū)別
- 3、為何Proxy不能被Polyfill?
- 🥊七、性能優(yōu)化相關(guān)
- 1、webpack如何實現(xiàn)懶加載?
- 2、webpack常見性能優(yōu)化(如何優(yōu)化webpack的構(gòu)建速度?)
- (1)從開發(fā)環(huán)境的角度
- (2)從產(chǎn)出代碼的角度
- 🎬八、結(jié)束語
- 🐣彩蛋 One More Thing
- (:參考資料
- (:pdf獲取
- (:更新地址
- (:番外篇
🧩序言
在前端的面試中, webpack 也是面試官考察的重點之一。如果說候選人不會 webpack ,從某種層面上來說不會特別影響面試官最終的面試結(jié)果。但從某種意義上來說,候選人給面試官的印象分就會稍微折扣了一點點。所以呢,以不變應(yīng)萬變,還是抓緊時間復(fù)盤學(xué)習(xí),應(yīng)變面試官有可能涉及到的各種問題。
那么在接下來的這篇文章當(dāng)中呢,將梳理 webpack 的基礎(chǔ)知識,以及將對常見面試題進行匯總和解答。一起來學(xué)習(xí)吧~😝
🎨一、基礎(chǔ)知識學(xué)習(xí)
我們先用一張思維導(dǎo)圖來對 webpack 的一些基礎(chǔ)知識進行總結(jié)歸納。詳情見下圖👇
對于以上內(nèi)容,周一有整理過 5 篇文章。戳webpack基礎(chǔ)知識傳送門
大家可以到專欄進行學(xué)習(xí)查看,同時,如果想對 webpack 有一個系統(tǒng)一點的學(xué)習(xí)的話,推薦給大家可以直接看 《Webpack實戰(zhàn):入門、進階與調(diào)優(yōu)》這本書。
這本書相對來說對入門選手會友好一點,也是周一剛學(xué)習(xí)時看的一本書。其他書我也還沒看過……等以后再來補充。
基礎(chǔ)知識學(xué)會了,那么我們繼續(xù)來看下比較常見的一些面試題匯總和解答~
🎲二、常見面試題匯總
同樣地,我們先用一張思維導(dǎo)圖來了解 webpack 中常見的一些面試題。詳情見下圖👇
現(xiàn)在我們來對這些問題進行一一解答。
🎯三、構(gòu)建和打包
1、前端代碼如何進行構(gòu)建和打包?
Webpack 的運行流程是一個串行的過程,從啟動到結(jié)束會依次執(zhí)行以下流程:
- 初始化參數(shù): 從配置文件和 Shell 語句中q去讀取與合并參數(shù),得出最終的參數(shù);
- 開始編譯: 用上一步得到的參數(shù)初始化 Compiler 對象,加載所有配置的插件,執(zhí)行對象的 run 方法開始執(zhí)行編譯;
- 確定入口: 根據(jù)配置中的 entry 找出所有的入口文件;
- 編譯模塊: 從入口文件出發(fā),調(diào)用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理;
- 完成模塊編譯: 在經(jīng)過第 4 步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系;
- 輸出資源: 根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個個包含多個模塊的 Chunk ,再把每個 Chunk 轉(zhuǎn)換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機會;
- 輸出完成: 在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng);
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監(jiān)聽到感興趣的事件后會執(zhí)行特定的邏輯,并且插件可以調(diào)用 Webpack 提供的 API 來改變 Webpack 的運行結(jié)果。
簡單來說:
- 初始化參數(shù): 啟動構(gòu)建,讀取與合并配置參數(shù),加載 Plugin ,實例化 Compiler ;
- 編譯模塊: 從 Entry 出發(fā),針對每個 Module 串行調(diào)用對應(yīng)的 Loader 去翻譯文件的內(nèi)容,再找到該 Module 依賴的 Module ,遞歸地進行編譯處理;
- 完成輸出: 將編譯后的 Module 組合成 Chunk,將 Chunk 轉(zhuǎn)換成文件,輸出到文件系統(tǒng)中。
2、前端為何要進行打包和構(gòu)建?
從代碼層面來說:
- 進行構(gòu)建和打包后的項目體體積更小( Tree-Shaking 、壓縮代碼、合并代碼,加載更快);
- 可以對高級語言或語法進行編譯(TS, ES6+ ,模塊化、 scss );
- 對代碼的兼容性和錯誤進行檢查( polyfill 、 postcss 、 eslint )。
從研發(fā)層面來說:
- 使得研發(fā)有著更統(tǒng)一、高效的開發(fā)環(huán)境;
- 讓項目組有著統(tǒng)一的構(gòu)建流程和產(chǎn)出標(biāo)準(zhǔn);
- 在提測和上線等流程中慢慢集成公司的構(gòu)建規(guī)范。
3、webpack原理
- 首先需要先解析入口文件 entry ,使用@babel/parser ,將其轉(zhuǎn)為 AST(抽象語法樹) ;
- 使用 @babel/traverse 插件,去找出入口文件中的所有 依賴模塊 ;
- 然后使用 @babel/core+ 和 @babel/preset-env 插件,將入口文件的 AST 轉(zhuǎn)為 Code ;
- 將 2 中找到的入口文件的依賴模塊,進行 遍歷遞歸 ,重復(fù)執(zhí)行 1,2,3 ;
- 重寫 require 函數(shù),并與 4 中生成的 遞歸關(guān)系圖 一起,輸出到 bundle 中。
🎰四、模塊相關(guān)
1、module chunk bundle 分別是什么意思,有何區(qū)別?
- module - 代表各個源碼文件, webpack 中一切皆模塊;
- chunk - 表示多模塊合并成的,如 entry 、 import() 、 splitChunk ;
- bundle - 表示最終的輸出文件。
2、source map是什么?開發(fā)環(huán)境和生產(chǎn)環(huán)境如何使用?
source map 是將編譯、打包、壓縮后的代碼映射回源代碼的過程。打包壓縮后的代碼不具備良好的可讀性,想要調(diào)試源碼就需要 soucre map 。map 文件只要不打開開發(fā)者工具,瀏覽器是不會加載的。下面給出在開發(fā)環(huán)境和生產(chǎn)環(huán)境下最適用的方式。
開發(fā)環(huán)境:cheap-module-eval-source-map
生產(chǎn)環(huán)境:cheap-module-source-map
注意點: 避免在生產(chǎn)中使用 inline- 和 eval- ,因為它們會增加 bundle 體積大小,并降低整體性能。
3、如何引用一個自己編寫的庫lib(第三方模塊)
-
在 output 中配置 filename 、 library 以及 libraryTarget 等項,來引用自己編寫的第三方庫;
-
解決庫引用沖突:externals 。
🧶五、loader和plugin
1、webpack中常見的loader有哪些
- file-loader:常用于處理圖片和字體,旨在把文件輸出到一個文件夾中,之后在代碼中通過相對的 url 去引用輸出的文件。
- url-loader:常用于處理圖片和字體,與 file-loader 類似,兩個的區(qū)別在于,對于 url-loader 來說,用戶可以設(shè)置一個閾值,當(dāng)大于閾值時會交給 file-loader 處理,小于閾值時返回文件 base64 形式編碼。
- css-loader:用于加載 CSS 文件,支持模塊化、壓縮、文件導(dǎo)入等特性。
- style-loader:用于把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS 。
- sass-loader:用于將 SCSS/SASS 代碼轉(zhuǎn)換成 CSS 代碼。
- postcss-loader:解決兼容性問題,擴展 CSS 語法,使用下一代 CSS ,可以配合 autoprefixer 插件自動補齊 CSS3 的廠商前綴。
2、webpaack中常見的plugin有哪些
-
html-webpack-plugin:自動創(chuàng)建一個新的 html 文件,并把打包生成的 js 文件自動引入到這個 html 文件中。
-
clean-webpack-plugin:清空指定目錄或者文件夾。
-
ignore-plugin:忽略部分文件。
-
splitChunkPlugin:對 js 文件進行代碼分割。
-
mini-css-extract-plugin:對 css 文件進行代碼分割,對于分割后的代碼來說,支持按需加載。
-
optimize-css-assets-webpack-plugin:用于壓縮 css 文件,減少 css 文件的大小。
3、loader和plugin的區(qū)別?
- loader ,可以說是一個模塊轉(zhuǎn)換器,用于處理我們引用的模塊。比如說,我們想要去引入一個 js 文件,或者是 css 格式的文件,都需要 loader 來幫助我們處理。
- plugin ,可以說是一個擴展插件,它用于在打包過程中的某些時刻里生效。常見的有 htmlWebpackPlugin 、 cleanWebpackPlugin 等等。
4、是否寫過Loader?簡單描述一下編寫loader的思路?
-
其本質(zhì)為函數(shù),函數(shù)中的 this 將會被作為上下文來提供給 webpack 填充,因此我們不能將 loader 設(shè)為一個箭頭函數(shù);
-
函數(shù)接受一個參數(shù),這個參數(shù)為 webpack 傳遞給 loader 的文件源內(nèi)容;
-
函數(shù)中 this 是由 webpack 提供的對象,能夠獲取當(dāng)前 loader 所需要的各種信息;
-
函數(shù)中有異步操作或同步操作,異步操作通過 this.callback 返回,返回值要求為 string 或者 Buffer 。
代碼如下所示:
// 導(dǎo)出一個函數(shù),source為webpack傳遞給loader的文件源內(nèi)容 module.exports = function(source) {const content = doSomeThing2JsString(source);// 如果 loader 配置了 options 對象,那么this.query將指向 optionsconst options = this.query;// 可以用作解析其他模塊路徑的上下文console.log('this.context');/** this.callback 參數(shù):* error:Error | null,當(dāng) loader 出錯時向外拋出一個 error* content:String | Buffer,經(jīng)過 loader 編譯后需要導(dǎo)出的內(nèi)容* sourceMap:為方便調(diào)試生成的編譯后內(nèi)容的 source map* ast:本次編譯生成的 AST 靜態(tài)語法樹,之后執(zhí)行的 loader 可以直接使用這個 AST,進而省去重復(fù)生成 AST 的過程*/this.callback(null, content); // 異步return content; // 同步 }5、是否寫過Plugin?簡單描述一下編寫plugin的思路?
(1) 由于webpack基于發(fā)布訂閱模式,在運行的生命周期中會廣播出許多事件,插件通過監(jiān)聽這些事件,就可以在特定的階段來執(zhí)行自己的插件任務(wù)。
(2) webpack 編譯會創(chuàng)建兩個核心對象:
-
compiler:包含了 webpack 環(huán)境種的所有配置信息,包括 options,loader 和 plugin,和 webpack 整個生命周期相關(guān)的鉤子。
-
compilation:作為 plugin 內(nèi)置事件回調(diào)函數(shù)的參數(shù),包含了當(dāng)前的模塊資源、編譯生成資源、變化的文件以及被跟蹤依賴的狀態(tài)信息。當(dāng)檢測到一個文件變化,一次新的 Compilation 將被創(chuàng)建。
(3) 如果自己要實現(xiàn) plugin ,也需要遵循一定的規(guī)范:
-
插件必須是一個函數(shù)或者是一個包含 apply 方法的對象,這樣才能訪問 compiler 實例。
-
傳給每個插件的 compiler 和 compilation 對象都是同一個引用,因此不建議修改。
-
異步的事件需要在插件處理完任務(wù)時去調(diào)用回調(diào)函數(shù),之后通知 Webpack 進入下一個流程,否則會卡住。
(4) 實現(xiàn)plugin的模板如下:
class MyPlugin {// Webpack 會調(diào)用 MyPlugin 實例的 apply 方法給插件實例傳入 compiler 對象apply (compiler) {// 找到合適的事件鉤子,實現(xiàn)自己的插件功能compiler.hooks.emit.tap('MyPlugin', compilation => {// compilation: 當(dāng)前打包構(gòu)建流程的上下文console.log(compilation);// do something...})} }🥁六、babel相關(guān)
1、babel和webpack的區(qū)別
- babel ,編譯 JS 新語法的一個工具,它不關(guān)心模塊化;
- 而 webpack ,是一個打包構(gòu)建工具,是多個 loader 和 plugin 的集合,它關(guān)心模塊化。
2、babel-polyfill和babel-runtime的區(qū)別
- babel-polyfill ,旨在解決低版本瀏覽器無法兼容 ES6 的部分新的語法變量的問題,但它有一個缺點就是會污染全局,即 @babel/preset-env 會將 Promise 翻譯成全局變量 var _Promise 。
- 而 babel-runtime 則不會污染全局, babel-runtime 提供了單獨的包,用以提供編譯模塊的工具函數(shù)。啟用插件 babel-plugin-transform-runtime 后, Babel 就會使用 babel-runtime 下的工具函數(shù)。
- 同時,值得注意的是,當(dāng)引用自己編寫的第三方庫 lib 時,要用 babel-runtime 。
3、為何Proxy不能被Polyfill?
-
Proxy 沒有辦法被 polyfill ,也就是說低版本瀏覽器無法兼容一些新的語法變量,所以這也是我們常說的為啥 vue3 無法兼容低版本瀏覽器。
-
像 class 可以用 function 模擬, Promise 可以用 callback 來模擬,但 Proxy 的功能用 Object.defineProperty 就無法模擬了,所以 vue3 暫時無法減容低版本瀏覽器。
🥊七、性能優(yōu)化相關(guān)
1、webpack如何實現(xiàn)懶加載?
-
import() 語法。
-
使用 preloading 和 prefetching 來文件進行異步加載。
-
preload 與 prefetch 的區(qū)別在于: preload 是跟主文件同時進行加載,而不是在主文件加載完才加載的。一般來說,我們都用 prefetch , 只有等主文件把活干完了,再來加載剩余的我們想要的文件,這樣的邏輯和對頁面的優(yōu)化才是比較完美的。
2、webpack常見性能優(yōu)化(如何優(yōu)化webpack的構(gòu)建速度?)
(1)從開發(fā)環(huán)境的角度
生產(chǎn)環(huán)境優(yōu)化:
- 優(yōu)化 babel-loader ;
- 使用 IgnorePlugin ,排除掉一些不使用的模塊,且用來縮小打包作用域;
- noParse;
- happyPack(不維護了);
- ParallelUglifyPlugin。
開發(fā)環(huán)境優(yōu)化:
- 自動刷新:使用 webpackDevServer 來實現(xiàn)自動刷新編譯結(jié)果。
- 熱模塊更新HMR:熱更新又稱熱替換, 這個機制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
- DllPlugin:使用 DllPlugin 進行分包,使用 DllReferencePlugin (索引鏈接) 對 manifest.json 引用,讓一些基本不會改動的代碼先打包成靜態(tài)資源,避免反復(fù)編譯浪費時間。
(2)從產(chǎn)出代碼的角度
- 懶加載;
- 提取公共代碼;
- 使用 cdn 加速;
- IgnorePlugin;
- 使用 production ;
- 使用 url-loader 對小圖片進行 base64 編碼;
- 對生成的 bundle 文件加 hash 值;
- Scope Hosting:
- 構(gòu)建后的代碼會存在大量閉包,造成體積增大,運行代碼時創(chuàng)建的函數(shù)作用域變多,內(nèi)存開銷變大。
- Scope hoisting 將所有模塊的代碼按照引用順序放在一個函數(shù)作用域里,然后適當(dāng)?shù)闹孛恍┳兞恳?strong>防止變量名沖突.
- 同時,必須是 ES6 的語法,因為有很多第三方庫仍采用 CommonJS 語法。
- 因此,為了充分發(fā)揮 Scope hoisting 的作用,需要配置 mainFields 對第三方模塊優(yōu)先采用 jsnext:main 中指向的 ES6 模塊化語法。
🎬八、結(jié)束語
在上面的文章中,我們從構(gòu)建和打包、模塊相關(guān)、 loader 和 plugin 、 babel 、性能優(yōu)化相關(guān)這五個方面,對 webpack 的一些常見面試題進行了歸納總結(jié)。相信通過上文的學(xué)習(xí),大家對這一塊的內(nèi)容又有了一定的了解。關(guān)于 webpack 的常見面試題講到這里就結(jié)束啦!希望對大家有幫助~
如文章有誤或有想要補充的內(nèi)容,歡迎留言或聯(lián)系 vx:MondayLaboratory 。
最后就是祝各位看到這篇文章的小伙伴們,都能夠斬獲到自己心儀的 offer 呀~🥂🥂🥂
🐣彩蛋 One More Thing
(:參考資料
👉再來一打Webpack面試題
👉騰訊面試官:兄弟,你說你會Webpack,那說說他的原理?
👉面試官:說說Webpack中Loader和Plugin的區(qū)別?編寫Loader,Plugin的思路?
(:pdf獲取
👉 微信搜索 星期一研究室 并關(guān)注,回復(fù)關(guān)鍵詞 webpack面試pdf 獲取相關(guān)pdf內(nèi)容~
👉回復(fù) 面試大全pdf 可獲取整專欄內(nèi)容🗂?
(:更新地址
👉 offer來了面試專欄
(:番外篇
- 關(guān)注公眾號星期一研究室,第一時間關(guān)注優(yōu)質(zhì)文章,更多精選專欄待你解鎖~
- 如果這篇文章對你有用,記得留個腳印jio再走哦~
- 以上就是本文的全部內(nèi)容!我們下期見!👋👋👋
總結(jié)
以上是生活随笔為你收集整理的「offer来了」从基础配置到高级配置,16大知识点带你巩固webpack知识体系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「offer来了」从基础到进阶原理,从v
- 下一篇: 知识图谱是什么?