Webpack4不求人(3) ——性能優化

限定Webpack處理文件範圍

項目比較小的狀況下Webpack的性能問題幾乎能夠忽略,可是一旦項目複雜度上升,Webpack會有額外的性能損失須要咱們進行優化。javascript

經過前面內容的學習咱們能夠知道Webpack主要幹下面這些事情:css

  1. 經過entry指定的入口腳本進行依賴解析。
  2. 找到文件後經過配置的loader對其進行處理。

所以,咱們能夠從這方面入手進行優化,減小Webpack搜索文件的範圍,減小沒必要要的處理。java

loader配置

在以前的內容中介紹過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文件
      }
    ]
  }
};

resolve.extensions配置

導入未添加擴展名的模塊時,Webpack會經過resolve.extensions後綴去檢查文件是否存在。因爲resolve.extensions是一個數組,若是數組項比較多,正確的後綴放置得越靠後,Webpack嘗試次數就會越多,影響到性能。react

所以配置resolve.extensions時須要遵照如下規則:webpack

  • 儘可能減小後綴列表,不要將不可能存在的文件後綴配置進來
  • 出現頻率越高的後綴儘可能寫到前面,好比能夠將.js寫在第一個
  • 業務代碼中導入模塊時,能夠手動加上後綴導入,省去Webpack查找過程

module.noParse配置

module.noParse能夠告訴Webpack忽略未採用模塊系統文件的處理,能夠有效地提升性能。好比常見的jQuery很是大,又沒有采用模塊系統,讓Webpack解析這類型文件徹底是浪費性能。web

所以咱們能夠配置以下的module.noParse:npm

module.exports = {
  module:{
      noParse:[/jQuery/]
  }
};

IgnorePlugin

在導入模塊時,IgnorePlugin能夠忽略指定模塊的生成。好比moment.js在導入時會自動導入本地化文件,通常狀況下幾乎不使用並且又比較大,此時能夠經過IgnorePlugin忽略對本地化文件的生成,減少文件大小。json

module.exports = {
  plugins:[
    new webpack.IgnorePlugin(/\.\/local/, /moment/)
  ]
};

DllPlugin

使用過Windows操做系統的讀者應該會常常看到以.dll擴展名的文件,這些文件叫作動態連接庫,包含了其餘程序或動態連接庫的函數和數據。數組

Webpack的DllPlugin的思想是相似的,先將公共模塊打包爲獨立的Dll模塊,而後在業務代碼中直接引用這些模塊。採用DllPlugin以後會大大提高Webpack構建速度,緣由在於,包含大量複用模塊的動態連接庫只須要編譯一次,以後的構建中會直接引用這些構建好的模塊。

在Webpack中使用動態連接庫有如下兩個步驟:

  1. 經過webpack.DllPlugin插件打包出Dll庫
  2. 經過webpack.DllReferencePlugin引用打包好的Dll庫

下面以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須要先構建,不然應用將構建失敗

HappyPack

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

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須要刷新頁面才能加載),這樣有如下優點:

  • 保留應用狀態,好比使用Vue/React時若是使用LiveReload,組件狀態所有丟失,而HMR不會
  • 只更新變動的內容,節省開發時間

使用如下配置便可打開內置的HMR功能:

const webpack = require('webpack');

module.exports = {
    devServer: {
    hot: true, // 啓用熱加載
    contentBase: './dist',
  },
  plugins:[
        new webpack.NamedModulesPlugin(), // 打印更新的模塊路徑
    new webpack.HotModuleReplacementPlugin() // 熱更新插件
  ]
};

小結

本文咱們對Webpack4最經常使用的性能優化技術進行了學習,這些優化方法對業務代碼的侵入性很是小(只有按需加載優化會要求使用import()函數進行加載),在實際的開發中,能夠結合這些技術進行鍼對性的優化,好比開發時編譯慢,可能就須要使用HappyPack插件進行多進程編譯以加快編譯速度等等。

0.jpeg

相關文章
相關標籤/搜索