Mastering Webpack Code Splitting with SplitChunksPlugin
When a JS app grows, the single bundle becomes a performance bottleneck. Webpack’s SplitChunksPlugin extracts stable third‑party code into a vendor bundle, while dynamic imports load heavy modules. This article explains how to configure, verify, and balance code splitting for optimal load times.
17 Jan 2026, 23:37 UTC

The Problem with Monolithic Bundles
When a JavaScript application grows, the single main.js file becomes a bottleneck. Users must download, parse, and execute the entire codebase—including heavy libraries like React, Lodash, or D3—before the page becomes interactive. This inflates the Time to Interactive (TTI) and hurts the user experience.
Webpack’s default behaviour is to bundle every imported module into one file. A tiny change in a component can change the hash of the entire bundle, forcing browsers to re‑download everything, even code that hasn’t changed.
Thesis: SplitChunksPlugin + Dynamic Imports = Faster Loads
Code splitting lets you break the monolith into logical pieces. The SplitChunksPlugin extracts common code—especially from node_modules—into a vendor bundle that can be cached across releases. Dynamic import() statements create on‑demand chunks for routes or heavy components. Together, they reduce the initial payload and improve caching.
1. Extracting Vendor Code with SplitChunksPlugin
In Webpack 5, SplitChunksPlugin is enabled by default. The key is to tune its cacheGroups so that stable third‑party libraries land in a single chunk. Below is a pragmatic configuration:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
optimization: {
splitChunks: {
chunks: 'all', // Optimize both sync and async imports
minSize: 20000,
maxInitialRequests: 10,
maxAsyncRequests: 20,
cacheGroups: {
vendors: {
test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/,
name: 'vendors',
chunks: 'all',
priority: -10,
enforce: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
Key points:
chunks: 'all'ensures both synchronous and asynchronous code is examined.- The
vendorsgroup pulls anything undernode_modulesinto a singlevendors.[contenthash].jsbundle. - Using
[contenthash]guarantees that only the vendor bundle changes when your app code changes, preserving cache.
2. On‑Demand Loading with Dynamic Imports
Dynamic imports are the syntax that tells Webpack to create a separate chunk for a module that isn’t needed immediately. For example, a heavy chart library used only on a report page:
// src/components/ReportButton.js
import React from 'react';
export default function ReportButton() {
const handleClick = async () => {
const { default: Chart } = await import(/* webpackChunkName: "chart" */ './heavy-chart');
Chart.render();
};
return Load Report;
}
Webpack generates a chart.[contenthash].chunk.js file that is fetched only when the button is clicked. The comment /* webpackChunkName: "chart" */ gives the chunk a readable name.
3. Verifying Your Split Strategy
- Bundle Analysis: Install
webpack-bundle-analyzerand run the build.
The visual report should shownpx webpack-bundle-analyzer dist/stats.jsonvendorsand any dynamic chunks separately. - Network Inspection: Open DevTools, reload the page, and verify that
vendors.[hash].jsloads once. Trigger the dynamic import and check thatchart.[hash].chunk.jsis requested only then. - Cache Persistence: Modify a small string in
src/index.js, rebuild, and confirm that the filename ofvendors.[hash].jsremains unchanged while the main bundle hash changes.
4. Trade‑Offs and Limitations
- Over‑Splitting: Too many tiny chunks increase the number of HTTP requests. On HTTP/1.1 this can degrade performance; HTTP/2 mitigates but still adds latency. Keep
minSizereasonable and setmaxAsyncRequeststo avoid bursts. - Duplicate Code: Misconfigured
cacheGroupscan cause the same library to appear in multiple chunks, negating caching benefits. Always inspect the analyzer output. - Server Support: If you serve static files via a CDN, ensure it supports
Cache-Control: immutablefor vendor chunks so that browsers can reuse them across releases.
Actionable Checklist
- Set
optimization.splitChunks.chunksto'all'and create avendorscacheGroup. - Use
[contenthash]in filenames. - Add dynamic
import()for heavy or route‑specific code. - Run
webpack-bundle-analyzerand inspect Network tab. - Verify vendor hash stability across builds.
- Monitor request counts; adjust
minSizeormaxAsyncRequestsif necessary.
By following these steps, you’ll deliver a faster, cache‑friendly experience that scales as your application grows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.