1. Primary analysis: Use Stats built into WebPack

Stats Builds statistics

// package.json{..."scripts": {
    	"build:stats": "webpack --env production --json > stats.json". }... }Copy the code

In the nodejs

const webpack = require('webpack');
const prodConfig = require('.. /.. /compile/webpack.prod.config');

webpack(prodConfig, (err, stats) = > {
  if (err) {
    console.log(err);
    process.exit(2);
  }
  if(stats.hasErrors()) {
  	return console.error(stats.toString('errors-only'));
  }
  console.log(stats);
})
Copy the code

Disadvantages: the granularity is too thick to see the problem.

2. Speed analysis: use speed-measure-webpack-plugin

Analyze the total packaging time as well as the execution time of each loader and plug-in.

  1. NPM install speed-measure-webpack-plugin -d
  2. Introduced in webpack.config.js
// webpack.config.js
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const sm= = new SpeedMeasurePlugin();
// Wrap the WebPack configuration object with sm.wrap()
const webpackConfig = sm.wrap({
	entry: './src/index.js'.plugins: [...]. });module.exports = webpackConfig;
Copy the code
  1. Build: NPM run build

3. Volume analysis: Use webpack-bundle-Analyzer

Once the build is complete, the size is displayed on port 8888, so you can analyze the size of the dependent third-party module files and the size of the components in the business code.

  1. Install: NPM I webpack-bundle-Analyzer -d
  2. Introduced in webpack.config.js
// webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
	...
    plugins:[
    	...
    	newBundleAnalyzerPlugin(); ] . }Copy the code
  1. Build: NPM run build

4. Use older versions of WebPack and NodeJS

Increase build speed and reduce build time.

  1. Reasons for using WebPack4 optimization:
  • V8 optimizations (for of instead of forEach, Map/Set instead of Object, includes instead of indexOf)
  • By default, the faster MD4 hash algorithm is used instead of MD5
  • The WebPack4 AST can be directly passed from the Loader to the AST, reducing the parsing time
  • Use string methods instead of regular expressions
  1. Higher-version Nodes take less time to parse

Execute the same js file as follows:

5. Multi-process multi-instance construction

Resource resolution parallel option

  1. HappyPack
  2. thread-loader
1. Use HappyPack to parse resources

How it works: Every time WebPack parses a module, HappyPack assigns it and its dependencies to the worker thread

  1. NPM install happypack -d
  2. Use:
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

module.exports = {
  ...
  module: {
    rules: [{test: /\.js$/.// pass the.js file processing to the HappyPack instance with id happyBabel
        loader: 'happypack/loader? id=happyBabel'.// Exclude files in node_modules
        exclude: /node_modules/}},],plugins: [
    new HappyPack({
        // Use the id to identify the class file that happypack processes
      id: 'happyBabel'.// How to handle the same usage as the loader configuration
      loaders: [{
        loader: 'babel-loader? cacheDirectory=true',}],// Share the process pool
      threadPool: happyThreadPool,
      // Allow HappyPack to output logs
      verbose: true,}})]Copy the code
HappyPack parameters
  • Id: String, which uses a unique identifier ID to indicate that the current HappyPack is used to process a particular class of files.
  • Loaders: Array. The usage is the same as in webPack Loader configuration.
  • Threads: Number: opens several sub-processes to handle this type of file. The default Number is 3. The type must be an integer.
  • Verbose: Boolean, whether HappyPack is allowed to output logs. The default value is true.
  • ThreadPool: HappyThreadPool represents a shared process pool. That is, multiple HappyPack instances use subprocesses in the same shared process pool to process tasks to prevent excessive resource usage.

VerboseWhenProfiling: Boolean, turn on Webpack –profile and still expect HappyPack to produce output. Debug: Boolean Enables debug for troubleshooting. False by default.

HappyPack not very well maintained: HappyPack

2. Use thread-loader to parse resources

How it works: Each time WebPack parses a module, it and its dependencies are assigned to the worker thread

  1. Install thread-loader: NPM I thread-loader -d
  2. Use:
