webpack 相關

 webpackgruntgulp 的區別

grunt、gulp 是基於任務運行的工具:它們會自動執行指定的任務,就像流水線,把資源放上去而後經過不一樣插件進行加工,它們包含活躍的社區,豐富的插件,能方便的打造各類工做流。css

webpack 是基於模塊化打包的工具:webpack 把一切都當作模塊,當 webpack 處理程序時,會遞歸地構建一個依賴關係圖,其中包含應用程序須要的每一個模塊,而後將全部的模塊打包成一個或者多個 bundlehtml

所以這是兩類徹底不一樣性質的工具,而 npm script 也能夠打造任務流。前端

webpackrollupparcel 優劣

webpack 適用於大型複雜的前端站點構建:webpack 有強大的 loader 和插件生態,打包後的文件實際上就是一個當即執行函數,這個當即執行函數接收一個參數(模塊對象),鍵爲各個模塊的路徑,值爲模塊內容。當即函數內部處理模塊之間的引用、執行模塊等,更適合文件依賴複雜的應用開發。vue

rollup 適用於基礎庫的打包,好比說vued3等。rollup 將各個模塊打包進一個文件中,並經過 Tree-shaking 來刪除無用的代碼,能夠最大程度上下降代碼體積,可是 rollup 沒有 webpack 那麼多的代碼分割、按需加載等功能,更加適合庫的開發。webpack

parcel 適用於簡單的實驗性項目:能夠知足低門檻的快速看到效果,可是生態差、報錯信息不夠全面都是問題,除了一些實驗性項目不建議使用。web

常見的 loader

  • file-loader 把文件輸出到一個文件夾中,在代碼中經過相對 URL 引用輸入的文件
  • url_loader 和 file-loader 相似,能在文件很小的狀況下以 base64 的方式將文件內容注入到代碼中
  • source-map-loader 加載額外的 Source Map 文件,方便斷點調試
  • image-loader 加載並壓縮圖片文件
  • babel-loader 將 ES6 轉換爲 ES5
  • css-loader 加載 css,支持模塊化、壓縮、文件導入等特性
  • style-loader 把 css 代碼注入到 JavaScript 中,經過 DOM 操做去加載 css
  • eslint-loader 經過 ESLint 檢查 JavaScript 代碼
  • html-minify-loader 壓縮HTML

loader 特性

  • loader 從右到左地取值(evaluate)/執行(execute)
  • loader 支持鏈式傳遞,鏈中的每一個 loader 會將轉換應用在已處理過的資源上
  • loader 也能夠內聯顯示指定
  • loader 能夠是同步的,也能夠是異步的
  • loader 運行在 Node.js 中,而且可以執行任何 Node.js 能作到的操做
  • loader 能夠經過 options 對象配置
  • 除了常見的經過 package.json 的 main 來將一個 npm 模塊導出爲 loader,還能夠在 module.rules 中使用 loader 字段直接引用一個模塊
  • loader 可以產生額外的任意文件

常見的 plugin

  • define-plugin 定義環境變量
  • html-webpack-plugin 簡化 html 文件建立
  • uglifyjs-webpack-plugin 經過 UglifyES 壓縮 ES6 代碼
  • webpack-parallel-uglify-plugin 多核壓縮,提升壓縮速度
  • webpack-bundle-analyzer 可視化 webpack 輸出文件的體積
  • mini-css-extract-plugin CSS 提取到單獨的文件中,支持按需加載
  • clean-webpack-plugin 在每次構建前清理 /dist 文件夾

loaderplugin 的不一樣

做用不一樣

loader 爲加載器,webpack 將一切文件視爲模塊,可是 webpack 原生只能解析 js 和 json 文件,若是想將其餘文件也打包的話,就會用到 loader,所以,loader 的做用是讓 webpack 能夠加載和解析非 JavaScript 文件。npm

plugin 爲插件。能夠擴展 webpack 的功能,讓 webpack 更靈活。在 webpack 的運行週期中會廣播出許多事件,plugin 能夠監聽這些事件,在合適的時機經過 webpack 提供的 API 改變輸出結果。json

