十大webpack優化插件

隨着前端項目日漸的複雜,咱們平常開發中使用的構建工具也不斷演變、進化,既要知足咱們開發時的便利,還要充當構建時各類資源優化、自動打包、自動測試的角色。目前,最受歡迎的當數webpack。知足複雜的功能的同時一定帶來必定的使用成本,繁雜的配置,構建的性能也成了咱們使用webpack時須要考慮的問題。javascript

在筆者看來,webpack有四大核心的配置:css

一、入口html

二、出口前端

三、loadervue

四、pluginsjava

這四個配置,缺乏任何同樣,都不能知足咱們平時構建的複雜的需求。插件更是打包優化的核心配置。本文主要從插件的角度,對webpack打包和構建作一些優化。node

一、SplitChunks

這是webpack4升級的最重要的配置之一,它的做用是將動態加載的模塊打包成common chunks,它的做用至關於以前的commonChunksPlugin,可是比以前的插件功能更增強大。由於幾乎全部的項目打包都必備,因此webpack直接內置爲一個配置,配置在optimization這個選項下。下面咱們看下默認的配置:react

splitChunks: {
  chunks: 'async', // 分割異步模塊
  minSize: 30000, // 分割的文件最小大小
  maxSize: 0,     
  minChunks: 1, // 引用次數
  maxAsyncRequests: 5, // 最大異步請求數
  maxInitialRequests: 3, // 最大初始化請求數
  automaticNameDelimiter: '~', // 抽離的命名分隔符
  automaticNameMaxLength: 30, // 名字最大長度
  name: true,
  cacheGroups: { // 緩存組
    vendors: { // 先抽離第三方庫
      test: /[\\/]node_modules[\\/]/,
      priority: -10
    },
    default: { 
      minChunks: 2,
      priority: -20, // 優先級
      reuseExistingChunk: true
    }
  }
}
複製代碼

使用cacheGroups咱們能夠任意定製咱們想打包的common chunk,還能夠控制每一個chunk的大小,默認配置已經知足大多數開發的需求。webpack

二、DllPlugin && DllReferencePlugin

接下來要介紹的是DllPluginDllReferencePlugin的結合,這兩個插件必須配合使用才能發揮其巨大的做用,主要的做用是提高你開發時的構建速度。它的思路是這樣的,首先使用DllPlugin預編譯全部你項目中幾乎不會變化的外部模塊,而後在構建以前,把這些資源打包成一個vendor,以後直接在項目中使用,每次修改文件這些資源將不用從新打包,下面咱們看下配置,單首創建webpack.dll.js:git

const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');

module.exports = {
    entry:['vue','vue-router', 'vuex'],
    mode:'production',
    output:{
        filename:'vue.dll.js',
        path:path.resolve(__dirname,'dll'),
        library:'vue'
    },
    plugins:[
        new DllPlugin({
            name:'vue',
            path:path.resolve(__dirname,'dll/manifest.json')
        })
    ]
}
複製代碼

執行webpack --config webpack.dll.js命令 ,咱們將看到生成的dll目錄下有兩個文件:vue.dll.js和manifest.json ,manifest.json中保存了咱們打包到vue.dll.js中的模塊路徑,而後接下來咱們須要使用DllReferencePlugin插件經過manifest.json文件去找咱們須要的依賴:

const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
// 構建時會引用動態連接庫的內容
new DllReferencePlugin({
  manifest:path.resolve(__dirname,'dll/manifest.json')
}),
// 經過插件將vue.dll.js自動引入到咱們的index.html中
new AddAssetHtmlWebpackPlugin(
  { filepath: path.resolve(__dirname,'dll/vue.dll.js') }
)
複製代碼

到此,咱們完成了兩個插件的使用。

三、image-webpack-loader

這裏是本文的一個特例,image-webpack-loader它不是一個插件,可是它的做用十分強大,像是插件的角色。前端開發中,咱們少不了對圖片資源的使用,那麼在繁雜的各類圖片資源中,咱們須要一個工具對不一樣的圖片格式進行壓縮處理,這樣構建處理的圖片才能在尺寸上也符合咱們的指望。image-webpack-loader能夠對各類圖片格式進行必定的壓縮。話很少說直接看配置:

loader: "image-webpack-loader",
options: {
  mozjpeg: {
    progressive: true,
    quality: 65
  },
  // optipng.enabled: false will disable optipng
  optipng: {
    enabled: false,
  },
  pngquant: {
    quality: [0.90, 0.95],
    speed: 4
  },
  gifsicle: {
    interlaced: false,
  },
  // the webp option will enable WEBP
  webp: {
    quality: 75
  }
}
複製代碼

它可讓咱們在保證圖片清晰度的狀況下,對圖片進行壓縮,能夠自行根據項目的須要配置,圖片壓縮就是這麼簡單。

四、MiniCssExtractPlugin

這是一個既包含loader又能夠做爲插件的插件,它的做用是將css單獨打包成一個文件。webpack通常經常使用的是經過style-loader將css經過style標籤插入到html中,可是這樣不利於緩存,也影響js的加載。因此,咱們通常須要將一些css單獨打包出來。下面看插件的使用:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // all options are optional
      filename: '[name].css',
      chunkFilename: '[id].css',
      ignoreOrder: false, // Enable to remove warnings about conflicting order
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              // you can specify a publicPath here
              // by default it uses publicPath in webpackOptions.output
              publicPath: '../',
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};
複製代碼

相比於extract-text-webpack-plugin插件,它有一些優點:

  • 異步加載
  • 不會有重複的編譯,在性能上有提高
  • 使用也更加方便
  • 專門處理css資源

五、purgecss-webpack-plugin

有時候咱們參與開發的項目很大,參與的開發人員也不少,你們在開發的時候極可能寫了一些無用的樣式,或是由於需求變動忘記刪除。這時候咱們就須要一個插件:purgecss-webpack-plugin,幫助咱們自動清理掉一些無用的樣式:

const glob = require('glob');
const PurgecssPlugin = require('purgecss-webpack-plugin');

// 須要配合mini-css-extract-plugin插件
{
  plugins: [
    new PurgecssPlugin({
      // 不匹配目錄,只匹配文件
    	paths: glob.sync(`${path.join(__dirname, "src")}/**/*`, { nodir: true }) 
		})
  ]
}

複製代碼

固然咱們須要配合glob庫使用,告訴插件須要匹配哪些目錄。咱們看一段代碼:

import './style.css'
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(<div>hello</div>,document.getElementById('root'));
複製代碼
// style.css
body{
    background: red
}

// 這個類的樣式是無用的,將會被清除
.class1{
    background: red
}
複製代碼

六、happypack

使用webpack對項目進行構建時,會對大量的文件進行處理,文件越多構建速度越慢。其中一個緣由就是運行在Node上的webpack是單線程的,它只能一個個任務排隊處理。使用happypack能夠將解析文件的任務分紅多個子進程併發執行,每一個子進程處理完再將結果返回給主進程,從而能大大提高webpack的構建項目速度。下面來看下happypack的使用方法:

首先將你想使用多進程處理的loader作一個修改:

const HappyPack = require('happypack');

module.exports = {
    ...
    module: {
        rules: [
            test: /\.js$/,
            // use: ['babel-loader?cacheDirectory'] 以前是使用這種方式直接使用 loader
            // 如今用下面的方式替換成 happypack/loader,並使用 id 指定建立的 HappyPack 插件
            use: ['happypack/loader?id=babel'],
            // 排除 node_modules 目錄下的文件
            exclude: /node_modules/
        ]
    }
}

複製代碼

而後在插件中配置happypack:

const HappyPack = require('happypack');

module.exports = {
    ...
    module: {
        rules: [
            test: /\.js$/,
            // use: ['babel-loader?cacheDirectory'] 以前是使用這種方式直接使用 loader
            // 如今用下面的方式替換成 happypack/loader,並使用 id 指定建立的 HappyPack 插件
            use: ['happypack/loader?id=babel'],
            // 排除 node_modules 目錄下的文件
            exclude: /node_modules/
        ]
    },
    plugins: [
        ...,
        new HappyPack({
            /* * 必須配置 */
            // id 標識符,要和 rules 中指定的 id 對應起來
            id: 'babel',
            // 須要使用的 loader,用法和 rules 中 Loader 配置同樣
            // 能夠直接是字符串,也能夠是對象形式
            loaders: ['babel-loader?cacheDirectory']
        })
    ]
}
複製代碼