module: {
    rules: [{test: /\.js$/,
            include: path.resolve('src'),
            use: [{loader: 'thread-loader'.// Loaders with the same configuration share a worker pool (worker pool)
                    options: {
                      // The number of workers generated, by default, is the number of CPU cores
                      workers: 2.// The number of concurrent tasks in a worker process
                      // The default is 20
                      workerParallelJobs: 50.// Additional Node.js parameters
                      workerNodeArgs: ['--max-old-space-size'.'1024'].// Delete worker processes when idle
                      // the default is 500ms
                      // It can be set to infinity to keep the worker alive in watch mode (--watch)
                      poolTimeout: 2000.// The number of jobs assigned to the worker by the pool
                      // The default is 200
                      // Lowering this number will reduce overall efficiency, but will improve work distribution more evenly
                      poolParallelJobs: 50.// Pool name
                      // You can change the name to create a pool with the same other options.
                      name: "my-pool"}},'babel-loader']]}},Copy the code

Multi-process/multi-instance parallel compression

  1. Parallel compression using the parallel-Ugliffe -plugin
  2. Use uglifyjs-webpack-plugin to enable the PARALLEL parameter
  3. Use the terser-webpack-plugin to turn on the PARALLEL parameter

6. Precompile the resource module

DLLPlugin is used for subcontracting and DllReferencePligin references manifest to improve packaging speed.

Use the DLLPlugin for the subcontracting step
  1. Create a configuration file, webpack.dll.config.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    vendor: [
      'react'.'react-dom'],},output: {
    filename: '[name]_[chunkhash].dll.js'.path: path.join(__dirname, 'build/library'),
    library: '[name]',},plugins: [
    new webpack.DllPlugin({
      name: '[name]_[hash]'.path: path.join(__dirname, 'build/library/[name].json')]}});Copy the code
  1. Add DLL commands to package.json
// package.json{...scripts: {..."dll": "webpack --config webpack.dll.config.js"}... }Copy the code
  1. Running the NPM Run DLL generates a build/library folder containing two files

The packaged vendor.js is a self-executing function that returns the function __webpack_require__ and assigns the vendor variable. Third-party modules are stored in closures. When an external call to vendor(ID) is made, __webpack_require__(id) is executed to retrieve the third-party module.

  1. Import build/library JSON files in webpack.config.js plugins
const webpack = require('webpack');

module.exports = {
	...
    plugins: [
    	new webpack.DllReferencePlugin({
            manifest: require('./build/library/vendor.json')})],... };Copy the code

Comparison of packing speed before and after subcontracting using DLL:

DLL process
  1. Vendor. json and vendor.js are generated by dllPlugin. Vendor. js returns a load function named vendor(configurable name) and stores the module in memory through closure. Note that vendor is a global variable.
  2. Webpack uses DllReferencePlugin to analyze which third-party modules are used in the business code during packaging, and which modules do not need to be packaged into the business code, but obtained from Vendor.js.
  3. Modules obtained from vendor are introduced by calling the global function Vendor (ID).

7. Make use of cache 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

8. Narrow your build goals

Build as few modules as possible

  • Babel-loader does not parse node_modules
module.exports = {
	module: {
    	rules: [{test: /\.js$/,
                loader: 'babel-loader'.exclude: 'node_modules'}}};Copy the code
  • Optimize the resolve.modules configuration to reduce the level of module search
  • Optimize the resolve.mainfields configuration
  • Optimize the resolve.extensions configuration
  • Use Aliases wisely
resolve: {
    extensions: [' '.'.js'.'.vue'.'.json'].alias: {
        'src': path.resolve(__dirname, '.. /src'),
        'components': path.resolve(__dirname, '.. /src/components'),
        'webview': path.resolve(__dirname, '.. /src/webview'),
        'lib': path.resolve(__dirname, '.. /src/lib'),}}Copy the code

9. Tree shaking Useless CSS

Use purgecss-webpack-plugin and mini-CSS-extract-plugin to remove unnecessary CSS purgecss-webpack-plugin usage

10. Use Webpack for image compression

Use the image – webpack – loader

11. Use dynamic Polyfill

Using the Polyfill service, it identifies the User Agent and issues different Polyfills.

According to the official services provided by Polyfill. IO