用法不一樣

loader 在 module.rules 中配置,即做爲模塊的解析規則存在。類型爲數組,每一項都是一個 object,裏面描述了對於什麼類型的文件是用什麼加載和使用的參數。gulp

plugin 在 plugins 中單獨配置。類型爲數組,每一項是一個 plugin 的實例,參數都是經過構造函數傳入。數組

bundlechunkmodule

bundle webpack 打包出來的文件

chunk 代碼塊,一個 chunk 由多個模塊組合而成,用於代碼的合併和分割

module 開發中的單個模塊,webpack 中一切皆模塊,一個模塊對應一個文件

webpack 的構建流程

webpack 的運行流程是一個串行的過程,從啓動到結束會一次執行如下流程:

  1. 初始化參數:從配置文件和腳本語句中讀取與合併參數,得出最終的參數;
  2. 開始編譯:用上一步獲得的參數初始化 Compiler 對象,加載全部配置的插件,執行對象的 run 方法開始執行編譯;
  3. 肯定入口:根據配置中的 entry 找出全部的入口文件;
  4. 編譯模塊:從入口文件出發,調用全部配置的 loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟,直到全部入口文件依賴的文件都通過了本步驟的處理;
  5. 完成模塊編譯:第4步翻譯完成全部模塊後,獲得了每一個模塊被翻譯後的最終內容以及它們的依賴關係;
  6. 輸出資源:根據入口和模塊之間的依賴關係,組裝成一個個包含多個模塊的 chunk,再把每一個 chunk 轉換成一個單獨的文件加入到輸出列表,這步是能夠修改輸出內容的最後機會;
  7. 輸出完成:在肯定好輸出內容後,根據配置肯定輸出的路徑和文件名,將文件內容寫入到文件系統。

在以上過程當中,webpack 會在特定的時間點廣播出特定的時間,插件在監聽到事件後,會執行特定的邏輯,而且插件能夠調用 webpack 提供的 API 改變 webpack 的運行結果。

是否本身寫過 loaderplugin

loader 把讀到的源文件內容轉義成新的文件內容,而且每一個 loader 經過鏈式操做,將源文件轉換成想要的樣子。

編寫 loader 的時候要遵循單一原則,每個 loader 只作一種轉義工做,loader 拿到的是源文件內容(source),處理後能夠經過返回值的方式將處理後的內容輸出,也能夠調用 this.callback() 方法將內容返回給 webpack。還能夠經過 this.async() 生成一個 callback 函數,再用這個 callback 將處理後的內容輸出出去。此外 webpack 還爲開發者準備了開發 loader 的工具函數集 —— loader-utils

plugin 監聽 webpack 運行中廣播出的事件,在合適的時機經過 webpack 提供的 API 改變輸出結果。

webpack 的熱更新是如何作到的

熱更新又稱做熱替換(Hot Module Replacement),縮寫爲 HMR。這個機制能夠作到不用刷新瀏覽器而將新變動的模塊替換掉舊的模塊。

