current position:Home>Webpack learning notes series 06- Packaging Optimization

Webpack learning notes series 06- Packaging Optimization

2022-06-24 08:16:03CS Xiaoyao Sword Fairy

webpack Learning notes series 06- Package optimization

Write By CS Xiaoyao sword immortal

My home page : csxiaoyao.com

GitHub: github.com/csxiaoyaojianxian

Email: [email protected]

QQ: 1724338257

1. splitChunks Split code

1.1 Three splitting methods

webpack Three code splitting methods of :

  • many entry Entrance configuration
  • Use import() or require.ensure Dynamic load on demand
  • webpack4 Of splitChunks Configuration replaces the previous CommonsChunkPlugin

1.2 splitChunks The default configuration

splitChunks The default configuration corresponds to the second on-demand loading method mentioned above :

module.exports = {
    // ... 
    optimization: {
        splitChunks: {
            chunks: 'async', // initial|all|async( Default )
          	maxInitialRequests: 3, //  Initialize maximum number of files , Priority over  cacheGroup, by  1  Do not extract  initial common
          	maxAsyncRequests: 5, //  Maximum number of asynchronous requests loaded on demand , by  1  Do not extract public  chunk
            maxSize: 0, //  Maximum file size ,0 Don't limit 
          	minSize: 30000, //  Minimum file size , Default 30K,development  Next 10k, And  chunk  The number is inversely proportional to 
            minChunks: 1, //  Default  1, The modules to be extracted must be at least several  chunk  Cited in , The bigger the value is. , The smaller the extracted file 
            automaticNameDelimiter: '~', //  Package file name separator 
            name: true, //  Split file name , Default  true  Auto generate file name , If set to fixed string , Then all  chunk  Merge into one 
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/, //  Regular rule , If it matches, extract  chunk 
                    priority: -10 //  Cache group priority , When a module may belong to more than one  chunkGroup, Here's the priority  
                },
                default: {
                    minChunks: 2,
                    priority: -20, //  priority  
                    reuseExistingChunk: true //  If it's time to chunk Contains modules It's already another divided chunk in , So direct reference to what already exists c hunk, There will be no more  
                }
            }
        }
    }
};

except JavaScript, splitChunks Also suitable for use mini-css-extract-plugin The plug-in css To configure

1.2.1 chunks

Optional value :async( Default ) | initial | all( recommend ), For the following a.js and b.js

// a.js
import $ from 'jquery';
import react from 'react';
import( /* webpackChunkName: "a-lodash" */ 'lodash');

// b.js
import $ from 'jquery';
import( /* webpackChunkName: "b-react" */ 'react');
import( /* webpackChunkName: "b-lodash" */ 'lodash');

Three different configurations :

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
    mode: 'development',
    entry: {
        a: './a.js',
        b: './b.js'
    },
    plugins: [new BundleAnalyzerPlugin()],
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendors: {
                    chunks: 'async', // async|initial|all 
                    test: /[\\/]node_modules[\\/]/
                }
            }
        }
    }
};

async: Only the dynamically introduced code is split

  • jquery Pack them separately a.js and b.js
  • react Packed in a.js And dismantling venders~b-react.js
  • lodash Split into one venders~a-lodash.js

initial: Share and disassemble ( Dynamic introduction of certain split ), According to the threshold minChunks Configure split

  • jquery It is divided into vendors~a~b.js
  • react Split into vendors~a.js( Dynamic introduction ) and b-react.js( Magic notes ), Be careful : if minSize Set large , It will not be taken out alone vendors~a.js
  • lodash Split into one a-lodash.js( Magic notes )

all: recommend , stay initial Generate reusable code as much as possible , Such as initial Of react Split into one vendors~a~b-react.js

1.2.2 maxInitialRequests / maxAsyncRequests / maxSize / minSize

priority :maxInitialRequest / maxAsyncRequests < maxSize < minSize

maxInitialRequests: For each entry Maximum number of files initialized , Priority over cacheGroup, Therefore 1 Will not extract initial common

maxAsyncRequests: The maximum number of asynchronous requests per on-demand load , by 1 Do not extract public chunk

maxSize: Maximum file size ,0 Don't limit

minSize: Minimum file size , Default 30K,development Next 10k, And chunk The number is inversely proportional to

webpack Magic notes

import(/* webpackChunkName: "react" */ 'react'); // You can set the generated bundle name

Use webpack-bundle-analyzer Plug in to check the packaging

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { mode: 'production', entry: { main: './default/index.js' }, plugins: [new BundleAnalyzerPlugin()] };

1.3 cacheGroups Cache group

splitChunks The configuration items of are used for cacheGroup Upper , There are two defaults cacheGroup:vendors and default ( Last section splitChunks The default configuration ), Support to rewrite , It also supports setting to false (splitChunks Will fail )

cacheGroups All except for the previous section splitChunks The default configuration , Extra support test / priority / reuseExistingChunk

1.3.1 reuseExistingChunk

Whether to use the existing chunk

1.3.2 priority

The weight , If a module satisfies multiple cache group conditions , It is determined by weight

1.3.3 test

Cache group hit condition , The value is regular 、 Strings and functions

cacheGroups: {
    vendors: {
      	// test: /[\\/]node_modules[\\/]/,
        test(module, chunks) {
            //...
            return module.type === 'javascript/auto'; 
        },
        priority: -20
    }
}

2. Build speed optimization

influence webpack The main reasons for building speed are :

  • loader/plugin The building process of
  • Compression process

