Webpack performance optimization: improve webpack compilation speed

This article mainly records the next  webpack performance optimization

status quo

As the project continues to develop and grow, the number of components begins to increase, the project also begins to grow, and the webpack compilation time will be longer and longer. Our current project is compiled only once  40s ——70s , which is very inefficient. operating. There are many optimization methods. The previous project has already done a lot. This article will explain the optimization from the perspective of caching.

The following only introduces several caching-related optimization methods, including

  • babel-loader of cacheDirectory

  • cache-loader

  • dll Dynamic link library

  • HardSourceWebpackPlugin

Let me talk about the conclusion first, the first one is the existing one in the project, the second and the third have little effect, and the fourth one has achieved the expected effect.

Our webpack version: 4.41.2, system: mac os

Bottleneck analysis

The first step of optimization should be to analyze the current performance, here we use the  speed-measure-webpack-plugin speed analysis

// 安装
npm install --save-dev speed-measure-webpack-plugin
// 使用方式
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
 
const smp = new SpeedMeasurePlugin();
 
const webpackConfig = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
});

The results are similar to the following, you can see  the time-consuming of each Loader and  every one  Plugin, with this, we can "prescribe the right medicine"

image

But it should be noted that: HardSourceWebpackPlugin and speed-measure-webpack-plugin cannot be used together , which makes me depressed for a long time

babel-loader 的 cacheDirectory

babel-loader It is allowed to use  Babel and  webpack translate  JavaScript files. Sometimes if we run  babel-loader very slowly, we can consider ensuring that as few files as possible are translated. You may use  /\.m?js$/ to match, which may translate  node_modules directories or other unneeded source code, resulting in performance degradation

You can  exclude exclude some files that do not need to be compiled. For example, the following will not escape  node_modules and  bower_components the contents of the folder

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-proposal-object-rest-spread']
        }
      }
    }
  ]
}

You can also  speed up at least twice by using  cacheDirectory options  babel-loader. This will cache the result of the translation in the file system. cacheDirectory The default value is  false. When set, the specified directory will be used to cache  loader the execution results. In subsequent  webpack constructions, it will try to read the cache to avoid the high-performance consumption Babel recompilation process that may occur each time it is executed  ( recompilation process). If an empty value is set  (loader: 'babel-loader?cacheDirectory')or  true (loader: 'babel-loader?cacheDirectory=true'), the loader will use the default cache directory node_modules/.cache/babel-loader. If no directory is found in any root  node_modules directory, it will downgrade and fall back to the default temporary file directory of the operating system.

{
  test: /\.js$/,
  use: 'babel-loader?cacheDirectory',
  include: [resolve('src'), resolve('test') ,resolve('node_modules/webpack-dev-server/client')]
}

cache-loader

Except  babel-loader, if we want to loader cache other  processing results, what should we do?

The answer is that it can be used  cache-loader. loader Add before  some high performance overhead  cache-loader, in order to cache the results to disk

installation

npm install --save-dev cache-loader

Configuration

module.exports = {
  module: {
    rules: [
      {
        test: /\.ext$/,
        use: ['cache-loader', ...loaders],
        include: path.resolve('src'),
      },
    ],
  },
};

⚠️ Please note that saving and reading these cache files will have some time overhead, so please use this loader only for loader with high performance overhead

In addition to the default configuration, cache-loader some other options are provided, see cache-loader[1] for details

dll caching scheme

What is a DLL?

The DLL file is a dynamic link library, and a dynamic link library can contain functions and data called for other modules

Why use DLL?

The reason is that the dynamic link library containing a large number of reused modules only needs to be compiled once, and the modules contained in the dynamic link library will not be recompiled in the subsequent construction process, but directly use the code in the dynamic link library. Since most of the dynamic link library contains commonly used third-party modules, for example  Vue react、react-dom, as long as the version of these modules is not upgraded, the dynamic link library does not need to be recompiled

how to use?

