original post @ Linguine Blog
The problem with a huge bundle file size is the increase in TTI (time to interactive).
TTI is the result of how long does it take for the user to actually be able to use the application or site.
This is measured in time (milliseconds, seconds, minutes, etc).
Let’s take a look at CNN.com and throttle the network to a slow 3G.
You can also see the compressed size, the uncompressed size, and how long it took to be completed.
If we open on their cnn-footer-lib.min.js file, you’ll see that there is nothing minified about it.
And it looks like it contains a lot of the logic for the site in that 1 file.
99% of the time when you’re developing in React, you’re going to be using Webpack to help you bundle up everything into a nice package.
Your React files aren’t big, it’s actually some of the smallest. But as you install React, and other third party libraries that bundle output gets bigger.
And loading a 500kb file isn’t a pretty user experience.
To give a better user experience, we can do a technique called dynamic importing, also known as lazy loading.
Also known as lazy loading.
The concept of lazy loading our React JS files is really simple.
Load the minimal code to the browser that will render a page.
Load additional small chunks of code when needed.
In today’s example, I will be starting off from a previous article that explains how to get started with React router.
One thing to note, is that the previous work is using Create React App.
And Create React App has already enabled Webpack to perform code splitting.
The goal now is to utilize the code splitting capabilities, and lazy loading technique, and apply it to the React app.
Another reason I want to use a previous example is because I’m going to demonstrate how to do route base code splitting with React.
And I will be using React lazy and Suspense to load other React files as a user navigates through the application.
Before we jump into implementing the lazy load code, let’s do a quick recap of the current app.
Here are the current pages the cat application has.
I have 3 pages:
- A list of cats
- A form to add a cat name
- A single view for a cat
Let’s take a quick look at the current code.
The file above is a route configuration that just attaches a path to a page.
The next file is the App.js file that grabs the route configuration file and creates routes out of it.
Look at lines 31-44.
It goes through a map loop to create a React route component.
Now let’s take a quick look at the React developer tools and see how it looks at initial render.
React renders every page route. Even when we don’t need it at the moment.
Let’s take a quick look at the network tab for JS files.
The main.[name].chunk.js file is basic Webpack initial code. The big file size is the React cat application.
Our goal is to make our initial load smaller and load in chunks when needed.
Let’s start adding the code!
The first step I took, was to remove route.js file.
The second step was to modify the App.js file. Take a look at the highlighted areas only.
The highlighted areas shows where the code has changed a bit. Don’t worry I’ll break it down.
The first step I took to update the App.js file was in line 5.
I imported the Switch component from react router dom.
The Switch component is a unique React component, as it’s job is to only render a single route component.
You will never see more than one.
In the React developer tool image above, you might have seen 3 routes. Let’s take a look at the developer tool again to see how many routes will render.
And as you navigate through the application, only 1 Route will ever show.
This is helpful because there is no need to have additional code that doesn’t get used at that given time.
In line 8 to 10, I created a React lazy components for each page.
React lazy let’s you import dynamically a file and covert it into a regular React component.
Before I use my React lazy components, I’m going to add the React Suspense component as a wrapper.
React Suspense is another component provided from the React library.
The React Suspense component helps as a fallback option, to let your users know it’s loading.
This is due to how dynamic importing works.
If we take a look at the image above, I’ve given 2 different examples of using the keyword import.
Even though it looks like the same, it’s not.
The first import statement can only happen at the top of the file, and only accepts a literal string.
This is good for importing modules that you’ll need in your code file.
The second import example, uses parenthesis, as you would use in a function.
This let’s your code know that this will be treated asynchronously, and will return a promise.
Since dynamic importing is asynchronous, that’s where React Suspense comes into play.
Suspense will display the fallback option until the promise has completed.
This will happen as the user goes to each new page.
This is a fairly simple step.
Inside my Switch component I’m defining my routes, with a path, and the React lazy component that I want to use.
And I’m also passing properties down to each React lazy component, such my list of cats or a onSubmit handler function.
What I’ve managed to do is grab the entire app and split them into smaller chunks.
There is always going to be a main bundle JS file. But only 1 small chunk file will be downloaded.
As the user navigates through the app and discovers new pages, other small chunks will be downloaded.
This method makes it easy for the browser to process, and execute.
Smaller chunks of code equals faster TTI results (time to interactive).
Code splitting your React application will bring better performance, because it will only load the minimal code it needs to render a page.
Thus bringing a better user experience, and making your users happy.
Github code: React router with lazy loading