original post @ Linguine Blog
JavaScript is fast. But before it becomes fast, your browser has to do a lot of work before it serves your fast JavaScript application.
One of the bottlenecks for JavaScript is the bundle size.
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.
In each row you can see the JavaScript file being downloaded and executed.
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.
React + Webpack = 1 big bundle 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.
Webpack at it’s core, is meant to help hot reload during development, and bundle all your JavaScript files into 1 or multiple JS files.
But if you’re developing React, you’re typically aiming for a single page application, which you’ll typically have 1 JavaScript bundle file.
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.
Benefits of Lazy loading React components
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.
By loading less JavaScript code to the browser, that will default to better performance and better TTI results.
The concept of lazy loading may apply to any JavaScript application, but for the sake of simplicity will keep it to React talk.
Code splitting with React
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.
I only want to load the JavaScript code that is needed to render a page, at that given time.
And I will be using React lazy and Suspense to load other React files as a user navigates through the application.
Lazy loading with React Suspense and React lazy
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!
Adding lazy loading to React router
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.
Step 1: Import React router Switch component
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.
Step 2: Create React lazy Components
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.
Step 3: Use React Suspense 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.
So what is dynamic importing?
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.
The promise in this case, is that a JavaScript file (React file) has been loaded and executed by the browser.
This will happen as the user goes to each new page.
Step 4: Add our React lazy component to a route
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.
The result
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).
Conclusion
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
Top comments (5)
That was a delight to read. Can you please write about suspense in details
Here you go sir. Hope this article helps.
linguinecode.com/post/how-react-su...
Okay, sounds good
Deep and clearly explained even for a beginner!
Thanks guy ;)
Thank you Florian