How to Enhance Webpack Performance with Code Splitting

Webpack is a powerful tool for bundling JavaScript, but as applications grow larger, optimizing those bundles can become challenging. In the early days of front-end development, bundling everything into a single JavaScript file was the default approach. However, as web applications became more complex, loading a massive single bundle with all the code—whether needed immediately or not—became inefficient. This resulted in longer load times, slower performance, and ultimately, a poor user experience.

To address this issue, code splitting was introduced. Code splitting allows you to break your bundle into smaller, more manageable pieces, loading only the code that's necessary for a given page or feature. This improves performance by reducing the initial load time, avoids duplicate dependencies across modules, and makes your web application more efficient.

Here’s a quick breakdown of how to handle single and multiple entry points with shared modules, and how to avoid duplication in your Webpack setup.


1. Single Entry Point with Shared Modules: No Duplication

Everything is bundled together when you use a single entry point for your Webpack config. If you're using a shared module, like Lodash, Webpack will only include it once in the bundle.

File Structure:

/src
  /index.js
  /lodash-util.js

Module Files

// src/index.js
const lodash = require('lodash');
const welCome = require('./another-module');
const component = () => {
    const element = document.createElement('div');
    element.innerHTML = lodash.join([welCome(), 'Webpack'], ' ');

    return element;
}
document.body.appendChild(component());


// src/another-module.js
const lodash = require('lodash');
const welCome = () => lodash.join(['Greetings', 'from'], ' ');
module.exports = welCome;

Webpack Configuration

module.exports = {
  entry: './src/index.js', // Single entry point
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new BundleAnalyzerPlugin(), // Analyze the bundle
  ],
};

What Happens?

  • Webpack bundles everything into a single bundle.js.

  • There is no duplication of shared modules like Lodash. Lodash will only appear once in the bundle.

  • The Bundle Analyzer shows a clean, single chunk with no repeats.

WebPack Bundle Analyzer Output

Even though both index.js and another-module.js are using the same lodash.js library, Webpack handles it properly and does not duplicate lodash.js in each module.

Key Takeaway

A single entry point keeps things simple. Dependencies like Lodash are only included once in the final bundle.


2. Multiple Entry Points: Duplication Happens

If you decide to use multiple entry points, like index.js and another-module.js, Webpack will bundle them separately. If both entry points depend on the same module, like Lodash, you’ll get duplicate Lodash in each bundle.

Example Project Structure

/src
  /index.js
  /another-module.js
  /lodash-util.js

Module Code

// src/index.js
const lodash = require('lodash');
const component = () => {
    const element = document.createElement('div');
    element.innerHTML = lodash.join(["Hello", 'from', 'Webpack'], ' ');

    return element;
}
document.body.appendChild(component());

//______________________________________________

// src/another-module.js
const lodash = require('lodash');
const welCome = () => lodash.join(['Greetings', 'from'], ' ');
module.exports = welCome;

If we look at the code, we have two modules (index.js and another-module.js), both of which import the same lodash module. However, since we are creating separate bundles for index.js and another-module.js, they will not import functions from each other. This is because each bundle is independent, and the modules do not share a runtime environment or scope to directly access each other's internal functions.

Webpack Configuration

module.exports = {
  entry: {
        /**
         * Multiple entry points
         */
        index: './src/index.js',
        another: './src/another-module.js',
    },
    output: {
        /**
         * using [name] to generate multiple bundles
         */
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
  plugins: [
        /**
        * using BundleAnalyzerPlugin to analyze the bundle size
        */
        new BundleAnalyzerPlugin({
            analyzerMode: 'static',
            openAnalyzer: false,
            reportFilename: 'bundle-analyzer-report.html',
        })
  ],
};

What Happens?

  • Webpack creates two separate bundles: index.bundle.js and another.bundle.js.

  • Lodash is included in both bundles, leading to duplication.

  • The Bundle Analyzer report will show Lodash in both bundles.

WebPack Bundle Analyzer Output

Looking at this bundle analyzer output, we can see that the lodash.js module is duplicated in each entry point bundle.

Key Takeaway

With multiple entry points, Webpack will bundle each entry separately. This can lead to duplicate dependencies being included in each bundle.


3. Avoiding Duplication with splitChunks

To prevent duplicate modules, you can use splitChunks optimization. This tells Webpack to extract shared modules (like Lodash) into a common chunk that can be shared across all entry points.

Example Project Structure

bashCopy code/src
  /index.js
  /another-module.js
  /lodash-util.js

Module Code

// src/index.js
const lodash = require('lodash');
const result = welCome();
const component = () => {
    const element = document.createElement('div');
    element.innerHTML = lodash.join(["Hello", 'from', 'Webpack'], ' ');

    return element;
}
document.body.appendChild(component());

//______________________________________________

// src/another-module.js
const lodash = require('lodash');
const welCome = () => lodash.join(['Greetings', 'from'], ' ');
module.exports = welCome;

Webpack Configuration

const path = require('path');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
    entry: {
        /**
         * Multiple entry points
         */
        index: './src/index.js',
        another: './src/another-module.js',
    },
    output: {
        /**
         * using [name] to generate multiple bundles
         */
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        /**
         * using BundleAnalyzerPlugin to analyze the bundle size
         */
        new BundleAnalyzerPlugin({
            analyzerMode: 'static',
            openAnalyzer: false,
            reportFilename: 'bundle-analyzer-report.html',
        })
    ],
    optimization: {
        /**
         * using splitChunks to split common modules into separate  bundles
         */
        splitChunks: {
            chunks: 'all',
        },
    },
}

What Happens?

  • Webpack now creates three bundles: index.bundle.js, another.bundle.js, and a shared chunk (e.g., vendors~index~another.js).

  • Lodash is extracted into the shared chunk and no longer duplicated in the individual entry point bundles.

  • The Bundle Analyzer shows Lodash only in the shared chunk.

WebPack Bundle Analyzer Output

Now both index.js and another-module.js share the same lodash.js module.

Key Takeaway

By using splitChunks, Webpack extracts common modules into a shared chunk, preventing duplication and improving overall performance.


Conclusion

Webpack's code splitting helps you optimize your bundles and avoid duplicate dependencies. Here's a quick recap:

  • Single entry point: Everything is bundled into one file, with no duplication of shared modules.

  • Multiple entry points: Webpack creates separate bundles for each entry point, leading to duplicate modules if they share dependencies.

  • splitChunks optimization: This extracts shared modules into their own chunk, eliminating duplication and improving performance.

Bundle Analyzer is a great way to visualize how Webpack splits your code and check for any unwanted duplication.

If you'd like to experiment with the code, feel free to pull it and run it on your local machine. GitHub - branch: code-splitting

Happy Coding 👨‍💻

— Basavaraj Patil

Did you find this article valuable?

Support Basavaraj Patil by becoming a sponsor. Any amount is appreciated!