In this article, we will discuss how lazy loading works and differs in both Angular and React applications. We will not be discussing the various features of Angular or React, nor will we cover the setup necessary for spinning up an application with either of these technologies.

We will, however, bootstrap the applications rather quickly (using their respective CLIs) and then move on to the crux- lazy loading. This is not an Angular vs React article, this is simply a comparison of how the same result (of lazy loading components) can be achieved using both the frameworks.

What is Lazy Loading?

Lazy Loading is the technique in which we load additional payload only when necessary. The easiest analogy for Lazy Loading is loading the signup related JS, CSS, and HTML only when the user clicks on the signup button. After all, it’s a relatively lesser used part of most applications compared to something like login or home page. To make the initial page load faster and for the overall improvement of the applications structure and hierarchy. We can split the application into logic chunks which can be loaded on demand.

What we will build

For the sake of simplicity, we are going to build parts of a simple website which has a home page and then two lazy loaded sibling routes — about and settings . We will load the about and the settings page on user navigation. Within the settings view, we will further load lazy load sub-components based on user interactions, in this case, a button click. The goal here is to see how both the frameworks allow us to achieve the same result.

Angular Lazy Loading

Assuming you have the angular-cli installed, setting up the project and a few of the components should be a breeze. Follow the commands below:

ng new angular-lazy-loaded cd angular-lazy-loaded ng generate module about --routing ng generate module settings --routing ng generate component home ng generate component about/main ng generate component settings/main

That sets up our three basic routes which we will be using. From the commands above, the home component does not have to be a module with routing configuration attached unlike the about and the settings modules. We will load the home component when the application loads, for which, we can set up the entire application routing as shown below.

For the basic route based lazy loading, we can simply define the route with the modules that we created for the about and settings routes. The HomeComponent loads by default when the application loads the default route.

Another thing to notice is that we added a main component to both the settings and the about routes. Let us include the main component into both of these modules so that they are loaded by default when the user navigates to either of these routes. Some code has been omitted to keep the article brief but please refer to the full code base for reference.

When we start the app with the cli and add some basic styles to the template to load the application, we see output for the lazy loaded routes as shown below:

The main and vendor javascript files are loaded when the page initially loads (and renders the HomeComponent ). The about and settings modules (and their MainComponents ) are only requested and rendered when the user tried to navigate to those routes.

The payloads that we see above are larger than expected as it is not the production build. We will test the same functionality with the production build later.

Until now, we have loaded components on demand via route, let us now try to lazy load components on pre-rendered routes via other user interactions. To illustrate, we will be editing the user profile on click of the edit button in the settings page. The settings page is already lazy loaded, we are now lazy loading another part of this page when the user clicks the edit button.

This is where things become a little muddy with Angular. In Angular, the main focus of the application hierarchy is around modules and not components. The modules (which include components, services, pipes etc), if imported in the main module, either directly or indirectly via the dependency tree, get packaged into the main bundle. If not, the modules get bundled as chunks and are available as lazy loaded modules.

To enable loading a component lazily, we have to bundle it as a module which is chunked and loaded when a request is made for it. There is no other way in which we can lazy load an Angular component without relying on routes and modules. To set up the necessary components as discussed, run the following commands:

ng generate module settings/main/edit-profile --routing ng generate component settings/main/edit-profile/edit

These commands would set up the necessary sub module (to which we will route) and the component for the edit part of the settings page.

To load these changes, we would have to set up our settings routes with lazy loading child component as shown below:

Everything seems as expected, we have added the new outlet property indicating where we want the component to be rendered (within the settings html page) and the loadChildren property indicating that it would be lazily loaded. Unfortunately, because of a bug in angular, the parent of a named router outlet cannot be ‘’ , therefore, we introduce a temp route in between which is just redirecting to our MainComponent when the parent route is loaded. The corresponding change on the settings template to load this lazy component would be as follows:

With that, we are ready to rock and roll. Let us run the application again and try to navigate between the routes. The outcome would be similar to what you can see below.

