一、有哪些常見的Loader
raw-loader:加載文件原始內容(utf-8)
file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件 (處理圖片和字體)
url-loader:與 file-loader 類似,區別是用戶可以設置一個閾值,大於閾值時返回其 publicPath,小於閾值時返回文件 base64 形式編碼 (處理圖片和字體)
source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
svg-inline-loader:將壓縮后的 SVG 內容注入代碼中
image-loader:加載並且壓縮圖片文件
json-loader 加載 JSON 文件(默認包含)
babel-loader:把 ES6 轉換成 ES5
ts-loader: 將 TypeScript 轉換成 JavaScript
style-loader:將 CSS 代碼注入 JavaScript 中,通過 DOM 操作去加載
css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
eslint-loader:通過 ESLint 檢查 JavaScript 代碼
更多 Loader 請參考官網:https://webpack.docschina.org/loaders
二、常見的Plugin
define-plugin:定義環境變量 (Webpack4 之后指定 mode 會自動配置)
ignore-plugin:忽略部分文件
html-webpack-plugin:簡化 HTML 文件創建 (依賴於 html-loader)
web-webpack-plugin:可方便地為單頁應用輸出 HTML,比 html-webpack-plugin 好用
webpack-parallel-uglify-plugin: 多進程執行代碼壓縮,提升構建速度
mini-css-extract-plugin: 分離樣式文件,CSS 提取為獨立文件,支持按需加載 (替代extract-text-webpack-plugin)
serviceworker-webpack-plugin:為網頁應用增加離線緩存功能
speed-measure-webpack-plugin: 可以看到每個 Loader 和 Plugin 執行耗時 (整個打包耗時、每個 Plugin 和 Loader 耗時)
webpack-bundle-analyzer: 可視化 Webpack 輸出文件的體積 (業務組件、依賴第三方模塊)
更多 Plugin 請參考官網:https://webpack.docschina.org/plugins
三、Loader和Plugin的區別
Loader 本質就是一個函數,在該函數中對接收到的內容進行轉換,返回轉換后的結果。因為 Webpack 只認識 JavaScript,所以 Loader 就成了翻譯官,對其他類型的資源進行轉譯的預處理工作。
Loader 在 module.rules 中配置,作為模塊的解析規則,類型為數組。每一項都是一個 Object,內部包含了 test(類型文件)、loader、options (參數)等屬性。
Plugin 就是插件,基於事件流框架 Tapable,插件可以擴展 Webpack 的功能,在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
Plugin 在 plugins 中單獨配置,類型為數組,每一項是一個 Plugin 的實例,參數都通過構造函數傳入。
四、Webpack構建流程
Webpack 的運行流程是一個串行的過程,從啟動到結束會依次執行以下流程:
-
初始化參數:從配置文件和 Shell 語句中讀取與合並參數,得出最終的參數 -
開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,執行對象的 run 方法開始執行編譯 -
確定入口:根據配置中的 entry 找出所有的入口文件 -
編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理 -
完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系 -
輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會 -
輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件后會執行特定的邏輯,並且插件可以調用 Webpack 提供的 API 改變 Webpack 的運行結果。
簡單說就是三步:
1、初始化:啟動構建,讀取合並配置參數,加載plugin,實例化Compiler
2、編譯:從entry入口出發,針對每個module串行調用對應的loader函數去翻譯文件的內容,再找出該module依賴的module,遞歸的進行編譯處理
3、輸出:將編譯后的module組合成chunk,將chunk轉換成文件,輸出到文件系統中
四、使用webpack開發時,有哪些可以提高效率的插件
webpack-dashboard:可以更友好的展示相關打包信息。
webpack-merge:提取公共配置,減少重復配置代碼
speed-measure-webpack-plugin:簡稱 SMP,分析出 Webpack 打包過程中 Loader 和 Plugin 的耗時,有助於找到構建過程中的性能瓶頸。
size-plugin:監控資源體積變化,盡早發現問題
HotModuleReplacementPlugin:模塊熱替換
五、source map是什么?生產環境怎么用?
source map 是將編譯、打包、壓縮后的代碼映射回源代碼的過程。打包壓縮后的代碼不具備良好的可讀性,想要調試源碼就需要 soucre map。
map文件只要不打開開發者工具,瀏覽器是不會加載的。
線上環境一般有三種處理方案:
-
hidden-source-map:借助第三方錯誤監控平台 Sentry 使用 -
nosources-source-map:只會顯示具體行數以及查看源代碼的錯誤棧。安全性比 sourcemap 高 -
sourcemap:通過 nginx 設置將 .map 文件只對白名單開放(公司內網)
六、模塊打包原理
Webpack 實際上為每個模塊創造了一個可以導出和導入的環境,本質上並沒有修改代碼的執行邏輯,代碼執行順序與模塊加載順序也完全一致。
七、文件監聽原理
在發現源碼發生變化時,自動重新構建出新的輸出文件。Webpack開啟監聽模式,有兩種方式:
- 啟動 webpack 命令時,帶上 --watch 參數
- 在配置 webpack.config.js 中設置 watch:true
原理:輪詢判斷文件的最后編輯時間是否變化,如果某個文件發生了變化,並不會立刻告訴監聽者,而是先緩存起來,等 aggregateTimeout 后再執行。
module.export = { // 默認false,也就是不開啟
watch: true, // 只有開啟監聽模式時,watchOptions才有意義
watchOptions: { // 默認為空,不監聽的文件或者文件夾,支持正則匹配
ignored: /node_modules/, // 監聽到變化發生后會等300ms再去執行,默認300ms
aggregateTimeout:300, // 判斷文件是否發生變化是通過不停詢問系統指定文件有沒有變化實現的,默認每秒問1000次
poll:1000 } }
八、Webpack 的熱更新原理(重點)
Webpack 的熱更新又稱熱替換(Hot Module Replacement),縮寫為 HMR。這個機制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
HMR的核心就是客戶端從服務端拉取更新后的文件,准確的說是 chunk diff (chunk 需要更新的部分),實際上 WDS 與瀏覽器之間維護了一個 Websocket,當本地資源發生變化時,WDS 會向瀏覽器推送更新,並帶上構建時的 hash,讓客戶端與上一次資源進行對比。客戶端對比出差異后會向 WDS 發起 Ajax 請求來獲取更改內容(文件列表、hash),這樣客戶端就可以再借助這些信息繼續向 WDS 發起 jsonp 請求獲取該chunk的增量更新。
后續的部分(拿到增量更新之后如何處理?哪些狀態該保留?哪些又需要更新?)由 HotModulePlugin 來完成,提供了相關 API 以供開發者針對自身場景進行處理,像react-hot-loader 和 vue-loader 都是借助這些 API 實現 HMR。
細節請參考Webpack HMR 原理解析:https://zhuanlan.zhihu.com/p/30669007
九、如何對bundle體積進行監控和分析
VSCode 中有一個插件 Import Cost 可以幫助我們對引入模塊的大小進行實時監測,還可以使用 webpack-bundle-analyzer 生成 bundle 的模塊組成圖,顯示所占體積。bundlesize 工具包可以進行自動化資源體積監控。
十、文件指紋是什么、怎么用
文件指紋是打包后輸出的文件名的后綴。
-
Hash:和整個項目的構建相關,只要項目文件有修改,整個項目構建的 hash 值就會更改 -
Chunkhash:和 Webpack 打包的 chunk 有關,不同的 entry 會生出不同的 chunkhash -
Contenthash:根據文件內容來定義 hash,文件內容不變,則 contenthash 不變
十一:如何保證各個loader按照預想方式工作
可以使用 enforce 強制執行 loader 的作用順序,pre 代表在所有正常 loader 之前執行,post 是所有 loader 之后執行。(inline 官方不推薦使用)