To complete the following three steps:

  • Pull away. Extract the basic modules that the web page depends on and pack them into separate dynamic link libraries. A dynamic link library can contain multiple modules

  • Obtain. When the module that needs to be imported exists in a dynamic link library, this module cannot be packaged again, but is obtained from the dynamic link library

  • load. All dynamic link libraries that the page depends on need to be loaded

Used DllPlugin and  DllReferencePlugin completed before  , but its configuration is very complicated, and if the file is updated, the dll needs to be regenerated manually. AutoDllPlugin[2] is selected here, it will automatically complete the functions of the above two plug-ins, this is Vue-cli a plug-in that  has been used

installation:

webpack 4

npm install --save-dev autodll-webpack-plugin

webpack 2 / 3

npm install --save-dev [email protected]

Basic use:

plugins: [
  new HtmlWebpackPlugin({
    inject: true,
    template: './src/index.html',
  }),
  new AutoDllPlugin({
    inject: true, // will inject the DLL bundles to index.html
    filename: '[name].js',
    entry: {
      vendor: [
        'react',
        'react-dom'
      ]
    }
  })
]

Before optimization

image

Optimized

Compiling for the first time:

image

Second compilation:image

Optimized for a few seconds, but little effect

The result is not very effective, because  webpack4 the performance is good enough, Vue-cli and this function is also abolished.

HardSourceWebpackPlugin

installation:

npm install --save-dev hard-source-webpack-plugin
# or
yarn add --dev hard-source-webpack-plugin

Configuration:

// webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

module.exports = {
  context: // ...
  entry: // ...
  output: // ...
  plugins: [
    new HardSourceWebpackPlugin()
  ]
}

Before optimization

image

As you can see, it takes 50s

Optimized

First start

image

Second start

image

It only takes 7 s, which is reduced  43 s, and the speed is increased by about 80%. The purpose of optimization is achieved!

Hot update speed

Seeing  issue that it mentioned about hot update, it will be slower, I used our project to do some tests, the following is the test data

Before optimization

js: 2443ms  1634ms 1844ms 2532ms 1443ms 1248ms

html: 1094ms 1232ms 1119ms 1490ms 1264ms

css: 1422ms 1186ms 1341ms  1562ms 1183ms

Optimized

js: 2429ms 2436ms 2860ms 2528ms 1917ms 1487ms 1450ms 1450ms 1557ms 2198ms

html: 2855ms 1569ms 1400ms 1298ms 1204ms 1299ms 1578ms 1485ms 2028ms

css: 2035ms 1406ms 1415ms 1600ms 1773ms 1604ms

In comparison, sometimes it is a bit slower, but overall it is acceptable. But there are also some impacts, so two npm script commands have been added to the project  . If you don’t want to open it, you can directly npm run dev:noCache

"scripts": {
  "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=true",
  "dev:noCache": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=false"
}

In  build/webpack.dev.conf.js the

if (args.cache) {
  devConfig = merge(devConfig, {
    plugins: [new HardSourceWebpackPlugin()]
  })
}

emphasize again:

HardSourceWebpackPlugin and speed-measure-webpack-plugin cannot be used together

Looking to the future

webpack 5 Has been released, which has a very attractive feature-persistent cache (it is said that the thinking  HardSourceWebpackPlugin is the same)

By  cache  caching the generated  webpack modules and chunkto improve the build speed. cache Will be set to in development mode  type: 'memory' and disabled in production mode

module.exports = {
  cache: {
    // 1. 将缓存类型设置为文件系统
    type: 'filesystem',

    buildDependencies: {
      // 2. 将你的 config 添加为 buildDependency,以便在改变 config 时获得缓存无效
      config: [__filename],

      // 3. 如果你有其他的东西被构建依赖,你可以在这里添加它们
      // 注意,webpack、加载器和所有从你的配置中引用的模块都会被自动添加
    },
  },
};

Guess you like

Origin blog.csdn.net/AN0692/article/details/114358197