Recently, we upgraded the company’s project from Webpack4 to Webpack5. After configuring the long-term cache of Webpack5, the speed of secondary construction is directly increased by more than 80%, and the packaging volume is also reduced. Of course, the premise is to make clear whether there are many pits.

There are some online practices that directly upgrade all the relevant packages, but I upgrade them one by one. If necessary, some packages are not upgraded (such as Babel-Loader, etc.), and most of the projects themselves use relatively new versions.

Webpack5 new features

First of all, we need to know what benefits webPackage 5 can bring to us. Let’s look at the new features of WebPackage 5

  • Improve build performance by persisting hard disk caching capabilities
  • Improved long-term caching with better algorithms (reduced cache failure rate for production resources)
  • Optimize the size of the artifacts with better Tree Shaking capability and code generation logic
  • Improve web platform compatibility
  • Cleaned up some weird states in the internal architecture that were left over when Webpack4 introduced some new features without a major update
  • Long term stability in Webpack5 releases by introducing some significant changes to prepare for future features

What is most interesting to me is the ability to build performance improvements and better Tree shaking capabilities to optimize product size.

Webpack5 version why build speed has a qualitative leap?

Mainly because:

Webpack4 generates chunkhash according to the structure of the code, adding blank lines or comments will cause changes in chunkhash, webpack5 generates chunkhash according to the content, changing comments or variables will not cause changes in chunkhash, browsers can continue to use caching.

  • Optimized the efficiency of using cache. In WebPackage 4, both chunkId and moduleId are self-incrementing ids. As soon as we add a module, the number of modules in the code changes, causing the moduleId to change, and the contents of the file to change. The same is true for chunkId. When a new entry is added, the chunkId changes due to the change in the number of chunks, resulting in changes in the file content. Therefore, chunk files that are actually unchanged cannot be used effectively. Webpack5 uses a new algorithm to calculate deterministic chunkId and moduleId. Caching can be used effectively. In production mode, optimization.chunkids and optimization.moduleids will default to ‘Deterministic’.

  • Added the configuration item that allows the cache to be written to disks. When the current build task is terminated on the CLI and the build task is started again, the cache written to disks can be reused to speed up the build process.

The above three explanations are quoted from Webpack5. The speed of build is amazing, and the early upgrade benefits early

After a brief overview of the above, a brief note of some of the things I did during the upgrade process, to see the full recommendations go to the official upgrade documentation

Direct upgrade dependency

Some of the following libraries do not need to be compatible after our project is directly upgraded to the latest version. The configuration itself is not much, but if your project plug-in writes many configuration items, there may be some places that need to be compatible.

  • webpack webpack-cli
  • html-webpack-plugin
  • terser-webpack-plugin
  • mini-css-extract-plugin
  • Style-loader, CSS-loader, postCSS, postCSS-loader (upgrade)

Compatible with

Resource module type

Before And after Webpack4, we used various loaders to process some resources, such as file-loader, URl-loader, raw-loader and so on. However, Webpack5 has built-in static resource building capability, so there is no need to install these extra loaders. Static resources can be packaged with simple configuration.

Asset Module Type replaces all of these loaders by adding 4 new module types:

  • asset/resourceSend a separate file and export the URL. Previously by usingfile-loaderThe implementation.
  • asset/inlineExport the data URI of a resource. Previously by usingurl-loaderThe implementation.
  • asset/sourceExport the source code of the resource. Previously by usingraw-loaderThe implementation.
  • assetAutomatically choose between exporting a data URI and sending a separate file. Previously by usingurl-loaderAnd configure the resource volume limitation implementation.

Example:

module: {
    rules: [{test: /\.(png|jpg|jpeg|gif)$/,
            type: `asset/resource`}},Copy the code

webpack-dev-server

Webpack-dev-server v4.0.0+ requires node >= v12.13.0

Update webpack-dev-server to ^4(next), otherwise HMR will fail

  • The wbePack4 startup mode is as follows:webpack-dev-server.
  • Change webpack5 to:webpack server
// v4
devServer: {
    contentBase: path.resolve(__dirname, '.. /dist'),
    compress: true.inline: true.// The code after the build changes controls the page refresh through the proxy client
    host: '0.0.0.0'.port: PORT,
    clientLogLevel: 'info'.historyApiFallback: true.stats: 'errors-only'.disableHostCheck: true,}Copy the code
// v5
devServer: {
    // contentBase becomes static inside the object
    static: {
      directory: path.resolve(__dirname, '.. /dist'),},client: {
      logging: 'info',},compress: true.// Inline: true, // remove directly without alternatives
    host: '0.0.0.0'.port: PORT,
    historyApiFallback: true.allowedHosts: 'all'.// Replace disableHostCheck: true
    // Add middleware configuration
    devMiddleware: {
      stats: 'errors-only',}},Copy the code

Related articles: Webpack-dev-server V3 Migration V4 Guide

Webpack5 removed Node.js Polyfill (compatible)

Webpack5 removes node.js polyfills, which will cause some packages to become unusable (‘XXX’ is not defined on the console). If you need to be compatible with Process /buffer Nodejs polyfills, Install the associated Polyfill: Process and declare injection explicitly in the Plugin. There are process variables used in the business code, so compatibility is required, and the Process /buffer library is installed.

{
    plugins: [
        new webpack.ProvidePlugin({
          process: 'process/browser',]}})Copy the code

Upgrade obsolete configuration items

Description of the configuration items before the modification (config/webpack_prod.ts) :

splitChunks: {
  chunks: 'all'.minSize: 30000.// Modules must be larger than 30KB to be extracted
  minChunks: 1.// Minimum number of references, default is 1
  maxAsyncRequests: 5.// The maximum number of simultaneous requests for asynchronous code loading cannot exceed 5
  maxInitialRequests: 3.// The maximum number of simultaneous requests for import files cannot exceed 3
  automaticNameDelimiter: '_'.// Module file name prefix
  name: true.// Automatically generates the file name
  cacheGroups: {
    // Extract the modules from node_modules into a public file
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: -10.// Execution priority, default is 0
    },
    // Other modules that are not in node_modules are also extracted if they are referenced at least twice
    default: {
      minChunks: 2.priority: -20.reuseExistingChunk: true.// Duplicate blocks will not be generated if the current code block contains modules that already exist}},},Copy the code
// v5
splitChunks: {
  cacheGroups: {
    / / vendors - > defaultVendors
    defaultVendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: -10.// Execution priority, default is 0}},},Copy the code

This can be renamed in (config/webpack_prod.ts)

Splitchunks.name (removed)

Splitchunks. name indicates the name of the extracted file

  • In V4, this configuration defaults to true to automatically generate file names
  • V5 removed the name of optimization.splitchunks: true: automatic naming is no longer supported

Migration: Use the default values. ChunkIds: “named” will give your file a useful name for easy debugging

Output configuration (compatible)

(node:58337) [DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_HASH] DeprecationWarning: [hash] is now [fullhash] (also consider using [chunkhash] or [contenthash], see documentation for details)

Hash is no longer recommended. Instead, use fullhash, which is named config/webpack_dev.ts more clearly than the original hash

// v4
output: {
    filename: 'js/[name].[hash].js'.chunkFilename: 'js/[name].[hash].js',},// v5
output: {
    filename: 'js/[name].[fullhash].js'.chunkFilename: 'js/[name].[fullhash].js',},Copy the code

Optimize configuration items (obsolete removal)

(config/webpack_prod. Ts)

// Webpack V4, deprecated in V5, needs to be removed

new webpack.HashedModuleIdsPlugin()
Copy the code

HashedModuleIdsPlugin Functions: Implements persistent caching. The module ID is computed via HashedModuleIdsPlugin, which replaces the numeric increment BASED ID with the module’s own hash. In this way, the ID of a module will only change when it is renamed or removed, and the new module will not affect its ID change.

Webpack5 adds support for certain moduleIDS and chunkId as follows:

optimization.moduleIds = 'deterministic'
optimization.chunkIds = 'deterministic'
Copy the code

This configuration is enabled by default in production mode and is used to assign 3-5 digit ids to modules and chunks in a determinate manner, replacing HashedModuleIdsPlugin v4.

Global variable writing (compatible)

module.exports = () = > {
  return {
    // ...
    plugins: [
      // Webpack5 defines environment variables differently
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify('production'),}),// webpack4
    // new webpack.DefinePlugin({
    // 'process.env': {
    // NODE_ENV: JSON.stringify('production'),
    / /},
    / /}),]}; };Copy the code

Cache optimization using cache attributes (New)

By default, webPack5 does not enable persistent caching. If you do not manually add cache configuration, webPack5 is not optimized. When cache.type: “filesystem” is set, webpack internally enables filesystem caching and memory caching in a hierarchical manner. When reading from the cache, the memory cache is first looked at, and if it is not found, it is demoted to the file system cache. The write cache writes to both the memory cache and the file system cache. The file system cache does not serialize requests to disk directly. It will not execute until the compilation process is complete and the compiler is idle. The reason for this is that serialization and disk writes take up resources, and we don’t want to delay the compilation process any further.

cache: {
    // Set the cache type to file system, memory by default
    type: 'filesystem'.buildDependencies: {
      // The cache is invalidated when the contents of the config file that builds the dependency (via the require dependency) change
      config: [__filename],
      // If you have other things to build on, you can add them here}},Copy the code

In case the cache is so fixed that changes to the build configuration go unnoticed, the old cache is still used, and by default, each change to the build configuration file causes the cache to restart. You can also set version on your own initiative to control the update of the cache.

Final optimization results

First compilation:

Second compilation:

Effect: the speed of secondary construction is increased by more than 85%

Refer to the article

  • Webpack5 new features are implemented
  • Webpack5 website
  • Webpack4 optimizes performance
  • Build efficiency significantly improved, Webpack5 in penguin tutorial upgrade practice
  • Webpack5 build speed is amazing, early upgrade early benefit