基於 Webpack 的應用包體尺寸優化
基於 Webpack 的應用包體尺寸優化翻譯自Optimising-Your-Application-Bundle-Size-With-Webpack,從屬於筆者的 Web 前端入門與最佳實踐 中的 React 入門與最佳實踐系列。筆者翻譯此文也是為了完善自己的技術體系內容,不過推薦直接瀏覽Webpack 官方網站。前面還有一篇簡單幾步助你優化React應用包體。
最近我在構建一個基於 React 的單頁應用,當我用Google TestMySite來檢測自己的站點時,它的反饋是載入時間過長,因此我開始考慮如何優化初次下載的包體大小。優化應用包體的第一步就是檢視當前的包體組成,判斷其中哪些依賴時必須的,我們在 Webpack 的回顯中可以看到當前的包體大小:
$ webpack -p --progressHash: dbce3735c9520e2dc682Version: webpack 1.14.0Time: 54264ms Asset Size Chunks Chunk Names dist/index.js 3.29 MB 0 [emitted] maindist/index.js.map 13.7 MB 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1374 hidden modules
分析包體依賴
這裡我們使用webpack-bundle-analyzer來分析 Webpack 生成的包體組成並且以可視化的方式反饋給開發者。我們可以使用npm來安裝該插件:
$ npm install --save-dev webpack-bundle-analyzer
然後我們需要修改webpack.config.js來引入該插件:
var BundleAnalyzerPlugin = require(webpack-bundle-analyzer).BundleAnalyzerPlugin;// ...plugins: [new BundleAnalyzerPlugin()]// ...
然後我們照常使用 Webpack 編譯之後,可視化的結果會被展示在http://localhost:8888/,你大概可以看到如下的交互界面:
這個交互插件應該能幫你分析哪些依賴佔據了主要的包體大小,這也提醒我們在引入某個功能的時候,應該只引入需要的模塊,以 Lodash 為例://1. Import the entire lodash library and add it to the bundleimport lodash from lodashlodash.groupBy(rows, id)//2. Import only the required function from lodashimport groupBy from lodash/groupBygroupBy(rows, id)
設置合適的 Node 環境變數
設置合適的環境變數能夠幫助 Webpack 更好地去壓縮處理依賴中的代碼,我們需要在生產環境中將NODE_ENV設置為production:
plugins: [... new webpack.DefinePlugin({ process.env.NODE_ENV: "production" }),..]
使用最小化的 SourceMap
當我們在生產環境下組合壓縮 JavaScript 文件時,Webpack 會為我們生成某個 SourceMap 文件來映射源文件的內容。在開發環境中我們經常會將devtool設置為eval,這樣會將大量的代碼信息打包到輸出包體中從而提升編譯速度。而開發環境中我們可以將該項設置為eval-source-map或者cheap-module-source-map,詳細介紹參考這裡,我們比較切換前後的包體大小可以發現縮小了將近 1MB 的內容:
$ webpack -p --progressHash: 68a52fddbcc2898a5899Version: webpack 1.14.0Time: 29757ms Asset Size Chunks Chunk Names dist/index.js 1.71 MB 0 [emitted] maindist/index.js.map 464 bytes 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1365 hidden modules
其他常用插件
這裡我列舉幾個常用的能夠用於減少包體大小的插件,我們可以根據項目需求選擇性的使用:
compression-webpack-plugin:該插件能夠將資源文件壓縮為.gz文件,並且根據客戶端的需求按需載入。
dedupeplugin:抽取出輸出包體中的相同或者近似的文件或者代碼,可能對於 Entry Chunk 有所負擔,不過能有效地減少包體大小。
uglifyjsplugin:壓縮輸出塊的大小,可以參考官方文檔。
ignoreplugin:用於忽略引入模塊中並不需要的內容,譬如當我們引入moment.js時,我們並不需要引入該庫中所有的區域設置,因此可以利用該插件忽略不必要的代碼。
...var CompressionPlugin = require("compression-webpack-plugin");...let config = { entry: path.join(__dirname, ../app/index), cache: false, devtool: cheap-module-source-map, plugins: [ new webpack.DefinePlugin({ process.env.NODE_ENV: "production" }), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: true, compress: { warnings: false, // Suppress uglification warnings pure_getters: true, unsafe: true, unsafe_comps: true, screw_ie8: true }, output: { comments: false, }, exclude: [/.min.js$/gi] // skip pre-minified libs }), new webpack.IgnorePlugin(/^./locale$/, [/moment$/]), new webpack.NoErrorsPlugin(), new CompressionPlugin({ asset: "[path].gz[query]", algorithm: "gzip", test: /.js$|.css$|.html$/, threshold: 10240, minRatio: 0 }) ... ],
引入該插件後包體的體積會受到進一步的壓縮:
$ webpack -p --progressHash: 68a52fddbcc2898a5899Version: webpack 1.14.0Time: 29757ms Asset Size Chunks Chunk Names dist/index.js 1.54 MB 0 [emitted] maindist/index.js.gz 390 KB 0 [emitted] maindist/index.js.map 464 bytes 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1365 hidden modules
推薦閱讀:
※React 實現一個漂亮的 Table
※React Conf 2017 不能錯過的大起底——Day 1!
※解析 Redux 源碼
※我對Flexbox布局模式的理解
※從0到1,細說 React 開發環境搭建那點事