Lazy loading increases the number of requests that are sent to the server for loading the necessary files. This means it is up to us to inform the user if any of the lazy loading requests, take too long, fail or are rejected. It would also be nice to handle these situations and show a loading indicator when the requests take too long to resolve.

There are several way of achieving this in Angular, the simplest way however would be to tie the lazy loading route event with some sort of loading indicator. Angular provides RouteConfigLoadStart and RouteConfigLoadEnd events which are trigged exclusively when a lazy loaded route begins loading and ends loading. We can use these events and set up a listener on our requesting settings module’s main component as shown below:

and the template:

This functions as expected when the server is rerun

The problem, however, arises when there are multiple lazy loaded components. We will have to add further checks on the event within our subscribe method to determine which request is on going and show the corresponding loading message/indicator.

Analysis

Although it works as expected, you may be a little confused and that’s fair. Angular has not made it particularly easy to understand how to lazy load components. Everything is tied to modules and our ability to lazy load the modules via routes. The presence of bugs/workarounds is not ideal either.

With our changes now complete, let us compress the build and test these changes again to analyze the payload size.

This is what our final bundled application loads. The last three chunks are our lazily loaded modules. Mind you, they are all pretty lean code wise — each containing only a few statements. The majority of our code changes were around setting up the necessary routing.

There are other areas of comparison such as Server Side Rendering but we will tackle that in a later article.

Full code base for angular lazy loading.

React Lazy Loading

Before jumping into lazy loading in react applications, let us quickly spin up a new React application using create-react-app . Since React handles only the view portion of the application, we need to add additional dependencies to handle other parts of the application. We will use react-router and react-loadable for loading our routes and enabling lazy loading so let us install them.

npm i -S react-loadable react-router react-router-dom

We are going to follow the same example as above, our application is made up of 3 routes, home , about , and settings . Home loads on the default route when the application loads. About and settings routes are lazy loaded. Within settings , we will further have lazy loaded components for edit of user profile on click of a button.

Our initial version of all the components are very lean and straight forward, similar to the component shown below:

We will now use the router to load the components on page navigation. Let us set up the router in our main app.jsx to facilitate the routing as shown below:

When we run the app, everything works as expected. We are able to click the links and navigate to the respective views.

Next comes the important step- setting up lazy loading. In this example, we are using react-loadable . It is an amazing library which comes with a wide range of features out of the box. In fact, below is the image which is available on their readme illustrating their recommendation on how lazy loading should work.

It is very clear from the image above that react-loadable wants to enable us to split the chunks by functional components rather than based on a certain route. Let us first enable route based lazy loading using react-loadable and then add further logic in our settings page to load the edit component lazily.

React-loadable internally is an extension of what webpack does along with added syntactical sugar so that we don’t need to fret about all the edge cases and the boilerplate code.

The code change is relatively easy and straight-forward to understand. Simply add an index.jsx file alongside your current component and use react-loadable to import it on demand.

We can then invoke this LazySettings component instead of the regular Settings component to enable lazy loading. The result is our lazy loaded components being loaded on route navigation.

Lastly, we will add the button to settings page which will load the sub component to edit the user profile. For that, we need to update our settings component to a stateful component which can load the LazyEditProfile component that we are yet to create.

and the LazyEditProfile component is similar to all the other lazily loaded components:

Some of the code has been omitted for brevity. Please refer to the full code base for the complete implementation.

The result as expected loads the components lazily.

Analysis

The usage, installation and setup is very easy in React when compared to Angular. The functionality is component centric and it gives you complete control of how to load the components.

A production build for payload analysis shows us the following payload sizes of the chunks:

Conclusion

In my personal opinion, lazy loading with React feels a lot more natural and easy from a developer stand-point. Maybe there are further optimizations and changes that can be made to make the overall development easier and faster, but as things are right now, react-loadable definitely has the edge.

Complete code base: react lazy loading app, angular lazy loading app.