(web前端) 工程化高頻面試題

1.webpack與grunt、gulp的不同?

Grunt、Gulp是基于任務(wù)運(yùn)行的工具:

它們會(huì)自動(dòng)執(zhí)行指定的任務(wù),就像流水線,把資源放上去然后通過(guò)不同插件進(jìn)行加工,它們包含活躍的社區(qū),豐富的插件,能方便的打造各種工作流。

Webpack是基于模塊化打包的工具:

自動(dòng)化處理模塊,webpack把一切當(dāng)成模塊,當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle。

因此這是完全不同的兩類工具,而現(xiàn)在主流的方式是用npm script代替Grunt、Gulp,npm script同樣可以打造任務(wù)流.

2.webpack、rollup、parcel優(yōu)劣?

  • webpack適用于大型復(fù)雜的前端站點(diǎn)構(gòu)建: webpack有強(qiáng)大的loader和插件生態(tài),?打包后的文件實(shí)際上就是一個(gè)立即執(zhí)行函數(shù),這個(gè)立即執(zhí)行函數(shù)接收一個(gè)參數(shù),這個(gè)參數(shù)是模塊對(duì)象,鍵為各個(gè)模塊的路徑,值為模塊內(nèi)容。立即執(zhí)行函數(shù)內(nèi)部則處理模塊之間的引用,執(zhí)行模塊等,這種情況更適合文件依賴復(fù)雜的應(yīng)用開(kāi)發(fā).
  • rollup適用于基礎(chǔ)庫(kù)的打包,如vue、d3等: Rollup 就是將各個(gè)模塊打包進(jìn)一個(gè)文件中,并且通過(guò) Tree-shaking 來(lái)刪除無(wú)用的代碼,可以最大程度上降低代碼體積,但是rollup沒(méi)有webpack如此多的的如代碼分割、按需加載等高級(jí)功能,其更聚焦于庫(kù)的打包,因此更適合庫(kù)的開(kāi)發(fā).
  • parcel適用于簡(jiǎn)單的實(shí)驗(yàn)性項(xiàng)目: 他可以滿足低門(mén)檻的快速看到效果,但是生態(tài)差、報(bào)錯(cuò)信息不夠全面都是他的硬傷,除了一些玩具項(xiàng)目或者實(shí)驗(yàn)項(xiàng)目不建議使用

3.有哪些常見(jiàn)的Loader?

  • file-loader:把文件輸出到一個(gè)文件夾中,在代碼中通過(guò)相對(duì) URL 去引用輸出的文件
  • url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內(nèi)容注入到代碼中去
  • source-map-loader:加載額外的 Source Map 文件,以方便斷點(diǎn)調(diào)試
  • image-loader:加載并且壓縮圖片文件
  • babel-loader:把 ES6 轉(zhuǎn)換成 ES5
  • css-loader:加載 CSS,支持模塊化、壓縮、文件導(dǎo)入等特性
  • style-loader:把 CSS 代碼注入到 JavaScript 中,通過(guò) DOM 操作去加載 CSS。
  • eslint-loader:通過(guò) ESLint 檢查 JavaScript 代碼

4.有哪些常見(jiàn)的Plugin?

  • define-plugin:定義環(huán)境變量
  • html-webpack-plugin:簡(jiǎn)化html文件創(chuàng)建
  • uglifyjs-webpack-plugin:通過(guò)UglifyES壓縮ES6代碼
  • webpack-parallel-uglify-plugin: 多核壓縮,提高壓縮速度
  • webpack-bundle-analyzer: 可視化webpack輸出文件的體積
  • mini-css-extract-plugin: CSS提取到單獨(dú)的文件中,支持按需加載

5.分別介紹bundle,chunk,module是什么

  • bundle:是由webpack打包出來(lái)的文件
  • chunk:代碼塊,一個(gè)chunk由多個(gè)模塊組合而成,用于代碼的合并和分割
  • module:是開(kāi)發(fā)中的單個(gè)模塊,在webpack的世界,一切皆模塊,一個(gè)模塊對(duì)應(yīng)一個(gè)文件,webpack會(huì)從配置的entry中遞歸開(kāi)始找出所有依賴的模塊

6.Loader和Plugin的不同?

