8/20/22

Improve User Experience with React Code Splitting and Lazy Loading Routes

When building single page applications, SPA. The application load time performance is very important as this improves the user experience. As development teams mostly focus on functional requirements, there is a tendency to skip some of the non-function requirements like performance improvements. The result is that when a web application is loaded, all the resources including views that are not visible on the home page are downloaded in a single bundle. This is referred as eagerly loading, and this approach often causes a slow load time as all the resources need to be downloaded before the user can interact with the application.


ozkary-lazy-loading-routes

To avoid this performance issue, we want to only load the resources that are needed at the time that the user is requesting it, on demand. As an example, only load the resources for the home page without loading other page resources, thus improving the load time. This is usually called lazy loading. To support this, we need to load chunks of the application on demand.  A chunk is basically a JavaScript or CSS file that packages only the containers, components and dependencies that are needed for that view to render.

To lazy load the different views for an application, we need to implement the concept of Code Splitting, which basically enables us to split the code bundle into chunks, so each container view and dependencies can be downloaded only as the user is requesting it. This greatly improves the app performance because the chunk size is small compared to the entire code bundle.

Importing Container Views and Routing

A simple yet very important approach to improve load time performance is to lazy load the routes. This is a code split process, which breaks down each container view into a separate chunk. In addition, components within these containers can also be lazy loaded to break down further the size of each chunk.

To get started, let’s look at what the navigation configuration of React application looks like, so we can review what takes place when a user loads the application.

ozkary-react-container-views

In this example, we should notice that our React app has three main containers, which are basically the pages or views that the user can load from the app.  These containers are usually in the container folders of the project file structure. This path is important because it is needed to associate them to a route.

👍 Pro Tip: It is a best practice to plan your folder structure and create a folder for each container, components, elements, and services.

To loads those views, we need to import them and map them to an application route. This should be done on the application starting point, which should be the App.tsx file. The code to do that looks like this:

In this code, we are using the import directives to load each container view. Each of those views is then mapped to an application route directive. When using import directives, there is no optimization, so we should expect that when this app loads on the browser, all the views should be loaded in a single bundle. To clearly see this, let’s use the browser dev tools to inspect how this look at the network level.


ozkary-app-loading-single-bundle


By doing a network inspection, we can see that there is a bundle.js file. This file has a 409kb size. In the example of a simple app, this is not bad at all, but for real world apps, this bundle size may be much bigger than that, and eventually it impacts the load time. A benefit of using a single bundle is that there are no additional trips to download other file chunks, but this approach will not let your application scale and perform acceptably over time.

Lazy Loading Container Views

Now, we should be able to understand that as the app continuous to grow, there is potential performance challenge, so the question is how can be optimized the loading of our application? The simple answer is that we need to Code Split the bundle into smaller chunks. A quick approach is to Lazy Loading the routes. This should enable us to improve the load time with very small code changes. Let modify our previous code and look at the performance difference.

In the updated version of our code, we are now using the lazy direct to delay the import of the container view only when the user requests that route. The rest of the code remains the same because we are still using the same container references and mapping them to a route. OK, let’s run the app and do another network inspection, so we can really understand the improvement.


ozkary-app-lazy-loading-routes


In this last trace, we can see there still a bundle file with roughly the same size of the file as before. This bundle file contains the optimization code to map a route to a particular bundle chunk. When a particular route is loaded, home route is loaded by default, the chunk for that view is downloaded, notice the src_container_Home_index_tsx.chunk.js. As the user navigates to other routes, the additional chunks are downloaded on demand, notice the Analytics and Admin chunks.

Final Thoughts

With this simple app, we may not be able to truly appreciate the optimization that has been done by just deciding to lazy load the containers. However, in real-world applications, the size of a single bundle will quickly get big enough to impact the usability of the application as users will have to wait a few or several seconds before the app is clickable. This is referred to as Load Time.

In addition, build tools for framework like React show performance warnings when loading the application in the development environment, as it tracks some performance indicators like load time. Also, it is a good practice to use a tool like Lighthouse, in the browser dev tools, to run a report and measure performance indicators like load time, render time and others.

ozkary-app-performance-report


👍 Pro Tip: Always use a performance tool to measure performance and other industry best practices for web applications.

With a bit of performance planning, we can feel confident that we are building an app that will scale and perform as additional business requirements are added, and the app will provide a much better user experience by improving the overall load time.

Send questions or comments at Twitter @ozkary

Originally published by ozkary.com