Loading time is one of the key metric for any web application these days. There are several optimization techniques exist to help with reducing page load time. If you are using Webpack, you can make use of tools that come in-built to improve page loading time.
In this article, we are going to see how to do code splitting using webpack. Let’s start!
What we are building?
We are building an imaginary web application, with a landing page and button. When the user clicks on the button, we are going to load a dynamic form. In real word, this form could be your big application.
The problem here is, the form we are loading could be huge. We need to show this form only when the user clicks on the button.
But, Without code splitting, we are loading the entire bundle, even for the user’s who may not even click the button. That’s bad!
So, let’s optimize this: let’s split landing page bundle and form bundle, and load the form bundle only when the user clicks on the button.
Setting up Webpack
First, we need a project and a working webpack setup. To do this, run the below commands in one of your working directory.
Once the dependencies are installed, open this project in any of your favorite IDE (I used IntelliJ). Now create folders
dist that will be our source and output folders. Also, create a file named
webpack.config.js in the root of your project. Finally, your structure will look something like this:
Now, use the following webpack configuration to get our project built through webpack.
With this simple configuration, webpack takes the source files from
./src/index.js and outputs them to
dist folder. Now, lets create two files:
index.js - our landing page and
form.js - our dynamically loaded form.
In our landing page, we are statically importing
form.js on load itself and attaching an event to the button. When the button is clicked, we are rendering the form contents to our page (Note: for simplicity, I am using methods like
appendChild to create dynamic elements on page. For production, you should consider frameworks such as React, Vue which are really good at UI construction).
Our imaginary application
form.js is very simple: It constructs three form fields dynamically and returns them. Again, don’t use
createElement to construct dynamic UI in production code. Use any frameworks.
Above is the HTML file that houses our application. For brevity, the style part is stripped out.
With all the above files created, the final directory structure will look like this:
Bundling our project
Now when you run
webpack, you will webpack is emitting one single bundle that has both our
form.js. And this single bundle weighs 545 KB which is bad and webpack itself complains about it via the comment [big].
Code splitting using Dynamic imports
Webpack supports dynamic imports via
import(). With this, webpack will be able to dynamically load a bundle at run time. But in order to use this, we need to setup babel first, as dynamic imports syntax is not supported out of the box now. We also need Syntax Dynamic Import babel plugin.
1. Install Babel and Configure webpack to use babel loader for JS files.
2. Configure Babel to use Syntax Dynamic Import
.babelrc file at the root of your project.
Once you have babel setup, now it’s time to setup webpack to use dynamic imports. To do this, let tell webpack to emit named chunks. Modify the
output options in
webpack.config.js as below:
And modify our landing page
index.js to use dynamic imports instead of static import.
Notice that we have removed
import form from "./form.js" line and moved it inside the event handler function of our button. We dynamically import this module via
import(/* webpackChunkName: "form" */ './form') statement. This will return a
Promise which will receive the dynamically loaded module as its param once its resolved. Inside the Promise callback, you can use the dynamically loaded module anyway you want.
Note: You need to access your exported values from the dynamically loaded module as
module.default(earlier, it was just
module). Also, in
index.html, load your modules as
/index.bundle.js, instead of
With this setup, now if you run
webpack, you will see webpack generated two modules
And, if you notice, now our landing page
index.bundle.js size is only 6.14 KB, which is a great reduction from the original size of 546 KB. Since we will load only the
index.bundle.js upon page load, our app will be very fast on the initial load. Hurrah!
To prove this, let’s measure our app performance with Lighthous for both pre and post optimization.
As you can see, with this simple setup, we are saving around 700ms of page load time. Our site loads and become interactive faster, which is a win! 🎉