不同的作用:

  • Loader直譯為"加載器"。Webpack將一切文件視為模塊,但是webpack原生是只能解析js文件,如果想將其他文件也打包的話,就會(huì)用到loader。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
  • Plugin直譯為"插件"。Plugin可以擴(kuò)展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運(yùn)行的生命周期中會(huì)廣播出許多事件,Plugin 可以監(jiān)聽(tīng)這些事件,在合適的時(shí)機(jī)通過(guò) Webpack 提供的 API 改變輸出結(jié)果。

不同的用法:

  • Loadermodule.rules中配置,也就是說(shuō)他作為模塊的解析規(guī)則而存在。 類型為數(shù)組,每一項(xiàng)都是一個(gè)Object,里面描述了對(duì)于什么類型的文件(test),使用什么加載(loader)和使用的參數(shù)(options
  • Pluginplugins中單獨(dú)配置。 類型為數(shù)組,每一項(xiàng)是一個(gè)plugin的實(shí)例,參數(shù)都通過(guò)構(gòu)造函數(shù)傳入。

7.webpack的構(gòu)建流程是什么?

Webpack 的運(yùn)行流程是一個(gè)串行的過(guò)程,從啟動(dòng)到結(jié)束會(huì)依次執(zhí)行以下流程:

  1. 初始化參數(shù):從配置文件和 Shell 語(yǔ)句中讀取與合并參數(shù),得出最終的參數(shù);
  2. 開(kāi)始編譯:用上一步得到的參數(shù)初始化 Compiler 對(duì)象,加載所有配置的插件,執(zhí)行對(duì)象的 run 方法開(kāi)始執(zhí)行編譯;
  3. 確定入口:根據(jù)配置中的 entry 找出所有的入口文件;
  4. 編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 Loader 對(duì)模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過(guò)了本步驟的處理;
  5. 完成模塊編譯:在經(jīng)過(guò)第4步使用 Loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系;
  6. 輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個(gè)個(gè)包含多個(gè)模塊的 Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成一個(gè)單獨(dú)的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì);
  7. 輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫(xiě)入到文件系統(tǒng)。

8.是否寫(xiě)過(guò)Loader和Plugin?描述一下編寫(xiě)loader或plugin的思路?

Loader像一個(gè)"翻譯官"把讀到的源文件內(nèi)容轉(zhuǎn)義成新的文件內(nèi)容,并且每個(gè)Loader通過(guò)鏈?zhǔn)讲僮鳎瑢⒃次募徊讲椒g成想要的樣子。

編寫(xiě)Loader時(shí)要遵循單一原則,每個(gè)Loader只做一種"轉(zhuǎn)義"工作。 每個(gè)Loader的拿到的是源文件內(nèi)容(source),可以通過(guò)返回值的方式將處理后的內(nèi)容輸出,也可以調(diào)用this.callback()方法,將內(nèi)容返回給webpack。 還可以通過(guò) this.async()生成一個(gè)callback函數(shù),再用這個(gè)callback將處理后的內(nèi)容輸出出去。 此外webpack還為開(kāi)發(fā)者準(zhǔn)備了開(kāi)發(fā)loader的工具函數(shù)集——loader-utils。

相對(duì)于Loader而言,Plugin的編寫(xiě)就靈活了許多。 webpack在運(yùn)行的生命周期中會(huì)廣播出許多事件,Plugin 可以監(jiān)聽(tīng)這些事件,在合適的時(shí)機(jī)通過(guò) Webpack 提供的 API 改變輸出結(jié)果。

9.webpack的熱更新是如何做到的?說(shuō)明其原理?

webpack的熱更新又稱熱替換(Hot Module Replacement),縮寫(xiě)為HMR。 這個(gè)機(jī)制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。

