Reduce Webpack packaging time

Posted by kycan on Fri, 11 Feb 2022 11:51:46 +0100

1.1 optimize Loader

For the Loader, Babel must bear the brunt of affecting the packaging efficiency. Because Babel will convert the code into string to generate AST, then continue to transform the AST, and finally generate new code. The larger the project is, the more code is converted, and the lower the efficiency is. Of course, we have a way to optimize it.

First, we can optimize the file search scope of Loader

module.exports = {
  module: {
    rules: [
      {
        // babel is used only for js files
        test: /\.js$/,
        loader: 'babel-loader',//It can be modified as loader: 'Babel loader? Cachedirectory = true 'to cache
        // Find only under src folder
        include: [resolve('src')],
        // Will not find the path
        exclude: /node_modules/
      }
    ]
  }
}

For Babel, we definitely want to work only on JS code, and then node_ The code used in modules is compiled, so we don't need to deal with it again.
Of course, this is not enough. We can also cache the files compiled by Babel. Next time, we only need to compile the changed code files, which can greatly speed up the packaging time

1.2 HappyPack

Due to the single thread operation of Node, Webpack is also single thread in the packaging process. Especially when executing Loader, there are many tasks of long-time compilation, which will lead to waiting.

HappyPack can convert the synchronous execution of Loader into parallel, which can make full use of system resources to speed up the packaging efficiency

module: {
  loaders: [
    {
      test: /\.js$/,
      include: [resolve('src')],
      exclude: /node_modules/,
      // The content after id corresponds to the following
      loader: 'happypack/loader?id=happybabel'
    }
  ]
},
plugins: [
  new HappyPack({
    id: 'happybabel',
    loaders: ['babel-loader?cacheDirectory'],
    // Open 4 threads
    threads: 4
  })
]

1.3 DllPlugin

DllPlugin can package specific class libraries in advance and then introduce them. This method can greatly reduce the number of times to package the class library. Only when the class library is updated, it needs to be repackaged, and it also realizes the optimization scheme of separating the public code into separate files.

// Separate configuration in one file
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    // Class libraries that want to be uniformly packaged
    vendor: ['react']
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].dll.js',
    library: '[name]-[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      // name must match output Library consistent
      name: '[name]-[hash]',
      // This attribute needs to be consistent with that in DllReferencePlugin
      context: __dirname,
      path: path.join(__dirname, 'dist', '[name]-manifest.json')
    })
  ]
}

Then we need to execute the configuration file to generate the dependency file. Next, we need to use DllReferencePlugin to introduce the dependency file into the project

// webpack.conf.js
module.exports = {
  // ... Omit other configurations
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      // manifest is the json file packaged before
      manifest: require('./dist/vendor-manifest.json'),
    })
  ]
}

1.4 code compression

In webpack 3, we usually use UglifyJS to compress code, but this is run by single thread. In order to speed up efficiency, we can use webpack parallel uglify plugin to run UglifyJS in parallel, so as to improve efficiency.

In webpack 4, we don't need the above operations. We just need to set the mode to production to enable the above functions by default. Code compression is also a necessary performance optimization scheme. Of course, we can not only compress JS code, but also HTML and CSS code. In the process of compressing JS code, we can also implement it through configuration, such as deleting console Log is the function of such code.

1.5 some small optimization points

  • resolve.extensions: used to indicate the list of file suffixes. The default search order is ['. JS','. JSON ']. If you do not add suffixes to your imported files, you will find files in this order. We should try to reduce the length of suffix list as much as possible, and then put the suffixes with high frequency first
  • resolve.alias: you can map a path by alias, which can make Webpack find the path faster
  • module.noParse: if you are sure that there are no other dependencies under a file, you can use this attribute to make Webpack not scan the file. This method is very helpful for large class libraries

Topics: node.js Front-end Webpack