Why performance tuning

When using Webpack, if you do not pay attention to performance optimization, you may have performance problems, which will lead to a not very silky development experience. Performance problems are mainly slow compilation speed and large packaging volume, so performance optimization is mainly analyzed in these aspects. This article is mainly their usual work accumulation and reference to other people’s articles, and summarize, based on Webpack4 version.

Build analysis

Compile speed analysis

The first task of optimizing Webpack build speed is to know where to look. The speed-measure-webpack-plugin can measure the webpack build speed

SMP ⏱ General output time took 38.3 secs SMP ⏱ Plugins HtmlWebpackPlugin took 1.31 secs CopyPlugin took 0.016 secs OptimizeCssAssetsWebpackPlugin took 0.002 secs ContextReplacementPlugin took 0.001 secs MiniCssExtractPlugin took 0 secs DefinePlugin took 0 secs SMP ⏱ Loaders [email protected]@babel-loader took 29.98 secs module count = 1503 _babel - [email protected] @ Babel - loader, And [email protected]@eslint-loader took 18.74 secs module count = 86 [email protected] @CSS-loader, And [email protected]@less-loader took 16.45 secs module count = 64 modules with no loaders took 2.24 secs module count = 7 [email protected]@file-loader took 1.03 secs module count = 17 [email protected]@style-loader, And _css - [email protected] @ CSS - loader, And [email protected]@less-loader took 0.102 secs module count = 64 [email protected]@html-webpack-plugin took 0.021 secs Module count = 1Copy the code

It achieved an impressive 38.3 seconds, which was a bit imprecise, but very slow. Babel-loader, ESlint-loader, CSS-loader, and less-loader occupy the majority.

const webpackBase = require('./webpack.base.conf'); const path = require('path'); const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin'); const smp = new SpeedMeasureWebpackPlugin(); Module.exports = smp.wrap({// set source code display mode devtool: 'eval-source-map', mode: 'development', entry: {app: ['./src/index.jsx'] }, output: { path: path.resolve(__dirname, 'dist'), filename: 'index.js' }, resolve: webpackBase.resolve, module: webpackBase.module, stats: webpackBase.stats, optimization: webpackBase.optimization, plugins: [ webpackBase.plugins.html, webpackBase.plugins.miniCssExtract, webpackBase.plugins.optimizeCssAssets, // webpackBase.plugins.progressBarPlugin, webpackBase.plugins.ContextReplacementPlugin, webpackBase.plugins.DefinePlugin, // webpackBase.plugins.AntdDayjsWebpackPlugin, webpackBase.plugins.CopyPlugin // webpackBase.plugins.HotModuleReplacementPlugin ], devServer: webpackBase.devServer, watchOptions: webpackBase.watchOptions, externals: webpackBase.externals });Copy the code

Package volume analysis

The webpack-bundle-Analyzer plugin can generate a build volume report after a Webpack build is complete. With a visual page, you can intuitively know the specific volume occupied in the build.

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: bundleAnalyzer: new BundleAnalyzerPlugin({ analyzerPort: 8081 })],
};
Copy the code

The renderings are as follows:

One obvious problem is Ant Design, TRTC, Mobx libraries.

Packing volume is as follows:

How to optimize

Narrow your Build goals

  • To optimize theresolve.modulesConfiguration (reduces module search levels and unnecessary compilation work)
  • To optimize theresolve.extensionsconfiguration
  • Increase the cache
const path = require('path'); Module. exports = {resolve: {// Automatically resolve extensions: ['.js', '.jsx', '.css', '.less', '.json'], alias: {// create an alias for import or require to ensure module introduction becomes simpler 'react': Path. The resolve (__dirname, '. / node_modules/react/dist/react. Min. Js')}, / / when the NPM package import module, This option will determine which fields are used to import modules in' package.json '// The default is browser -> module -> main mainFields: ['main']}, module: {rules: [{/ / exclude node_modules module test: / \. (js | JSX) $/, exclude: / node_modules /, / / open the buffer loader: 'babel-loader?cacheDirectory=true' } ] } };Copy the code

Enable multiple processes by using thread-loader

Thread-loader will run your loader in a pool of workers, each of which is a separate node.js process with a 600ms limit. Data exchange across processes is also limited. Use it in a high-overhead loader; otherwise, the effect is poor.

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

Use the hard – source – webpack – the plugin

In Webpack4, the hard-source-webpack-plugin is a better alternative to DLLS.

Hard-source-webpack-plugin is a plug-in for Webpack that provides an intermediate caching step for modules. To see the results, you need to run Webpack twice with this plug-in: the first build will take a normal amount of time. The second build will be significantly faster (approximately 90% faster build speed). However, the plugin has not been updated for a long time and is not recommended.

Remove eslint – loader

Since I’m using eslint-Loader in my project, I can remove it if PREcommit is configured.

Exclude related packages via externals

Webpack

Module.exports = {externals: {react: 'react ', 'react-dom': externals: {react: 'react ', 'react-dom': 'ReactDOM', 'trtc-js-sdk': 'TRTC', bizcharts: 'BizCharts', antd: 'antd', mobx: 'mobx', 'mobx-react': 'mobxReact' } };Copy the code

index.html

<! DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" /> <meta name="baidu-site-verification" content="ptk9VJudKz" /> <link rel="stylesheet" A href = "https://xxx/antd.min3.26.20.css" / > < title > webpack < / title > < script type = "text/javascript" SRC = "https://xxx/17.0.0react.production.min.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/17.0.0react-dom.production.min.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/BizCharts3.5.8.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/trtc4.6.7.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/moment2.29.1.min.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/moment2.29.1zh-cn.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/polyfill.min7.8.0.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/antd.min3.26.20.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/mobx.umd.min5.13.1.js" > < / script > < script type = "text/javascript" SRC = "https://xxx/mobx-react.index.min5.4.4.js" > < / script > < / head > < body > < div id = "root" > < / div > < / body > < / HTML >Copy the code

JS compressed

Starting with Webpack4, terser is used by default to compress output in production. Terser is an ES2015 + compatible JavaScript compressor. Compared to UglifyJS, an early standard for many projects, it is a future-oriented choice. There was a branch of UglifyJS, uglip-es, but since it was no longer maintained, a separate branch was born from this branch, terser.

const TerserPlugin = require('terser-webpack-plugin'); Module. Exports = {optimization: {minimizer: [/ js/compression new TerserPlugin ({test: / \. (JSX | js) $/, extractComments: true, parallel: true, cache: true }) ] }, };Copy the code

CSS compression

After Webpack 4.0, it is recommended to use the mini-CSs-extract-plugin to package CSS files.

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /\.(css|less)$/,
                use: [MiniCssExtractPlugin.loader]
            }
        ]
    },
};
Copy the code

