If you have any thoughts on my blog or articles and you want to let me know, you can either post a comment below(public) or tell me via this i_kkkp@163.com

Webpack Performance Optimization-1

Introduction

Let’s talk about why optimization is necessary. If your project is small and builds quickly, you might not need to worry too much about performance optimization. However, as your project grows with more pages, features, and business logic, the build time of webpack, the underlying build tool, also increases. At this point, optimizing performance becomes crucial.

Webpack offers various avenues for performance optimization, which can be broadly categorized into two areas:

Optimization One: Optimizing the built result for production, focusing on performance during deployment (e.g., code splitting, reducing bundle size, using CDN servers, etc.).
Optimization Two: Optimizing build speed for development or production build, enhancing the speed of the build process (e.g., using exclusion, cache loaders, etc.).
The performance during production directly affects user experience, whereas build time is closely related to developers’ daily workflow. If the local development server or production build takes too long, it significantly hampers productivity.

Performance Optimization - Code Splitting

Code splitting is a critical feature in webpack:

Its primary purpose is to separate code into different bundles, which can be loaded on demand or in parallel.
By default, all JavaScript code (business logic, third-party dependencies, and modules not immediately used) is loaded on the initial page load, impacting the loading speed.
Code splitting allows creating smaller bundles and controlling resource loading priorities, thereby enhancing code loading performance.

Webpack provides three common approaches to code splitting:

  • Entry Points: Manually splitting code using entry configuration
  • Preventing Duplication: Avoiding duplicate code using Entry Dependencies or SplitChunksPlugin
  • Dynamic Imports: Splitting code using inline functions in modules

Optimizing Entry Points - Entry Dependencies

When a project has multiple entry points, there might be issues with duplicate dependencies. Some modules might be referenced in multiple entry points, causing redundancy in the final output, increasing the output file size.

module.exports = {
  entry: {
    page1: {
      import: './src/page1.js',
      dependOn: 'shared',
    },
    page2: {
      import: './src/page2.js',
      dependOn: 'shared',
    },
    shared: './src/shared.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: __dirname + '/dist',
  },
}; 

Dynamic Imports

Dynamic imports are a technique in webpack for lazy loading, allowing modules to load asynchronously at runtime instead of bundling all modules into a large initial file. This approach improves the initial loading speed and reduces the initial bundle size.

const path = require('path');

module.exports = {
  entry: {
    main: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
  },
  module: {
    rules: [
      // Add your loader rules here
    ],
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

In the above configuration, code splitting is achieved using optimization.splitChunks with the option chunks: 'all'.

Then, dynamic imports can be used in the code like this:

// Dynamically import modules where needed
const loadModule = () => import('./Module');

loadModule().then(module => {
  // Use the loaded module
});

Webpack will split the modules imported using import() into separate files. These files will be loaded asynchronously when needed during runtime.

Custom Bundle Splitting - SplitChunks

Bundle splitting is an optimization strategy that allows breaking down code into smaller pieces, enabling faster content display during loading.

Webpack provides various strategies for bundle splitting, one of which involves using the SplitChunksPlugin plugin. This strategy is known as splitChunks.

module.exports = {
  // ...other configurations
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 30000, // Minimum size of the module before splitting
      minChunks: 1, // Minimum number of times a module should be duplicated before splitting
      maxAsyncRequests: 5, // Maximum number of parallel requests when loading modules on demand
      maxInitialRequests: 3, // Maximum number of parallel requests at an entry point
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

For more information, refer to the webpack-split-chunks-plugin documentation.


Performance Optimization - CDN

CDN, or Content Delivery Network, refers to a network of interconnected servers strategically placed to deliver content to users efficiently. It ensures faster and more reliable delivery of resources such as music, images, videos, applications, and other files by utilizing servers closest to each user, providing high performance, scalability, and low-cost content delivery.

In development, CDN is typically used in two ways:

  • All static resources are bundled and stored on a CDN server, and users load resources exclusively through the CDN.
  • Some third-party resources are hosted on CDN servers.

Utilizing a Content Delivery Network (CDN) is a highly effective performance optimization strategy, especially within Webpack. CDN accelerates website loading speed, reduces server load, and enhances user experience. Here’s how you can configure and use CDN in Webpack:

Using CDN for Third-Party Libraries

Integrate third-party libraries used in your project (such as React, Vue, jQuery, etc.) through CDN links directly in the HTML file:

<script src="https://cdn.jsdelivr.net/npm/react@version/dist/react.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@version/dist/react-dom.min.js"></script>

Configuring Externals in Webpack

In your Webpack configuration, utilize the externals field to inform Webpack about externally referenced modules that shouldn’t be bundled:

module.exports = {
  // ...other configurations
  externals: {
    react: 'React',
    'react-dom': 'ReactDOM',
  },
};

Then, include the CDN links in the HTML file using script tags:

<script src="https://cdn.jsdelivr.net/npm/react@version/dist/react.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@version/dist/react-dom.min.js"></script>

Configuring CDN’s publicPath

In the Webpack output field, set the publicPath to specify the URL prefix for resource imports, typically set to the CDN’s address:

module.exports = {
  // ...other configurations
  output: {
    // ...other output configurations
    publicPath: 'https://cdn.example.com/',
  },
};

This way, during Webpack build, all resource paths will be prefixed with the CDN’s address.

Performance Optimization - Extracting CSS Files

Extracting CSS files from JavaScript bundles is a common performance optimization strategy. This approach reduces the size of JavaScript files, speeds up page loading, and allows browsers to download CSS and JavaScript files in parallel, enhancing loading performance. In Webpack, you can achieve this using the mini-css-extract-plugin plugin.

Webpack Configuration

In your Webpack configuration file, include the mini-css-extract-plugin plugin and configure the module.rules to handle CSS files:

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

module.exports = {
  // ...other configurations

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          // Additional CSS loaders like postcss-loader and sass-loader can be added here
        ],
      },
    ],
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles.css', // Filename for the extracted CSS file
    }),
  ],
};

