在前文 Webpack 打包優化之體積篇中,對如何減小 Webpack
打包體積,做了些探討;當然,那些法子對於打包速度的提升,也是大有裨益。然而,打包速度之於開發體驗和及時構建,相當重要;所以有必要對其做更為深入的研究,以便完善工作流,這就是本文存在的緣由。
減小文件搜索范圍
在使用實際項目開發中,為了提升開發效率,很明顯你會使用很多成熟第三方庫;即便自己寫的代碼,模塊間相互引用,為了方便也會使用相對路勁,或者別名(alias
);這中間如果能使得 Webpack
更快尋找到目標,將對打包速度產生很是積極的影響。於此,我們需要做的即:減小文件搜索范圍,從而提升速度;實現這一點,可以有如下兩法:
配置 resolve.modules
Webpack的resolve.modules
配置模塊庫(即 node_modules)所在的位置,在 js 里出現 import 'vue'
這樣不是相對、也不是絕對路徑的寫法時,會去 node_modules 目錄下找。但是默認的配置,會采用向上遞歸搜索的方式去尋找,但通常項目目錄里只有一個 node_modules,且是在項目根目錄,為了減少搜索范圍,可以直接寫明 node_modules
的全路徑;同樣,對於別名(alias
)的配置,亦當如此:
1 |
function resolve (dir) { |
需要額外補充一點的是,這是 Webpack2.* 以上的寫法。在 1.* 版本中,使用的是 resolve.root
,如今已經被棄用為 resolve.modules
;同時被棄用的還有resolve.fallback
、resolve.modulesDirectories
。
設置 test & include & exclude
Webpack
的裝載機(loaders),允許每個子項都可以有以下屬性:
test:必須滿足的條件(正則表達式,不要加引號,匹配要處理的文件)
exclude:不能滿足的條件(排除不處理的目錄)
include:導入的文件將由加載程序轉換的路徑或文件數組(把要處理的目錄包括進來)
loader:一串“!”分隔的裝載機(2.0版本以上,”-loader”不可以省略)
loaders:作為字符串的裝載器陣列
對於include
,更精確指定要處理的目錄,這可以減少不必要的遍歷,從而減少性能損失。同樣,對於已經明確知道的,不需要處理的目錄,則應該予以排除,從而進一步提升性能。假設你有一個第三方組件的引用,它肯定位於node_modules,通常它將有一個 src 和一個 dist 目錄。如果配置 Webpack
來排除 node_modules,那么它將從 dist 已經編譯的目錄中獲取文件。否則會再次編譯它們。故而,合理的設置 include & exclude,將會極大地提升 Webpack
打包優化速度,比如像這樣:
1 |
module: { |
增強代碼代碼壓縮工具
Webpack
默認提供的 UglifyJS
插件,由於采用單線程壓縮,速度頗慢 ;推薦采用 webpack-parallel-uglify-plugin 插件,她可以並行運行 UglifyJS 插件,更加充分而合理的使用 CPU
資源,這可以大大減少的構建時間;當然,該插件應用於生產環境而非開發環境,其做法如下,
1 |
new webpack.optimize.UglifyJsPlugin({ |
替換如上自帶的 UglifyJsPlugin
寫法為如下配置即可:
1 |
var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); |
當然也有其他同類型的插件,比如:webpack-uglify-parallel,但根據自己實踐效果來看,並沒有 webpack-parallel-uglify-plugin
表現的那么卓越,有興趣的朋友,可以更全面的做下對比,擇優選用。需要額外說明的是,webpack-parallel-uglify-plugin
插件的運用,會相對 UglifyJsPlugin
打出的包,看起來略大那么一丟丟(其實可以忽略不計);如果在你使用時也是如此,那么在打包速度跟包體積之間,你應該有自己的抉擇。
用 Happypack 來加速代碼構建
你知道,Webpack
中為了方便各種資源和類型的加載,設計了以 loader
加載器的形式讀取資源,但是受限於 nodejs
的編程模型影響,所有的 loader
雖然以 async
的形式來並發調用,但是還是運行在單個 node 的進程,以及在同一個事件循環中,這就直接導致了些問題:當同時讀取多個loader文件資源時,比如`babel-loader`需要 transform 各種jsx,es6的資源文件。在這種同步計算同時需要大量耗費 cpu 運算的過程中,node的單進程模型就無優勢了,而 Happypack 就是針對解決此類問題而生的存在。
Happypack
的處理思路是:將原有的 webpack
對 loader
的執行過程,從單一進程的形式擴展多進程模式,從而加速代碼構建;原本的流程保持不變,這樣可以在不修改原有配置的基礎上,來完成對編譯過程的優化,具體配置如下:
1 |
var HappyPack = require('happypack'); |
可以研究看到,通過在 loader
中配置直接指向 happypack
提供的 loader,對於文件實際匹配的處理 loader,則是通過配置在 plugin
屬性來傳遞說明,這里 happypack 提供的 loader 與 plugin 的銜接匹配,則是通過id=happybabel來完成。配置完成后,laoder的工作模式就轉變成了如下所示:
Happypack
在編譯過程中,除了利用多進程的模式加速編譯,還同時開啟了 cache
計算,能充分利用緩存讀取構建文件,對構建的速度提升也是非常明顯的;更多關於 happyoack
個中原理,可參見 @淘寶前端團隊(FED) 的這篇:happypack 原理解析。如果你使用的 Vue.js
框架來開發,也可參考 vue-webpack-happypack 相關配置。
設置 babel 的 cacheDirectory 為true
babel-loader is slow! 所以不僅要使用exclude
、include
,盡可能准確的指定要轉化內容的范疇,而且要充分利用緩存,進一步提升性能。babel-loader
提供了 cacheDirectory
特定選項(默認 false
):設置時,給定的目錄將用於緩存加載器的結果。
未來的 Webpack
構建將嘗試從緩存中讀取,以避免在每次運行時運行潛在昂貴的 Babel
重新編譯過程。如果值為空(loader: ‘babel-loader?cacheDirectory’)或true
(loader: babel-loader?cacheDirectory=true),node_modules/.cache/babel-loader 則 node_modules 在任何根目錄中找不到任何文件夾時,加載程序將使用默認緩存目錄或回退到默認的OS臨時文件目錄。實際使用中,效果顯著;配置示例如下:
1 |
rules: [ |
設置 noParse
如果你確定一個模塊中,沒有其它新的依賴,就可以配置這項, Webpack
將不再掃描這個文件中的依賴,這對於比較大型類庫,將能促進性能表現,具體可以參見以下配置:
1 |
module: { |
拷貝靜態文件
在前文 Webpack 打包優化之體積篇中提到,引入 DllPlugin
和 DllReferencePlugin
來提前構建一些第三方庫,來優化 Webpack
打包。而在生產環境時,就需要將提前構建好的包,同步到 dist
中;這里拷貝靜態文件,你可以使用 copy-webpack-plugin
插件:把指定文件夾下的文件復制到指定的目錄;其配置如下:
1 |
var CopyWebpackPlugin = require('copy-webpack-plugin') |
當然,這種工作,實現的法子很多,比如可以借助 shelljs
,可以參見這里的實現 vue-boilerplate-template。
於深圳.南山 @17-08-10 Last Modify: @17-08-13
如若轉載,請保留原文鏈接: Webpack 打包優化之速度篇