首先要知道server端和client端都做了處理工作

  1. 第一步,在 webpack 的 watch 模式下,文件系統(tǒng)中某一個(gè)文件發(fā)生修改,webpack 監(jiān)聽(tīng)到文件變化,根據(jù)配置文件對(duì)模塊重新編譯打包,并將打包后的代碼通過(guò)簡(jiǎn)單的 JavaScript 對(duì)象保存在內(nèi)存中。
  2. 第二步是 webpack-dev-server 和 webpack 之間的接口交互,而在這一步,主要是 dev-server 的中間件 webpack-dev-middleware 和 webpack 之間的交互,webpack-dev-middleware 調(diào)用 webpack 暴露的 API對(duì)代碼變化進(jìn)行監(jiān)控,并且告訴 webpack,將代碼打包到內(nèi)存中。
  3. 第三步是 webpack-dev-server 對(duì)文件變化的一個(gè)監(jiān)控,這一步不同于第一步,并不是監(jiān)控代碼變化重新打包。當(dāng)我們?cè)谂渲梦募信渲昧薲evServer.watchContentBase 為 true 的時(shí)候,Server 會(huì)監(jiān)聽(tīng)這些配置文件夾中靜態(tài)文件的變化,變化后會(huì)通知瀏覽器端對(duì)應(yīng)用進(jìn)行 live reload。注意,這兒是瀏覽器刷新,和 HMR 是兩個(gè)概念。
  4. 第四步也是 webpack-dev-server 代碼的工作,該步驟主要是通過(guò) sockjs(webpack-dev-server 的依賴)在瀏覽器端和服務(wù)端之間建立一個(gè) websocket 長(zhǎng)連接,將 webpack 編譯打包的各個(gè)階段的狀態(tài)信息告知瀏覽器端,同時(shí)也包括第三步中 Server 監(jiān)聽(tīng)靜態(tài)文件變化的信息。瀏覽器端根據(jù)這些 socket 消息進(jìn)行不同的操作。當(dāng)然服務(wù)端傳遞的最主要信息還是新模塊的 hash 值,后面的步驟根據(jù)這一 hash 值來(lái)進(jìn)行模塊熱替換。
  5. webpack-dev-server/client 端并不能夠請(qǐng)求更新的代碼,也不會(huì)執(zhí)行熱更模塊操作,而把這些工作又交回給了 webpack,webpack/hot/dev-server 的工作就是根據(jù) webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器呢還是進(jìn)行模塊熱更新。當(dāng)然如果僅僅是刷新瀏覽器,也就沒(méi)有后面那些步驟了。
  6. HotModuleReplacement.runtime 是客戶端 HMR 的中樞,它接收到上一步傳遞給他的新模塊的 hash 值,它通過(guò) JsonpMainTemplate.runtime 向 server 端發(fā)送 Ajax 請(qǐng)求,服務(wù)端返回一個(gè) json,該 json 包含了所有要更新的模塊的 hash 值,獲取到更新列表后,該模塊再次通過(guò) jsonp 請(qǐng)求,獲取到最新的模塊代碼。這就是上圖中 7、8、9 步驟。
  7. 而第 10 步是決定 HMR 成功與否的關(guān)鍵步驟,在該步驟中,HotModulePlugin 將會(huì)對(duì)新舊模塊進(jìn)行對(duì)比,決定是否更新模塊,在決定更新模塊后,檢查模塊之間的依賴關(guān)系,更新模塊的同時(shí)更新模塊間的依賴引用。
  8. 最后一步,當(dāng) HMR 失敗后,回退到 live reload 操作,也就是進(jìn)行瀏覽器刷新來(lái)獲取最新打包代碼。

10.如何用webpack來(lái)優(yōu)化前端性能?

用webpack優(yōu)化前端性能是指優(yōu)化webpack的輸出結(jié)果,讓打包的最終結(jié)果在瀏覽器運(yùn)行快速高效。

  • 壓縮代碼:刪除多余的代碼、注釋、簡(jiǎn)化代碼的寫(xiě)法等等方式。可以利用webpack的UglifyJsPluginParallelUglifyPlugin來(lái)壓縮JS文件, 利用cssnano(css-loader?minimize)來(lái)壓縮css
  • 利用CDN加速: 在構(gòu)建過(guò)程中,將引用的靜態(tài)資源路徑修改為CDN上對(duì)應(yīng)的路徑??梢岳脀ebpack對(duì)于output參數(shù)和各loader的publicPath參數(shù)來(lái)修改資源路徑
  • Tree Shaking: 將代碼中永遠(yuǎn)不會(huì)走到的片段刪除掉??梢酝ㄟ^(guò)在啟動(dòng)webpack時(shí)追加參數(shù)--optimize-minimize來(lái)實(shí)現(xiàn)
  • Code Splitting: 將代碼按路由維度或者組件分塊(chunk),這樣做到按需加載,同時(shí)可以充分利用瀏覽器緩存
  • 提取公共第三方庫(kù): SplitChunksPlugin插件來(lái)進(jìn)行公共模塊抽取,利用瀏覽器緩存可以長(zhǎng)期緩存這些無(wú)需頻繁變動(dòng)的公共代碼