熱更新在 server 端和 client 端都作了處理

  1. webpackwatch 模式下,文件系統中的某個文件發生改變,webpack 監聽到文件變化,根據配置文件對模塊從新編譯打包,並將打包後的代碼經過簡單的 JavaScript 對象保存在內存中。
  2. webpack-dev-serverwebpack 之間的接口交互,這一步,主要是 dev-server 的中間件 webpack-dev-middlewarewebpack 之間的交互,webpack-dev-middleware 調用 webpack 暴露的 API 對代碼變化進行監控,而且告訴 webpack 將代碼打包到內存中。
  3. webpack-dev-server 對文件變化的監控,並非監控代碼變化從新打包。當在配置文件中配置了 devServer.watchContentBasetrue 的時候,server 會監聽這些配置文件夾中靜態文件的變化,變化後會通知瀏覽器端對應用進行 live reload,這裏是瀏覽器刷新。
  4. wecpack-dev-server 代碼的工做,主要經過 sockjswebpack-dev-server 的依賴)在瀏覽器端和服務器端創建一個 websocket 的長鏈接,將 webpack 編譯打包的各個階段的狀態信息告知瀏覽器端,同時也包括第3步中 server 監聽靜態文件變化的信息。瀏覽器端根據這些 socket 消息進行不一樣的操做,服務端傳遞的主要信息仍是新模塊的 hash 值,後面的步驟根據這一 hash 值來進行模塊熱替換。
  5. webpack-dev-server/client 端並不可以請求更新代碼,也不會執行熱更新模塊操做,這些工做依舊會交回給 webpackwebpack/hot/dev-server 的工做是根據 webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器仍是進行模塊熱更新。若僅僅是刷新瀏覽器,就沒有後續的操做了。
  6. HotModuleReplacement.runtime 是客戶端 HMR 的中樞,接收上一步傳給它的新模塊的 hash 值,經過 JsonpMainTemplate.runtimeserver 端發送 Ajax 請求,服務端返回一個 json,該 json 包含了全部要更新的模塊的 hash 值,獲取到更新列表後,該模塊再次經過 jsonp 請求獲取到最新的模塊代碼。
  7. HotModulePlugin 會對新舊模塊進行對比,決定是否更新模塊,再決定更新模塊後,檢查模塊之間的依賴關係,更新模塊的同時更新模塊間的依賴引用。
  8. HMR 失敗後,回退到 live reload 操做,也就是進行瀏覽器刷新來獲取最新打包代碼。

webpack 優化前端性能

  • 壓縮代碼:刪除多餘的代碼、註釋、簡化代碼的寫法。可使用 UglifyJsPluginParallelUglifyPlugin 來壓縮 JS 文件,利用 cssnano 來壓縮 css 代碼。
  • 利用 CDN 加速:在構建的過程當中將引用的靜態資源路徑修改成 CDN 上對應的路徑,可使用 webpack 對於 output 參數和各個 loader 的 publicPath 參數來修改資源路徑。
  • Tree Shaking:將代碼中永遠不會走到的片斷刪除掉,能夠在啓動 webpack 時追加參數  --optimize-minimize 來實現。
  • Code Splitting:將代碼按照路由維度或者組件分塊,能夠作到按需加載,同時能夠充分利用瀏覽器緩存。
  • 提取公共第三方庫:SplitChunksPlugin 插件來進行公共模塊抽取,利用瀏覽器緩存能夠長期緩存這些無需頻繁變更的公共代碼。

提升 webpack 的打包速度

  • happypack:利用進程並行編譯 loader,利用緩存來使得 rebuild 更快,相似的替代者:thread-loader
  • 外部擴展:將不怎麼須要的第三方庫脫離 webpack 打包,減小打包時間。
  • dll:採用 webpackDllPluginDllReferencePlugin 引入 dll,讓一些基本不會改動的代碼先打包成靜態資源,避免反覆編譯浪費時間。
  • 利用緩存:webpack.cachebabel-loader.cacheDirectoryHappyPack.cache 均可以利用緩存提升 rebuild 的時間。
  • 縮小文件搜索範圍:好比 babel-loader,若文件僅存在於 src 中可使用:include: path.resolve(__dirname, src)

提升 webpack 的構建速度

  • 多入口狀況下,使用 CommonsChunkPlugin 來提取公共代碼
  • 經過 external 配置來提取經常使用庫
  • 利用 DllPluginDllReferencePlugin 預編譯資源模塊,經過 DllPlugin 來對哪些引用可是絕對不會修改的 npm 包來進行預編譯,再經過 DllReferencePlugin 將預編譯的模塊加再加載進來
  • 使用 HappyPack 實現多線程加速編譯
  • 使用 webpack-uglify-parallel 來提高 uglifyPlugin 的壓縮速度
  • 使用 Tree-shakingScope Hoisting 來剔除多餘代碼
相關文章
相關標籤/搜索