Hello there! I've just finished optimizing my last commercial project, and now, I want to share what I've learned. So, I've decided to start a series of articles.
In this article, I want to share with you knowledge about webpack's optimization.splitChunks functionality. That functionality is a part of the webpack since version 4 before It was an external plugin called SplitChunksPlugin. It provides a way to split your bundle into several parts.
When can it be useful?
It can help you at least in two kinds of cases:
- When you have a single entry, you can separate vendors for a better cache strategy
- When you have many entries, you can separate common parts
Let's take a look at examples of both cases.
Single entry
Let's imagine that we have a bundle that contains react app. It includes JavaScript code from an app
directory and several npm packages from the node_modules
directory:
Our bundle's name contains a contenthash
for cache validation in the browser. When we change some code in our app, we create a new bundle that includes a different contenthash
, and users will download it again. Frequently we'll change code inside our app
directory and not change our npm dependencies, but our users will anew download the whole bundle. Here is where splitChunks can help us.
We can separate our bundle into two parts:
- code inside
app
directory - code inside
node_modules
In this way, when we'll change a code inside the app
directory, our users will download only that part.
Let's do it!
To do that we need to add that code to our webpack config:
{
entry: {
... // here is your entry
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /node_modules/,
chunks: 'initial',
filename: 'vendors.[contenthash].js',
priority: 1,
maxInitialRequests: 2, // create only one vendor file
minChunks: 1,
}
}
}
}
}
Now our bundles will looks like that:
How you can see we don't reduce bundle size, but we save some kb of traffic for our users in case when we change only one part of code.
You can get more control of what will be added to bundle by passing function instead of regexp as test:
{
entry: {
... // here is your entry
},
optimization: {
splitChunks: {
cacheGroups: {
react: {
test(module) {
// `module.resource` contains the absolute path of the file on disk.
return (
module.resource &&
module.resource.includes('node_modules/react')
);
},
chunks: 'initial',
filename: 'react.[contenthash].js',
priority: 1,
maxInitialRequests: 2,
minChunks: 1,
}
}
}
}
}
In this case will be created bundle that will contain only code of react package.
Many entries
Assume we have three entries like that:
We can move common code to separate bundle:
{
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /node_modules/,
chunks: 'initial',
filename: 'vendors.[contenthash].js',
priority: 1,
maxInitialRequests: 2,
minChunks: 3, // count of entries
}
}
}
}
}
Now our bundles may looks like that:
We didn't reduced size of javascript needed for page, but we reduced total size of bundles and now we can cache common bundle across pages, and it's cool!
That's it
Now you know how you can use the splitChunks to improve UX in your app, read documentation for more detais and try it out!
Thank you for reading! This is the first article of the series about web performance, click on the Follow
button to see future articles and motivate me to write them.
Follow me on Twitter: https://twitter.com/paulcodes_tech, there I'll share with you some tips and tools for Frontend developers.
Answer me in comments:
- Did this article was helpful?
- Do you like the pictures I provide?
- Will you try it out?
- Do you want me to provide a repository for this and future articles?
- Any other feedback :)
Top comments (0)