這樣就完成了happypack的使用。happypack有不少配置項,詳細能夠查看happypack

七、hard-source-webpack-plugin

使用緩存來有優化性能在前端領域是一種很常見的手段,既然webpack每次都要構建大量的文件,是否是能夠經過一個插件對前一次的構建結果作一些緩存了?答案固然是能夠的,hard-source-webpack-plugin就是這樣一個webpack插件。既然是緩存,因此固然要第二次才能看到效果,第一次構建插件就會默認把緩存結果存到node_modules下的.cache目錄下,第二次構建的時候再取出緩存使用。它還能夠配置緩存目錄,緩存時間,緩存資源的最大尺寸等等。下面咱們看下它的一些配置和使用方法:

new HardSourceWebpackPlugin({
  // Either an absolute path or relative to webpack's options.context.
  cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
  // Either a string of object hash function given a webpack config.
  configHash: function(webpackConfig) {
    // node-object-hash on npm can be used to build this.
    return require('node-object-hash')({sort: false}).hash(webpackConfig);
  },
  // Either false, a string, an object, or a project hashing function.
  environmentHash: {
    root: process.cwd(),
    directories: [],
    files: ['package-lock.json', 'yarn.lock'],
  },
  // An object.
  info: {
    // 'none' or 'test'.
    mode: 'none',
    // 'debug', 'log', 'info', 'warn', or 'error'.
    level: 'debug',
  },
  // Clean up large, old caches automatically.
  cachePrune: {
    // Caches younger than `maxAge` are not considered for deletion. They must
    // be at least this (default: 2 days) old in milliseconds.
    maxAge: 2 * 24 * 60 * 60 * 1000,
    // All caches together must be larger than `sizeThreshold` before any
    // caches will be deleted. Together they must be at least this
    // (default: 50 MB) big in bytes.
    sizeThreshold: 50 * 1024 * 1024
  },
})
複製代碼

八、webpack-bundle-analyz

工欲善其事必先利其器,咱們想要對webpack構建或者構建的資源作一些優化,那咱們首先得知道,優化的方向在哪?不少的優化建議可能只是針對某些項目有效,不必定適合你的項目。因此,咱們須要藉助一些工具,經過工具產出的數據來指導咱們進行構建的優化。webpack-bundle-analyz,這個插件可讓咱們瞭解到構建出的文件的尺寸大小、依賴哪些模塊等等,下面是一張效果圖:

webpack bundle analyzer zoomable treemap

經過圖咱們能夠知道:

  • 可以看到輸出的bundle依賴哪些模塊
  • 找出你的bundle中尺寸最大的模塊
  • 找出是否是由於失誤而引多餘的依賴模塊
  • 知道怎麼去優化你的bundle

它的使用也很簡單:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}
複製代碼

固然它有一些的具體參數能夠配置,詳情參考webpack-bundle-analyz

九、speed-measure-webpack-plugin

上面咱們介紹了一個能夠對webpack構建出的bundle進行分析的插件,從而找到合適的一些優化途徑。這裏要介紹的是另外一個測量插件--speed-measure-webpack-plugin,它的做用是測量webpack構建過程當中使用的loader和各插件所花費的時間,從而讓咱們清楚地知道webpack構建的時間主要花在什麼地方。下面是一張使用這個插件生成的效果圖:

Preview of Speed Measure Plugin's output

經過圖,咱們能夠很清楚地瞭解到每一個插件和loader所花費的時間。咱們來看下它的使用:

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

module.export = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
})
複製代碼

使用也很是簡單,若是你還想了解更多的配置項,能夠查看SpeedMeasurePlugin

十、preload-webpack-plugin

這個插件的做用是向html中注入<link rel='preload|prefetch'> 標籤,從而到達優化頁面靜態資源預加載的功能,並且支持異步的chunk。此插件必須配合html-webpack-plugin插件使用,並且配置的時候緊跟其後,下面是一個簡單的配置:

const PreloadWebpackPlugin = require('preload-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = [
  plugins: [
  	new HtmlWebpackPlugin(),
  	new PreloadWebpackPlugin()
	]
]
複製代碼

使用以後的效果:

preloads-plugin-compressor

在vue-cli3中就內置了這個插件,默認幫你將資源優先級高的資源加上preload的功能。更多配置參考:preload-webpack-plugin

相關文章
相關標籤/搜索