Including CSS Files

In your JavaScript files or entry point file, import the CSS file:

import './styles.css';

Alternatively, in the HTML file, use the link tag to include the extracted CSS file:

<link rel="stylesheet" href="styles.css">

Performance Optimization - Bundling File Naming (Hash, ContentHash, ChunkHash)

In Webpack, how files are named during bundling is a crucial performance optimization strategy. Proper naming ensures that browsers can cache files correctly, avoiding unnecessary network requests and improving application loading speed. Here are three common bundling file naming techniques: Hash, ContentHash, and ChunkHash.

Hash

Hash is generated based on file content. When file content changes, its corresponding hash value also changes. In Webpack, you can use the [hash] placeholder to represent the hash value.

output: {
  filename: 'bundle.[hash].js',
}

ContentHash

ContentHash is generated based on file content as well, but unlike Hash, it’s solely influenced by file content and remains unaffected by file name or path changes. In Webpack, you can use the [contenthash] placeholder to represent the ContentHash value.

output: {
  filename: 'bundle.[contenthash].js',
}

ChunkHash

ChunkHash is generated based on module content. Different module contents result in different ChunkHash values. In Webpack, you can use the [chunkhash] placeholder to represent the ChunkHash value.

output: {
  filename: '[name].[chunkhash].js',
}

Performance Optimization - Implementing Tree Shaking in Webpack

JavaScript Tree Shaking:

Tree Shaking in JavaScript originates from the rollup bundler, a build tool. It relies on the static syntax analysis of ES Modules (no code execution) to determine module dependencies.

Webpack 2 introduced native support for ES2015 modules, enhancing tree shaking capabilities. Webpack 4 extended this ability and introduced the sideEffects property in package.json to indicate which files have no side effects, allowing webpack to safely remove unused code.

In Webpack 5, partial CommonJS tree shaking support was introduced.

CommonJS Tree Shaking

Implementing Tree Shaking in JavaScript

Webpack implements Tree Shaking through two methods:

  • usedExports: Marking certain functions as used and optimizing them using Terser.
  • sideEffects: Skipping entire modules/files and checking if they have side effects.

Tree Shaking for CSS

Tree Shaking for CSS involves using additional plugins. While PurifyCss was used previously, it’s no longer maintained. An alternative is PurgeCSS, a tool for removing unused CSS.


Note: This translation includes placeholder strings like [hash], [contenthash], and [chunkhash] to represent dynamic values. Please replace these placeholders with appropriate values based on your specific use case.


Note: This article is a translated version of the original post. For the most accurate and up-to-date information, please refer to the original source.
```

pack-tool-preview Understanding Ajax and Cross-Origin Requests Easily

Comments