Unlock Webpack splitChunks & Manifest: A Hands‑On Guide to Smarter Bundling
This tutorial walks through the fundamentals of Webpack’s splitChunks and manifest features, explaining modules, chunks, and bundles, detailing configuration options like chunks, cacheGroups, minChunks, priority, maxInitialRequests, and maxAsyncRequests, and shows practical code examples and visual results to help developers master efficient asset bundling.
1 Background
For anyone new to building projects, Webpack often feels like an insurmountable hurdle because of its abstract concepts and concise documentation.
The author rarely writes Webpack configurations from scratch, so some settings are not completely clear.
A recent requirement to add MD5 version numbers to page resources gave an opportunity to revisit and reorganize the project's Webpack configuration.
This article skips basic concepts such as entry and output and focuses on the splitChunks and manifest sections.
2 Basic Concepts
To understand splitChunks, you need to grasp three core ideas: module, chunk, and bundle.
module : each imported file is a module (the code you write yourself).
chunk : when source files are fed to Webpack, it generates chunks based on import relationships.
bundle : the final compressed output that can be executed directly.
An illustration of these concepts:
Chunks come in three types:
Project entry (entry).
Dynamically imported code.
Code split out by splitChunks.
3 splitChunks Overview
splitChunksis used to split bundles, extracting code that meets certain rules into separate packages to isolate common modules and reduce duplication.
The configuration items inside splitChunks define the splitting rules; the cacheGroups option must satisfy all its conditions to take effect.
In Webpack 5, the default configuration for splitChunks is:
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
// Only split when the content exceeds minSize
minSize: 20000,
// Ensure the remaining chunk after splitting is larger than this value to avoid zero‑size modules
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
// Force split when size exceeds this threshold, ignoring minRemainingSize, maxAsyncRequests, maxInitialRequests
enforceSizeThreshold: 50000,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
// Reuse an existing chunk if it has already been split from the main bundle
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};The following sections explain the configuration items that were not commented.
3.1 chunks
The chunks option can be all, async, or initial; the default is async.
Consider this example with entry1.js that dynamically imports page1.js (React syntax requires Babel).
entry1.js
import React from 'react';
import ReactDom from 'react-dom';
const App = () => {
let Page1 = null;
import('./page1.js').then(comp => {
Page1 = comp;
});
return (
<div>
<div>App</div>
<Page1 />
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))page1.js
import _ from 'lodash';
import React from 'react';
const Page1 = () => {
return (
<div>
<div>Page1</div>
</div>
)
}
export default Page1;Bundling result (illustrated below):
Analysis: main.js is the entry file and is split into its own chunk. page1_js.js is the dynamically loaded file, also a separate chunk.
The third chunk contains the third‑party library lodash, extracted according to the cacheGroups configuration.
Why is lodash extracted while react, which is imported by both entry1.js and page1.js, is not? The answer lies in the chunks: "async" setting, which only applies to asynchronously loaded packages.
Because lodash is imported in page1.js, which is loaded asynchronously, it meets the split rule. react is not loaded asynchronously, so it does not trigger the split.
Understanding chunks: "async" makes it easy to grasp the behavior of chunks: "all" and chunks: "initial": initial splits only from entry modules. all splits from both entry and async modules.
3.2 cacheGroups
cacheGroupsis the core of splitChunks. Each group defines a set of rules for extracting modules. The default vendors group matches node_modules, so third‑party libraries are placed into a vendor chunk. The default group extracts shared user‑defined modules.
Key options in cacheGroups:
3.2.1 minChunks
A module is extracted when it is imported at least minChunks times, but only counting imports from entry modules (dynamic imports are ignored unless chunks is set to all).
Example: both entry1.js and entry2.js import a local jquery.js. Since the import count is 2, jquery satisfies minChunks and is extracted.
When only entry1.js remains, the dynamic import of jquery in page1.js does not count toward minChunks, so jquery stays in the entry chunk.
3.2.2 priority
The priority field determines which rule wins when a chunk satisfies multiple groups. Higher priority wins; if equal, the first defined group wins. This explains why react-dom ends up in the vendors chunk instead of the default chunk.
3.3 maxInitialRequests
This option limits the maximum number of parallel requests for entry files. It prevents excessive chunk splitting that would cause too many HTTP requests.
When multiple chunks qualify for extraction but the limit is reached, Webpack selects the larger chunk to split.
3.4 maxAsyncRequests
Similar to maxInitialRequests, but applies to asynchronous modules. It limits the number of parallel async requests.
4 manifest
When a new version of a page is deployed, browsers may still serve cached resources unless the filenames contain a hash. Adding a contenthash to the filename solves this, but when one project imports assets built by another project, the hash changes each build, making it hard to know which file to request.
The manifest plugin records the mapping between original filenames and their hashed counterparts, enabling accurate requests for versioned assets.
Example manifest generated by webpack-manifest-plugin:
5 Summary
By experimenting with concrete demos, even a daunting tool like Webpack becomes much more approachable. When you encounter a technology that feels intimidating, it signals a knowledge gap—spend time mastering it, and the next encounter will feel like an opportunity to showcase your expertise.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
