Overview of common build optimization for webpack s

Posted by utpal on Wed, 20 Nov 2019 22:08:25 +0100

brief introduction

Read "Shallow web pack" to summarize common web pack construction optimization strategies, you can improve the speed of project construction by the following means

More precise loader rules

Write the loader rules clearly

Just let the files that need to be processed go into the loader process as follows

    rules: [{
      // Regular as accurate as possible
      test: /\.js$/,
      // With caching, it compiles faster when the file is unchanged after caching (see Supplement 1 for cache lookup principles)
      use: ['babel-loader?cacheDirectory'],
      // Specify directories to process
      include: path.resolve(__dirname, 'src')
      // In theory, only include is sufficient, but in some cases you can use this to exclude files that do not need to be processed
      // exclude: []
    }]

Find directories more accurately

Set Find Path to Precise

Theoretically, the third-party dependencies of our projects should all be under the node_modules of our own projects, so we can set the lookup directory to reduce the default lookup of nodes (see Supplement 2 for the default lookup method)

module.exports = {
    resolve: {
        // Specify the node_modules directory under the current directory
        modules: [path.resolve(__dirname, 'node_modules')]
    }
}

More precise extensions

Try to put more types of files first

Writing code in general, we are used to writing file names directly instead of extensions, so parsing is done according to the following properties

module.exports = {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
}

Default value

extensions: [".js", ".json"]

Pre-compile large modules using dynamic link libraries

Compile large modules ahead of time using dynamic link libraries

See Supplement 3 for principles

Create a new file, webpack_dll.config.js, as follows

const path = require('path');
const webpack = require('webpack');

// Place the reused large modules here so that you don't need to recompile them every time
const vendors = [
  'react',
  'react-dom',
  'lodash'
];

module.exports = {
  mode: 'development',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].js',
    library: '[name]',
  },
  entry: {
    vendors,
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve(__dirname, './dist/manifest.json'),
      name: '[name]',
    }),
  ],
};

Execute webpack --config webpack_dll.config.js for the first compilation (if a newer version needs to be compiled again)

Then introduce manifest.json into your webpack configuration file

  plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./dist/manifest.json')
    })
  ],

Multiprocessing Files

Using HappyPack to handle multiple loader compilation tasks simultaneously

To function as a multi-core CPU computer, use HappyPack to distribute tasks to multiple sub-processes and execute them concurrently

const path = require('path');
const HappyPack = require('happypack');
// Share 5 process pools
const happyThreadPool = HappyPack.ThreadPool({ size: 5 });

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    // noParse: [/react\.production\.min\.js$/],
    rules: [{
      test: /\.js$/,
      // And the following plugin id until happypack finds it
      use: ['happypack/loader?id=babel'],
      include: path.resolve(__dirname, 'src')
    }]
  },
  plugins: [
    // Plugins can instantiate multiple
    new HappyPack({
      // Corresponds to above
      id: 'babel',
      // The actual loader to use
      loaders: ['babel-loader?cacheDirectory'],
      // Default number of open processes
      threads: 3,
      // Allow happyPack to print logs
      verbose: true,
      // Number of shared processes, if you use more than one happyplugin, the official recommendation is to share the process pool
      threadPool: happyThreadPool
    })
  ],
};

Principle See Supplement 4

Multiprocess Compressed File

Compress files simultaneously using ParallelUglifyPlugin multi-process

ParallelUglifyPluginYesUglifyJSOn the basis of this, the capacity of multi-input and multi-output processing is added to speed up the compression speed

import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin';
 
module.exports = {
  plugins: [
    new ParallelUglifyPlugin({
      test,
      include,
      exclude,
      cacheDir,
      workerCount,
      sourceMap,
      uglifyJS: {
      },
      uglifyES: {
      }
    }),
  ],
};

Reduce listening files

Reduce listening files

Principle See Supplement 5

When we use the watch ability of webpack for file listening, a better way is to control the listening directory, as follows, excluding node_modules reduces listening on that directory, reduces compiling files that need to be looped, and improves checking speed

module.export = {
    watchOptions: {
        ignored: /node_modules/
    }
}

Other less important optimizations

More accurate mainFields

The default way to find this value is on the official website Click here

Looking at react and lodash, there's only one main, and es6 doesn't seem to be common at the moment, so this value may not be important right now

module.exports = {
    resolve: {
        mainFields: ['main']
    }
}

Third-party library mapping

Why is this unimportant? I find that index.js exported directly from react determines which code to use based on the environment, and visually does not require cyclical dependency processing

Dependencies allow you to use packaged code directly instead of Web packs to de-cycle dependencies

  resolve: {
    mainFields: ["main"],
    alias: {
      'react': path.resolve(__dirname, './node_modules/react/cjs/react.production.min.js')
    }
  }

devServer without inline mode

Principle See Supplement 6

By default, the application enables inline mode.This means that a script that handles real-time overloading is inserted into your bundle and the build message will appear in the browser console.

When using inline mode, devServer injects an overloaded piece of script code into each Chunk, but it only needs one page, so if there are too many Chunks, inline can be set to false

module.export = {
    devServer: {
        inline: false
    }
}

supplement

Supplementary 1-cacheDirectory Principle

When the cache directory is set, the specified directory will be used to cache the results of the loader's execution.Subsequent webpack builds will attempt to read the cache to avoid the high-performance, potentially expensive Babel recompiling process that can occur at each execution.If a null value (loader:'babel-loader? cacheDirectory') or true (loader: babel-loader?cacheDirectory=true) is set, the loader will use the default cache directory node_modules/.cache/babel-loader, and if the node_modules directory is not found in any root directory, the downgrade will fall back to the default temporary file directory of the operating system.

Supplement default 2-node lookup

  1. Find the node_modules directory in the current directory to see if there is a match, and if so, hit the file
  2. Find the node_modules under the parent directory, if any, hit the file
  3. Follow this rule and search all the way to the parent directory until you reach the node_modules under the root directory

Supplementary 3-Dynamic Link Library Ideas

Modules that can be reused in a large number of projects only need to be compiled once, and modules contained in a passive dynamic link library will not be recompiled during subsequent builds, but will use the code in the dynamic link library directly.(Note: If you upgrade a dependent module version, you will need to recompile the dynamic link library)

Supplementary 4-HappyPack Principle

In the construction of webpack, a large number of loader conversion operations are required, which is time consuming. Because nodejs are single-threaded, if you want to make better use of the multi-core capabilities of the cpu, you can start multiple processes and process the files at the same time. You can see that in the configuration file, we give the files to happypack-loader to process each time, and happypack to schedule the processing of the files (happypack)Which loaders to use for processing is known by id)

Supplement 5-File Listening Principles

The webpack triggers from the entry, puts all the dependencies into a list, modifies the contents of the file each time, goes back and traverses the entire list to see if there is a change in editing time, and compiles if there is one

Supplement 6-Automatic Refresh Principle

  • Inject proxy client code into the page to be developed and refresh the entire page through the proxy client (default)
  • Put the web page you want to develop into an iframe and refresh it to see the refresh effect

Topics: Javascript Webpack React JSON less