You can reduce the search process from 、 Multithreading 、 Precompile and Cache Multi angle optimization

2.1 Reduce the search process

  • resolve.alias: Skip the time-consuming recursive module resolution operation by alias
module.exports = {
    resolve: {
        //  Direct use of production environment  react.min.js
        alias: {
            react: path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
            '@lib': path.resolve(__dirname, './src/lib/')
        }
    }
};
  • resolve.extensions: Configure suffix order , Reduce speculation when importing modules
resolve.extensions = ['js', 'json']
  • module.noParse: Exclude modules that do not need to be resolved

In especial jQuery And other large libraries that do not adopt modular standards , But should pay attention to , Excluded files cannot contain importrequiredefine And so on .

  • rule: adopt testincludeexclude Control the search scope
rules: [{
    loader: 'babel-loader',
    test: /\.js$/, // test  Regular 
    exclude: [path.resolve(__dirname, './node_modules')], //  Exclude absolute paths  Array
    include: [path.resolve(__dirname, './src')] //  Find the absolute path  Array
}];

exclude priority > include / test, It is suggested to use more include Avoid using exclude.

2.2 Multithreading

Use thread-loader and HappyPack It can realize multi-threaded packaging for large projects .

thread-loader: take loader In a worker Running in pool , To achieve multithreaded build

module.exports = {
    module: {
        rules: [{
            test: /\.js$/,
            include: path.resolve('src'),
            use: [
            		'thread-loader', //  Need to be placed in other  loader  Before 
                //  Other high expenses  loader (e.g babel-loader)
            ]
        }]
    }
};

HappyPack: Accelerate code building through a multi process model , But the corresponding loader Support

const os = require('os');
const HappyPack = require('happypack');
//  according to  cpu  Number of thread pools created  
const happyThreadPool = HappyPack.ThreadPool({
    size: os.cpus().length
});
module.exports = {
    module: {
        rules: [{
            test: /\.js$/,
            use: 'happypack/loader?id=jsx'
        }, {
            test: /\.less$/,
            use: 'happypack/loader?id=styles'
        }]
    },
    plugins: [
        new HappyPack({
            id: 'jsx',
            threads: happyThreadPool,
            loaders: ['babel-loader']
        }),
        new HappyPack({
            id: 'styles',
            threads: 2, //  Number of custom threads  
            loaders: ['style-loader', 'css-loader', 'less-loader']
        })
    ]
};

2.3 DllPlugin precompile

Precompile and package some unchanged library files , Directly introduce... Into the business code . Need to be alone for dll File create a configuration file , adopt DLLPlugin The plug-in packages third-party dependencies into bundle file , And generate manifest.json file , In the project webpack Use in profile DllReferencePlugin Plug in resolution manifest.json, skip dll Packaging of dependencies contained in .

//  A separate  dll  Package configuration file  webpack.config.dll.js 
const webpack = require('webpack');
const vendors = ['react', 'react-dom']; //  Third party dependency Library  
module.exports = {
    mode: 'production',
    entry: {
        vendor: vendors //  The entry file for packaging public files is set to  vendor.js
    },
    output: {
        filename: '[name].[chunkhash].js',
        library: '[name]_[chunkhash]' //  take  verdor  As  library  export , And specify the global variable name  [name]_[chunkhash]
    },
    plugins: [
      	new webpack.DllPlugin({
            path: 'manifest.json', //  Set up  mainifest.json  route 
            name: '[name]_[chunkhash]',
            context: __dirname
    		})
    ]
};

perform webpack --config webpack.config.dll.js

//  Project profile  webpack.config.js 
const webpack = require('webpack');
module.exports = {
    output: {
        filename: '[name].[chunkhash].js'
    },
    entry: {
        app: './src/index.js'
    },
    plugins: [
      	new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./manifest.json') //  Import 
    		})
    ]
};

Be careful : After packaging html Will not actively introduce dll Of vendor.js file , Need to be handled manually .

2.4 cache cache

babel-loader It is often the most time-consuming part of the compilation process , Although the cacheDirectory Configure the specified cache directory , But the default is false close , Set to true The default cache directory is used node_modules/.cache/babel-loader

rules: [{
    test: /\.js$/,
    loader: 'babel-loader',
    options: {
        cacheDirectory: true
    },
    exclude: /node_modules/,
    include: [path.resolve('.src')]
}];

2.5 other

  • sourceMap Choose the right one devtool value
  • Switch faster loader
  • terser-webpack-plugin Enable multithreading and caching
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
    optimization: {
        minimizer: [new TerserPlugin({
            cache: true, //  Open the cache 
            parallel: true //  Multithreading 
        })]
    }
};

3. Tree-Shaking

ES6 Modules yes Tree-Shaking The basis of static analysis .Webpack Through analysis ES6 Introduction and use of modules , Remove unused import introduce ; Besides , Tools such as uglifyjs-webpack-plugin and terser-webpack-plugin To delete ( only mode=production Take effect ). The implementation of tree shaking needs to maintain good development habits :

  1. You have to use ES6 modular
  2. Introduce on demand , In especial UI frame
  3. Reduce side effects in your code ( Pure function )
// package.json
{
    "name": "tree-shaking-side-effect",
    "sideEffects": ["./src/utils.js"]
}

stay package.json in , In addition to sideEffects Specify files with side effects , If you can ensure that there are no side effects , You can set sideEffects: false No more side effects .

sign

copyright notice
author[CS Xiaoyao Sword Fairy],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/175/20210627163646703H.html

Random recommended