項目比較小的狀況下Webpack的性能問題幾乎能夠忽略,可是一旦項目複雜度上升,Webpack會有額外的性能損失須要咱們進行優化。javascript
經過前面內容的學習咱們能夠知道Webpack主要幹下面這些事情:css
所以,咱們能夠從這方面入手進行優化,減小Webpack搜索文件的範圍,減小沒必要要的處理。java
在以前的內容中介紹過loader可使用test、include、exclude配置項來匹配須要Loader處理的文件,所以推薦給每一個loader定義test以後還定義include或exclude。node
module.exports = { module:{ rules:[ { test:/\.js$/, use:'babel-loader', include: path.resolve(__dirname, 'src'), // 只處理src目錄下的js文件 } ] } };
導入未添加擴展名的模塊時,Webpack會經過resolve.extensions後綴去檢查文件是否存在。因爲resolve.extensions是一個數組,若是數組項比較多,正確的後綴放置得越靠後,Webpack嘗試次數就會越多,影響到性能。react
所以配置resolve.extensions時須要遵照如下規則:webpack
module.noParse能夠告訴Webpack忽略未採用模塊系統文件的處理,能夠有效地提升性能。好比常見的jQuery很是大,又沒有采用模塊系統,讓Webpack解析這類型文件徹底是浪費性能。web
所以咱們能夠配置以下的module.noParse:npm
module.exports = { module:{ noParse:[/jQuery/] } };
在導入模塊時,IgnorePlugin能夠忽略指定模塊的生成。好比moment.js在導入時會自動導入本地化文件,通常狀況下幾乎不使用並且又比較大,此時能夠經過IgnorePlugin忽略對本地化文件的生成,減少文件大小。json
module.exports = { plugins:[ new webpack.IgnorePlugin(/\.\/local/, /moment/) ] };
使用過Windows操做系統的讀者應該會常常看到以.dll擴展名的文件,這些文件叫作動態連接庫,包含了其餘程序或動態連接庫的函數和數據。數組
Webpack的DllPlugin的思想是相似的,先將公共模塊打包爲獨立的Dll模塊,而後在業務代碼中直接引用這些模塊。採用DllPlugin以後會大大提高Webpack構建速度,緣由在於,包含大量複用模塊的動態連接庫只須要編譯一次,以後的構建中會直接引用這些構建好的模塊。
在Webpack中使用動態連接庫有如下兩個步驟:
下面以React項目爲例進行說明。
Dll庫須要單獨構建,所以咱們須要一份單獨的配置Webpack文件。
1.新建webpack.dll.config.js
const webpack = require('webpack'); module.exports = { entry:{ react: ['react', 'react-dom'] }, output:{ filename: '_dll_[name].js', // 輸出的文件名 path: path.resolve(__dirname, 'dist'), // 輸出到dist目錄 library: '_dll_[name]' }, plugins: [ // name要等於output.library裏的name new webpack.DllPlugin({ name: "_dll_[name]", path: path.resolve(__dirname, "dist", "manifest.json") // 清單文件路徑 }) ] };
2.編輯webpack.config.js
const webpack = require('webpack'); module.exports = { entry: './src/main', output:{ filename: '[name].js', // 輸出的文件名 path: path.resolve(__dirname, 'dist'), // 輸出到dist目錄 }, plugins: [ // 傳入manifest.json new webpack.DllReferencePlugin({ manifest: path.resolve(__dirname, "dist", "manifest.json") // 清單文件路徑 }) ] };
3.添加構建命令
{ "scripts":{ "build-dll":"webpack --config webpack.dll.config.js", "build":"webpack" } }
4.構建Dll
npm run build-dll
5.構建應用
npm run build
Dll須要先構建,不然應用將構建失敗
Webpack默認狀況下是單進程執行的,所以沒法利用多核優點,經過HappyPack能夠變成多進程構建,從而提高構建速度。下面咱們一塊兒來看看如何使用happypack來加速構建。
1.安裝happypack
npm isntall happypack
2.編輯配置文件,須要將Loader配置到HappyPack插件中,由HappyPack對Loader進行調用。
const HappyPackPlugin = require('happypack'); const path = require('path'); module.exports = { entry: './src/main', output:{ path: path.resolve(__dirname, 'build'), filename:'[name].js' }, module:{ rules:[ { test:/\.js$/, use:'happypack/loader?id=js', // 配置id爲js include:[ path.resolve(__dirname,'src') ] }, { test:/\.scss$/, use:'happypack/loader?id=scss', // 配置id爲scss include:[ path.resolve(__dirname,'src') ] }, { test:/\.css$/, use:'happypack/loader?id=css', // 配置id爲css include:[ path.resolve(__dirname,'src') ] } ] }, plugins:[ new HappyPackPlugin({ id:'js', // id爲js的loader配置 use:[ { loader:'babel-loader', options:{ plugins:['@babel/transform-runtime'], presets:['@babel/env'] } } ] }), new HappyPackPlugin({ id:'scss', // id爲scss的loader配置 use:['style-loader','css-loader','sass-loader'] }), new HappyPackPlugin({ id:'css', // id爲css的loader配置 use:['style-loader','css-loader'] }), ] };
Tree-Shaking原始的本意是」搖動樹「,這樣就會將一些分支」搖掉「,從而減小主幹大小。而Webpack中的Tree-Shaking是相似的,在Webpack項目中,有一個入口文件,至關於樹的主幹,入口文件又依賴了許多模塊。實際開發中,雖然依賴了某個模塊,但其實只使用了其中的部分代碼,經過Tree-Shaking,能夠將模塊中未使用的代碼剔除掉,從而減小構建結果的大小。
注意:只有使用ES6模塊系統的代碼,在mode爲production時,Tree-Shaking纔會生效。所以,在編寫代碼時儘可能使用import/export的方式。
在開發中,咱們通常會將業務代碼打包爲app.js,其餘第三方依賴打包爲vendor.js。這樣會有一個比較大的問題,若是依賴的第三方模塊過多,vendor.js會愈來愈大,而在瀏覽器加載時須要徹底加載完vendor.js才能夠,這樣就會形成無謂的等待,由於咱們當前頁面可能只使用了一部分代碼。此時可使用Webpack來實現按需加載,只有在真正用到這個模塊時纔會加載相應的js。
好比基於echarts開發了一個數據可視化頁面,能夠在這個路由組件下面使用異步的方式加載echarts的代碼:
import('echarts').then(modules => { const echarts = modules.default; const chart = echarts.init(document.querySelector('#chart')); });
不過使用按需加載時,構建代碼中會包含Promise調用,所以低版本瀏覽器須要注入Promise的polyfill實現。
Webpack4中能夠將多個公共模塊打包一份,減小代碼冗餘,Webpack4以前的版本是使用webpack內置的CommonsChunkPlugin實現的,Webpack4直接配置optimization
便可。
module.exports = { optimization:{ splitChunks:{ cacheGroups:{ common:{ // 應用代碼中公共模塊 chunks: 'all', // 最小公共模塊引用次數 minChunks: 2 }, vendor:{ // node_modules中第三方模塊 test: /node_modules/, chunks: 'all', minChunks: 1 } } } } };
第三方庫代碼的變動通常比較少(經過package.json的版本能夠指定依賴版本),所以構建出來的vendor.js基本不會變就能夠利用瀏覽器的緩存機制進行緩存。
而應用代碼的變動是比較頻繁的,所以單獨打包爲common.js,瀏覽器能夠單獨緩存,若是應用代碼發生變動,瀏覽器只用從新下載common.js文件,而不用從新下載vendor.js。
HMR(Hot Module Replacement)是Webpack提供的經常使用功能之一,它容許在運行時對模塊進行修改,而無需刷新整個頁面(LiveReload須要刷新頁面才能加載),這樣有如下優點:
使用如下配置便可打開內置的HMR功能:
const webpack = require('webpack'); module.exports = { devServer: { hot: true, // 啓用熱加載 contentBase: './dist', }, plugins:[ new webpack.NamedModulesPlugin(), // 打印更新的模塊路徑 new webpack.HotModuleReplacementPlugin() // 熱更新插件 ] };
本文咱們對Webpack4最經常使用的性能優化技術進行了學習,這些優化方法對業務代碼的侵入性很是小(只有按需加載優化會要求使用import()函數進行加載),在實際的開發中,能夠結合這些技術進行鍼對性的優化,好比開發時編譯慢,可能就須要使用HappyPack插件進行多進程編譯以加快編譯速度等等。