preface

Summary of their own performance optimization and webpack optimization. The current article describes Webpack, and the performance before Webpack will be summarized in the future.

The overall brain map is as follows:

Primary analysis: Use stats built into WebPack

Use stats in package.json

"Scripts ": {"stats": "webpack --json > stats.json"}, NPM run stats to produce the stas.json file, which contains the build statisticsCopy the code

Speed analysis: use speed-measure-webpack-plugin

The built-in STAS analysis of Webpack is coarse and difficult to find problems in file size and construction speed. The speed-measure-webpack-plugin can be used to analyze the time consumption of each loader and plugin

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

const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
  plugins: [new MyPlugin(), new MyOtherPlugin()],
});
Copy the code

Volume analysis: Use Webpack-bundle-Analyzer to analyze volumes

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

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}
Copy the code

Performance improvement methods (for build speed and volume optimization)

Use older versions of WebPack and Node.js

When webpack4 first came out, compared to webpack3 on twitter, webpack4’s build time was reduced by 60-98%

Reasons for using WebPack4:

  1. V8 optimizations (for of instead of forEach, Map and set instead of Object, includes instead of indexOf)

  2. The default is to use the faster MD4 hash algorithm instead of MD5

  3. Webpacks AST can be passed directly from the Loader to the AST, reducing parsing time

  4. Use string methods instead of regular expressions

Multi-process, multi-instance: Parse builds

Options:

  1. Thread-loader (Official)
  2. parallel-webpack
  3. HappyPack

Use HappyPack to parse resources Every time WebPack parses a module, HappyPack assigns it and its dependencies to worker threads webpack-happyLoader-happyPlguin -happyThreadPool-happyThread [1…N] – HappyWorkerChannel[1…N] – HappyWorker[1..N] (HappyPack workflow)

Use thread-loader to parse resources

How it works: As with HappyPack, each time webPack parses a module, Thread-Loader assigns it and its dependencies to worker threads

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          'thread-loader',
          // your expensive loader (e.g babel-loader)
        ],
      },
    ],
  },
};
Copy the code

If you need to configure three-Loader, you can configure it in the form of configuration items

use: [ { loader: 'thread-loader', // loaders with equal options will share worker pools options: { // the number of spawned workers, defaults to (number of cpus - 1) or // fallback to 1 when require('os').cpus() is undefined workers: 2, // number of jobs a worker processes in parallel // defaults to 20 workerParallelJobs: 50, // additional node.js arguments workerNodeArgs: ['--max-old-space-size=1024'], // Allow to respawn a dead worker pool // respawning slows down the entire compilation // and should be set to false for  development poolRespawn: false, // timeout for killing the worker processes when idle // defaults to 500 (ms) // can be set to Infinity for watching builds to keep workers alive poolTimeout: In 2000, // number of jobs the poll distributes to the workers // defaults to 200 // decrease of less efficient but more fair distribution poolParallelJobs: 50, // name of the pool // can be used to create different pools with elsewise identical options name: 'my-pool', }, }, // your expensive loader (e.g babel-loader) ];Copy the code

Multi-process, multi-instance: parallel compression

Method 1: Use the parallel ugliffe -plugin

Uglifyjs-webpack-plugin enables parallel (recommended before WebPack 4.0)

Terser-webpack-plugin enables parallel (recommended)

module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: True, // parallel defaults to 2 times the number of cpus in the current computer environment minus 1}),],},};Copy the code

If you are using WebPack V5 or above, you do not need to install this plugin. Webpack V5 comes with the latest Terser-webpack-plugin. If you use Webpack V4, you must install the version of Terser-webpack-Plugin V4

Further subcontracting: precompile resource modules

Method 1: use html-webpack-externals-plugin (e.g. React/react-dom base package via CDN)

Method 2: Use SplitChunksPlugin

Method 3: Use DLLPlugin for subcontracting, DIIReferencePlugin to Mainfest.json (official built-in plugin)

Generally, the webpack.dll. Js file is created to subcontract public base packages and service base packagesThen in webpack. Config. Js through webpack. DllReferenctPlugin for reference

Make full use of cache to improve secondary build speed

Objective: To improve the speed of secondary construction

  1. Babel-loader enables caching
  2. Terser-webpack-plugin enables caching
  3. Use cache-loader or hard-source-webpack-plugin

Narrow your Build goals

Purpose: Build as few modules as possible such as babel-loader that does not resolve node_modules

Reduce file search scope

  1. Optimize the resolve.modules configuration (reduce the module search hierarchy)
  2. Optimize the resolve.mainfields configuration
  3. Optimize the resolve.extensions configuration
  4. Use aliases wisely (mark yourself as a good alias)

Use Tree Shaking to erase useless JavaScript and CSS

About the tree shaking

Concept: A module may have multiple methods, and as long as one of them is used, the whole file will be sent to the bundle. Tree shaking is simply putting used methods into the bundle, while unused methods are erased during the Uglify phase.

Use: Webpack by default. Babelrc sets modules: false to production mode by default

Requirements: must be ES6 syntax, CJS methods do not support

Erase useless CSS

Use purgecss-Webpack-Plugin and mini-CSS-extract-Plugin together

const path = require('path'); const glob = require('glob') const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin'); const smp = new SpeedMeasureWebpackPlugin(); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const TerserPlugin = require("terser-webpack-plugin"); const webpack = require('webpack'); const PurgeCSSPlugin = require('purgecss-webpack-plugin') const PATHS = { src: Path. The join (__dirname)} module. Exports = SMP. Wrap ({/ / developer tools Don't need to develop a debugging devtool: false, / / development mode for code compression mode: 'development', // entry file entry: './index.js', output: {// output filename filename: 'bundle.js', // output file path: Path. The join (__dirname, '/'),}, the module: {rules: [{/ / regular matching suffix called CSS file test: / \. CSS $/, use: [MiniCssExtractPlugin.loader, 'css-loader'], } ] }, plugins: [ new MiniCssExtractPlugin(), new PurgeCSSPlugin({ paths: Glob. Sync (` ${PATHS. SRC} / * `, {nodir: true}), / / support only absolute path}),]});Copy the code

Use the dynamic Polyfill service

Use Webpack for image compression

Use image-Webpack-loader air tickets

Volume optimization strategy summary

  1. scope Hoisting
  2. Tree-shaking
  3. Separation of common resources
  4. Image compression
  5. Dynamic polyfill