FAQ

Ant Design could not load

Make sure that Moment and Polyfill are loaded before Ant Design

MobX cannot load

MobX introduced the mobx.umd.min.js library, which mobx-React needed to introduce

package.json

{" name ":" webpack ", "version" : "1.0.0", "private" : true, "main" : "index. Js", "dependencies" : {" antd ": "^ 3.26.20", "Babel - eslint" : "^ 10.0.3", "Babel - loader" : "^ 8.0.0", "Babel - plugin - import" : "^ 1.13.0", "Babel - plugin - react - CSS - modules" : "^ 5.2.6", "bizcharts" : "^ 3.5.8", "China - division" : "^ 2.3.1," "compression will webpack - plugin" : "^ 3.0.1", "copy - webpack - plugin" : "^ 5.1.1", "CSS - loader" : "^ 3.2.0", "eslint" : "^ 6.8.0 eslint - config -", "prettier" : "^ 6.11.0", "eslint - config - standard" : "^ 14.1.0", "eslint - loader" : "^ 3.0.4 eslint - plugin -", "import" : "^ 2.20.0", "eslint - plugin - promise" : "^ 2", "eslint - plugin - react" : "^ 7.17.0 eslint - plugin -", "standard" : "^ 4.0.1", "HTML - webpack - plugin" : "^ 3.2.0", "less" : "^ 3.8.1", "less - loader" : "^ 5.0.0 lint -", "staged" : "^ 10.0.8", "mini - CSS - extract - the plugin" : "^ 0.8.0", "mobx" : "^ 5.13.1", "mobx - react" : "^ 5.4.4," "optimize - CSS - assets - webpack - plugin" : "^ 5.0.1", the "pre - commit" : "^ 1.2.2", "progress - bar - webpack - plugin" : "^ 1.12.1" and "react", "^ 17.0.0", "the react - dom" : "^ 17.0.0", "speed - measure - webpack - plugin" : "^ 1.3.1", "style - loader" : "^ 1.2.1 terser - webpack -", "plugins" : "^ 2.2.1", "the TRTC - js - SDK" : "^ 4.6.7", "viewerjs" : "^ 1.5.0", "webpack" : "^ 4.41.2 webpack", "- a bundle - analyzer" : "^ 3.6.0", "webpack - cli" : "^ 3.3.10", "webpack - dev - server" : "^ 3.10.1"}}Copy the code

The final result

Packing volume:

The packing volume has changed from 2.1m to 882KB, which is a huge effect.

Package:

Ant Design, TRTC, Mobx libraries are also gone

Compilation speed:

SMP ⏱ General output time took 10.67 secs SMP ⏱ Plugins HtmlWebpackPlugin took 1.69 secs BundleAnalyzerPlugin took 0.091 Secs CopyPlugin took 0.011 secs MiniCssExtractPlugin took 0.003 secs OptimizeCssAssetsWebpackPlugin took 0.002 secs DefinePlugin took 0.001 secs ContextReplacementPlugin took 0 secs SMP ⏱ Loaders [email protected]@babel-loader took 8.26 secs module count = 277 [email protected]@babel-loader, And [email protected]@eslint-loader took 7.18 secs module count = 86 [email protected] @CSS-loader, And [email protected]@less-loader took 1.94 secs module count = 28 modules with no loaders took 0.728 secs module count = 12 [email protected]@file-loader took 0.392 secs module count = 17 [email protected]@style-loader, And _css - [email protected] @ CSS - loader, And [email protected]@less-loader took 0.052 secs module count = 28 [email protected]@html-webpack-plugin took 0.026 secs module count = 1Copy the code

The compile speed has been reduced from 38.3 secs (15 seconds) to 10.67 secs (10 seconds).

Public CDN addresses at home and abroad

  • BootCDN
  • cdnjs

The resources

  • Webpack Guidebook
  • What is the core knowledge of Webpack?

blog

blog