11.如何提高webpack的打包速度?

  • happypack: 利用進(jìn)程并行編譯loader,利用緩存來(lái)使得 rebuild 更快,遺憾的是作者表示已經(jīng)不會(huì)繼續(xù)開(kāi)發(fā)此項(xiàng)目,類似的替代者是thread-loader
  • 外部擴(kuò)展(externals): 將不怎么需要更新的第三方庫(kù)脫離webpack打包,不被打入bundle中,從而減少打包時(shí)間,比如jQuery用script標(biāo)簽引入
  • dll: 采用webpack的 DllPlugin 和 DllReferencePlugin 引入dll,讓一些基本不會(huì)改動(dòng)的代碼先打包成靜態(tài)資源,避免反復(fù)編譯浪費(fèi)時(shí)間
  • 利用緩存: webpack.cache、babel-loader.cacheDirectory、HappyPack.cache都可以利用緩存提高rebuild效率
  • 縮小文件搜索范圍: 比如babel-loader插件,如果你的文件僅存在于src中,那么可以include: path.resolve(__dirname, 'src'),當(dāng)然絕大多數(shù)情況下這種操作的提升有限,除非不小心build了node_modules文件

12.如何提高webpack的構(gòu)建速度?

  1. 多入口情況下,使用CommonsChunkPlugin來(lái)提取公共代碼
  2. 通過(guò)externals配置來(lái)提取常用庫(kù)
  3. 利用DllPluginDllReferencePlugin預(yù)編譯資源模塊 通過(guò)DllPlugin來(lái)對(duì)那些我們引用但是絕對(duì)不會(huì)修改的npm包來(lái)進(jìn)行預(yù)編譯,再通過(guò)DllReferencePlugin將預(yù)編譯的模塊加載進(jìn)來(lái)。
  4. 使用Happypack 實(shí)現(xiàn)多線程加速編譯
  5. 使用webpack-uglify-parallel來(lái)提升uglifyPlugin的壓縮速度。 原理上webpack-uglify-parallel采用了多核并行壓縮來(lái)提升壓縮速度
  6. 使用Tree-shakingScope Hoisting來(lái)剔除多余代碼

13.怎么配置單頁(yè)應(yīng)用?怎么配置多頁(yè)應(yīng)用?

單頁(yè)應(yīng)用可以理解為webpack的標(biāo)準(zhǔn)模式,直接在entry中指定單頁(yè)應(yīng)用的入口即可,這里不再贅述

多頁(yè)應(yīng)用的話,可以使用webpack的 AutoWebPlugin來(lái)完成簡(jiǎn)單自動(dòng)化的構(gòu)建,但是前提是項(xiàng)目的目錄結(jié)構(gòu)必須遵守他預(yù)設(shè)的規(guī)范。 多頁(yè)應(yīng)用中要注意的是:

  • 每個(gè)頁(yè)面都有公共的代碼,可以將這些代碼抽離出來(lái),避免重復(fù)的加載。比如,每個(gè)頁(yè)面都引用了同一套css樣式表
  • 隨著業(yè)務(wù)的不斷擴(kuò)展,頁(yè)面可能會(huì)不斷的追加,所以一定要讓入口的配置足夠靈活,避免每次添加新頁(yè)面還需要修改構(gòu)建配置

14.webpack的基本功能和工作原理?

代碼轉(zhuǎn)換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等

文件優(yōu)化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合并圖片等

代碼分割:提取多個(gè)頁(yè)面的公共代碼、提取首屏不需要執(zhí)行部分的代碼讓其異步加載

模塊合并:在采用模塊化的項(xiàng)目有很多模塊和文件,需要構(gòu)建功能把模塊分類合并成一個(gè)文件

自動(dòng)刷新:監(jiān)聽(tīng)本地源代碼的變化,自動(dòng)構(gòu)建,刷新瀏覽器

代碼校驗(yàn):在代碼被提交到倉(cāng)庫(kù)前需要檢測(cè)代碼是否符合規(guī)范,以及單元測(cè)試是否通過(guò)

自動(dòng)發(fā)布:更新完代碼后,自動(dòng)構(gòu)建出線上發(fā)布代碼并傳輸給發(fā)布系統(tǒng)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容