#9 Step By Step: Split Chunks Plugin
Friday, October 26, 2018
In this article we will go over how to separate out the code that we write from the third party code that typically lives within the node_modules folder. We will start off by putting all of this third party code into a single bundle and we will end by seeing how we can take out specific parts and place them in their own bundle.
Add some packages
- WebUi
- package.json
In order for us to see how the split chunks plugin works we need to include some npm packages to add to our bundles. For demonstration we will add a couple of react packages and lodash (a). As usual the version numbers of the packages, as of this writing of this article, are shown in (b).
Terminal
npm install --save-dev
@types/lodash
@types/react
@types/react-dom
lodash
react
react-dom
package.json
{
"devDependencies": {
...
"@types/lodash": "^4.14.117",
"@types/react": "^16.4.8",
"@types/react-dom": "^16.0.7",
...
"lodash": "^4.17.11",
"react": "^16.4.2",
"react-dom": "^16.4.2",
...
}
}
Adding our own code
- WebUi
- Source
- pages
- page-1.page.tsx
- page-2.page.tsx
- pages
- Source
In addition to third party code most application will also require code that we write ourselves. To demonstrate the splitting of code we are going to create two react pages that are very similar. The first (c) and second (d) both contain the same code with a little extra in page 1.
page-1.page.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";
import { filter } from "lodash";
ReactDOM.render(
<h1>Page 1</h1>,
document.getElementById("root")
);
const examples = ["one", "two"];
console.log(filter(examples, (e: string) => {
return e === "one";
}));
page-2.page.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";
ReactDOM.render(
<h1>Page 2</h1>,
document.getElementById("root")
);
Updating our webpack configuration
- WebUi
- webpack.config.js
The first changes to our configuration that we will make is to add the entry points for both of our pages (e). And since we are using react in our project we need to update our webpack configuration so that in addition to regular typescript files we are also passing react pages to the typescript loader.
webpack.config.js
...
const entry = {
"page-1": ["./Source/pages/page-1.page.tsx"],
"page-2": ["./Source/pages/page-2.page.tsx"]
};
...
const _module = {
rules: [
...,
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
"ts-loader"
]
}
]
};
...
With that done we are now ready to create our bundles using as usual the npm run build:prod
command. When webpack is done we should see the output shown in (f). The importing
thing to note is that the way the bundles are created now requires that all the necessary react code has to be present
in both bundles. And of course the code needed for our lodash call is included in the page 1 bundle.
Split chunks to the rescue
- WebUi
- webpack.config.js
There are several reasons that we would not like to have all of the react code in every bundle that we create. One of them for example is it severely impacts our ability to cache bundles. When compared to our code the third party code that we use is probably updated far less frequently but every time we update our code then a new bundle will be generated and then the user will have to re-download a lot of code that has not changed. To fix this we again need to update our webpack configuration file by adding a new optimization object (g).
webpack.config.js
...
const optimization = {
splitChunks: {
cacheGroups: {
commons: { test: /[\\/]node_modules[\\/]/, name: "common", chunks: "all" }
}
}
};
...
module.exports = {
...
optimization,
...
}
With that done we we once again create our bundles we should see the output shown in (h).
What is happening here is that we have specified a test that looks for code that comes from the node_modules
folder and if any is found it should be placed in a bundle with the name common
.
For the vast majority of projects that I have worked on this would be sufficient but every once in a while a little more splitting is required.
It does not have to be all third party in one bundle
- WebUi
- webpack.config.js
In addition to just splitting the code on whether it lives in the node_modules
folder
we can go further. Very rarely I have had the need to separate out a specific set of third part code which we can demonstrate
here with the react code we are importing. What we want to do is keep our page 1 and page 2 bundles but instead of having
a monolithic common bundle we will create a bundle for react and then a bundle for everything else in the
node_modules
folder (i).
webpack.config.js
...
const optimization = {
splitChunks: {
cacheGroups: {
react: { test: /[\\/]node_modules[\\/]((react).*)[\\/]/, name: "react", chunks: "all" },
commons: { test: /[\\/]node_modules[\\/]((?!react).*)[\\/]/, name: "common", chunks: "all" }
}
}
};
...
Once again after re-creating our bundles we should see the output shown in (j).