盤點(diǎn)一些面試經(jīng)常被問的webpack知識點(diǎn)
點(diǎn)擊下方“前端開發(fā)愛好者”,選擇“設(shè)為星標(biāo)”
第一時(shí)間關(guān)注技術(shù)干貨!
前言
哈嘍,大家好 我是
xy???????。雖然Vite越來越火,但是作為前端構(gòu)建工具的霸主webpack依然成為面試必考熱點(diǎn),于是周末匯總整理了webpack的常見面試題分享給大家,?。?!
對 webpack 的理解?
webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的「靜態(tài)模塊打包工具」。我們可以使用webpack管理模塊。因?yàn)樵?code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">webpack看來,項(xiàng)目中的所有資源皆為模塊,通過分析模塊間的依賴關(guān)系,在其內(nèi)部構(gòu)建出一個(gè)依賴圖,最終編繹輸出模塊為 HTML、JavaScript、CSS 以及各種靜態(tài)文件(圖片、字體等),讓我們的開發(fā)過程更加高效。
webpack的主要作用如下:
-
模塊打包。可以將不同模塊的文件打包整合在一起,并且保證它們之間的引用正確,執(zhí)行有序。利用打包我們就可以在開發(fā)的時(shí)候根據(jù)我們自己的業(yè)務(wù)自由劃分文件模塊,保證項(xiàng)目結(jié)構(gòu)的清晰和可讀性。 -
編譯兼容。在前端的“上古時(shí)期”,手寫一堆瀏覽器兼容代碼一直是令前端工程師頭皮發(fā)麻的事情,而在今天這個(gè)問題被大大的弱化了,通過webpack的Loader機(jī)制,不僅僅可以幫助我們對代碼做polyfill,還可以編譯轉(zhuǎn)換諸如.less,.vue,.jsx這類在瀏覽器無法識別的格式文件,讓我們在開發(fā)的時(shí)候可以使用新特性和新語法做開發(fā),提高開發(fā)效率。 -
能力擴(kuò)展。通過webpack的Plugin機(jī)制,我們在實(shí)現(xiàn)模塊化打包和編譯兼容的基礎(chǔ)上,可以進(jìn)一步實(shí)現(xiàn)諸如按需加載,代碼壓縮等一系列功能,幫助我們進(jìn)一步提高自動(dòng)化程度,工程效率以及打包輸出的質(zhì)量。
webpack 的構(gòu)建流程?
webpack的運(yùn)行流程是一個(gè)串行的過程,從啟動(dòng)到結(jié)束會(huì)依次執(zhí)行以下流程:
-
初始化參數(shù):從配置文件和 Shell 語句中讀取與合并參數(shù),得出最終的參數(shù) -
開始編譯:用上一步得到的參數(shù)初始化 Compiler 對象,加載所有配置的插件,執(zhí)行對象的 run 方法開始執(zhí)行編譯 -
確定入口:根據(jù)配置中的 entry 找出所有的入口文件 -
編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 loader 對模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理 -
完成模塊編譯:在經(jīng)過上一步使用 loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系 -
輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個(gè)個(gè)包含多個(gè)模塊的 Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成一個(gè)單獨(dú)的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì) -
輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)
在以上過程中,webpack會(huì)在特定的時(shí)間點(diǎn)廣播出特定的事件,插件在監(jiān)聽到感興趣的事件后會(huì)執(zhí)行特定的邏輯,并且插件可以調(diào)用webpack提供的 API 改變webpack的運(yùn)行結(jié)果。
「簡單說:」
-
初始化:啟動(dòng)構(gòu)建,讀取與合并配置參數(shù),加載 Plugin,實(shí)例化 Compiler -
編譯:從 entry 出發(fā),針對每個(gè) Module 串行調(diào)用對應(yīng)的 loader 去翻譯文件的內(nèi)容,再找到該 Module 依賴的 Module,遞歸地進(jìn)行編譯處理 -
輸出:將編譯后的 Module 組合成 Chunk,將 Chunk 轉(zhuǎn)換成文件,輸出到文件系統(tǒng)中
常見的 loader 有哪些?
默認(rèn)情況下,webpack只支持對js和json文件進(jìn)行打包,但是像css、html、png等其他類型的文件,webpack則無能為力。因此,就需要配置相應(yīng)的loader進(jìn)行文件內(nèi)容的解析轉(zhuǎn)換。
常用的loader如下:
-
image-loader:加載并且壓縮圖片文件。 -
less-loader:加載并編譯 LESS 文件。 -
sass-loader:加載并編譯 SASS/SCSS 文件。 -
css-loader:加載 CSS,支持模塊化、壓縮、文件導(dǎo)入等特性,使用css-loader必須要配合使用style-loader。 -
style-loader:用于將 CSS 編譯完成的樣式,掛載到頁面的 style 標(biāo)簽上。需要注意loader執(zhí)行順序,style-loader要放在第一位,loader都是從后往前執(zhí)行。 -
babel-loader:把 ES6 轉(zhuǎn)換成 ES5 -
postcss-loader:擴(kuò)展 CSS 語法,使用下一代 CSS,可以配合autoprefixer插件自動(dòng)補(bǔ)齊 CSS3 前綴。 -
eslint-loader:通過 ESLint 檢查 JavaScript 代碼。 -
vue-loader:加載并編譯 Vue 組件。 -
file-loader:把文件輸出到一個(gè)文件夾中,在代碼中通過相對 URL 去引用輸出的文件 (處理圖片和字體) -
url-loader:與file-loader類似,區(qū)別是用戶可以設(shè)置一個(gè)閾值,大于閾值會(huì)交給file-loader處理,小于閾值時(shí)返回文件 base64 形式編碼 (處理圖片和字體)
更多 loader,點(diǎn)擊此處查看官方文檔[1]
常見的 plugin 有哪些?
webpack中的plugin賦予其各種靈活的功能,例如打包優(yōu)化、資源管理、環(huán)境變量注入等,它們會(huì)運(yùn)行在webpack的不同階段(鉤子 / 生命周期),貫穿了webpack整個(gè)編譯周期。目的在于「解決 loader 無法實(shí)現(xiàn)的其他事」。
常用的plugin如下:
-
HtmlWebpackPlugin:簡化 HTML 文件創(chuàng)建 (依賴于 html-loader) -
mini-css-extract-plugin: 分離樣式文件,CSS 提取為獨(dú)立文件,支持按需加載 (替代 extract-text-webpack-plugin) -
clean-webpack-plugin: 目錄清理
更多 plugin,點(diǎn)擊此處查看官方文檔[2]
loader 和 plugin 的區(qū)別?
loader是文件加載器,能夠加載資源文件,并對這些文件進(jìn)行一些處理,諸如編譯、壓縮等,最終一起打包到指定的文件中;plugin賦予了webpack各種靈活的功能,例如打包優(yōu)化、資源管理、環(huán)境變量注入等,目的是解決 loader無法實(shí)現(xiàn)的其他事。
在運(yùn)行時(shí)機(jī)上,loader 運(yùn)行在打包文件之前;plugin則是在整個(gè)編譯周期都起作用。
在配置上,loader在module.rules中配置,作為模塊的解析規(guī)則,類型為數(shù)組。每一項(xiàng)都是一個(gè) Object,內(nèi)部包含了 test(類型文件)、loader、options (參數(shù))等屬性;plugin在 plugins中單獨(dú)配置,類型為數(shù)組,每一項(xiàng)是一個(gè) plugin 的實(shí)例,參數(shù)都通過構(gòu)造函數(shù)傳入。
webpack 的熱更新原理是?
模塊熱替換(HMR \- hot module replacement),又叫做熱更新,在不需要刷新整個(gè)頁面的同時(shí)更新模塊,能夠提升開發(fā)的效率和體驗(yàn)。熱更新時(shí)只會(huì)局部刷新頁面上發(fā)生了變化的模塊,同時(shí)可以保留當(dāng)前頁面的狀態(tài),比如復(fù)選框的選中狀態(tài)等。
熱更新的核心就是客戶端從服務(wù)端拉去更新后的文件,準(zhǔn)確的說是 chunk diff (chunk 需要更新的部分),實(shí)際上webpack-dev-server與瀏覽器之間維護(hù)了一個(gè)websocket,當(dāng)本地資源發(fā)生變化時(shí),webpack-dev-server會(huì)向?yàn)g覽器推送更新,并帶上構(gòu)建時(shí)的hash,讓客戶端與上一次資源進(jìn)行對比??蛻舳藢Ρ瘸霾町惡髸?huì)向webpack-dev-server發(fā)起 Ajax 請求來獲取更改內(nèi)容(文件列表、hash),這樣客戶端就可以再借助這些信息繼續(xù)向webpack-dev-server發(fā)起 jsonp 請求獲取該chunk的增量更新。
后續(xù)的部分(拿到增量更新之后如何處理?哪些狀態(tài)該保留?哪些又需要更新?)由HotModulePlugin 來完成,提供了相關(guān) API 以供開發(fā)者針對自身場景進(jìn)行處理,像react-hot-loader和vue-loader都是借助這些 API 實(shí)現(xiàn)熱更新。
如何提高 webpack 的構(gòu)建速度?
-
代碼壓縮
-
JS 壓縮 webpack 4.0默認(rèn)在生產(chǎn)環(huán)境的時(shí)候是支持代碼壓縮的,即mode=production模式下。實(shí)際上webpack 4.0默認(rèn)是使用terser-webpack-plugin這個(gè)壓縮插件,在此之前是使用uglifyjs-webpack-plugin,兩者的區(qū)別是后者對 ES6 的壓縮不是很好,同時(shí)我們可以開啟parallel參數(shù),使用多進(jìn)程壓縮,加快壓縮。 -
CSS 壓縮
CSS 壓縮通常是去除無用的空格等,因?yàn)楹茈y去修改選擇器、屬性的名稱、值等??梢允褂昧硗庖粋€(gè)插件:css-minimizer-webpack-plugin。 -
HTML 壓縮
使用HtmlWebpackPlugin插件來生成 HTML 的模板時(shí)候,通過配置屬性minify進(jìn)行 html 優(yōu)化。
module.exports = {
plugin:[
new HtmlwebpackPlugin({
minify:{
minifyCSS: false, // 是否壓縮css
collapseWhitespace: false, // 是否折疊空格
removeComments: true // 是否移除注釋
}
})
]
}
-
圖片壓縮
配置image-webpack-loader -
Tree Shaking
Tree Shaking是一個(gè)術(shù)語,在計(jì)算機(jī)中表示消除死代碼,依賴于 ES Module 的靜態(tài)語法分析(不執(zhí)行任何的代碼,可以明確知道模塊的依賴關(guān)系)。在webpack實(shí)現(xiàn)Tree shaking有兩種方案: -
usedExports:通過標(biāo)記某些函數(shù)是否被使用,之后通過 Terser來進(jìn)行優(yōu)化的
module.exports = {
...
optimization:{
usedExports
}
}
使用之后,沒被用上的代碼在webpack打包中會(huì)加入unused harmony export mul注釋,用來告知Terser在優(yōu)化時(shí),可以刪除掉這段代碼。
sideEffects:跳過整個(gè)模塊/文件,直接查看該文件是否有副作用
sideEffects用于告知webpack compiler哪些模塊時(shí)有副作用,配置方法是在package.json中設(shè)置sideEffects屬性。如果sideEffects設(shè)置為false,就是告知webpack可以安全的刪除未用到的exports。如果有些文件需要保留,可以設(shè)置為數(shù)組的形式,如:
"sideEffecis":[
"./src/util/format.js",
"*.css" // 所有的css文件
]
-
縮小打包域
排除webpack不需要解析的模塊,即在使用loader的時(shí)候,在盡量少的模塊中去使用??梢越柚?include和exclude這兩個(gè)參數(shù),規(guī)定loader只在那些模塊應(yīng)用和在哪些模塊不應(yīng)用。 -
減少 ES6 轉(zhuǎn)為 ES5 的冗余代碼
使用bable-plugin-transform-runtime插件 -
提取公共代碼
通過配置CommonsChunkPlugin插件,將多個(gè)頁面的公共代碼抽離成單獨(dú)的文件
