Angular is a frontend JavaScript framework developed by Google for building scalable enterprise-grade web applications. Some of these applications can get quite large, affecting the load time of your application.

To reduce load time and improve the overall experience of your users, you can use a technique known as lazy loading. This native Angular feature allows you to load only the required bits of the web app first, then load other modules as needed.

In this article, you will learn about lazy loading and how it can help speed up your web app.

What is Lazy Loading?

Lazy loading refers to the technique of loading webpage elements only when they are required. Its counterpart is eager loading, when everything loads — or tries to load — immediately. Fetching all images, videos, CSS, and JavaScript code eagerly might mean long load times — bad news for users.

Lazy loading is often used for images and videos on sites that host a lot of content. Instead of loading all media at once, which would use a lot of bandwidth and bog down page views, those elements are loaded when their location on the page is about to scroll into view.

Angular is a single-page application framework that relies on JavaScript for much of its functionality. Your app’s collection of JavaScript can easily become large as the app grows, and this comes with a corresponding increase in data use and load time. To speed things up, you can use lazy loading to first fetch required modules and defer the loading of other modules until they are needed.

Benefits of Lazy Loading in Angular

Lazy loading offers benefits that will make your site more user-friendly. These include:

  • Faster load time: JavaScript contains instructions for displaying your page and loading its data. Because of this, it’s a render-blocking resource. This means the browser has to wait to load all of the JavaScript before rendering your page. When lazy loading in Angular, the JavaScript is split into chunks that are loaded separately. The initial chunk contains only logic that is needed for the main module of the page. It is loaded eagerly, then the remaining modules are loaded lazily. By reducing the size of the initial chunk, you’ll make the site load and render faster.
  • Less data usage: By splitting the data into chunks and loading as needed, you might use less bandwidth.
  • Conserved browser resources: Since the browser loads only the chunks that are needed, it doesn’t waste memory and CPU trying to interpret and render code that isn’t required.

Implementing Lazy Loading in Angular

To follow along with this tutorial, you will need the following:

  • NodeJS installed
  • Basic knowledge of Angular

Step Up Your Project

You’ll use the Angular CLI to create your project. You can install the CLI using npm by running the command:

npm install -g @angular/cli

After that, create a project named Lazy Loading Demo like this:

ng new lazy-loading-demo --routing

That command creates a new Angular project, complete with routing. You’ll be working exclusively in the src/app folder, which contains the code for your app. This folder contains your main routing file, app-routing.module.ts. The structure of the folder should look like this:

Screenshot: The Angular folder structure displayed in a terminal.
The folder structure of an Angular project.

Create a Feature Module with Routes

Next, you’ll create a feature module that will load lazily. To create this module, run this command:

ng generate module blog --route blog --module app.module

This command creates a module named BlogModule, along with routing. If you open src/app/app-routing.module.ts, you will see it now looks like this:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [ { path: 'blog', loadChildren: () => import('./blog/blog.module').then(m => m.BlogModule) }];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { } 

The part that is important for lazy loading is the third line:

const routes: Routes = [ { path: 'blog', loadChildren: () => import('./blog/blog.module').then(m => m.BlogModule) }];

That line defines the routes. The route for the blog uses the loadChildren argument instead of component. The loadChildren argument tells Angular to lazy load the route — to dynamically import the module only when the route is visited, and then return it to the router. The module defines its own child routes, such as blog/**, in its routing.module.ts file. The blog module you generated looks like this:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BlogComponent } from './blog.component';

const routes: Routes = [{ path: '', component: BlogComponent }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class BlogRoutingModule { }

You will note that this routing file contains a single route, ''. This resolves for /blog and points to the BlogComponent. You can add more components and define those routes in this file.

For example, if you wanted to add a component that would pull details about a particular blog post, you could create the component with this command:

ng generate component blog/detail

That generates the component for the blog detail and adds it to the blog module. To add a route for it, you can simply add it to your routes array:

const routes: Routes = [{ path: '', component: BlogComponent },
                        {path:"/:title",component: DetailComponent}];

This adds a route that resolves for blog/:title (for example, blog/angular-tutorial). This array of routes is lazy-loaded and not included in the initial bundle.

Verify Lazy Loading

You can easily check that lazy loading is working by running ng serve and observing the output. At the bottom of your output, you should get something like this:

Screenshot: Output of Angular's ng serve command in the terminal.
Verifying lazy loading using Angular’s ng serve.

The output above is divided into two parts: Initial Chunk Files are the files loaded when the page first loads. Lazy Chunk Filesare lazy-loaded. The blog module is listed in this example.

Checking for Lazy Loading Through Browser Network Logs

Another way to confirm lazy loading is by using the Network tab in your browser’s Developer Tools panel. (On Windows, that’s F12 in Chrome and Microsoft Edge, and CtrlShiftI in Firefox. On a Mac, that’s CommandOptionI in Chrome, Firefox and Safari.)

Select the JS filter to view only JavaScript files loaded over the network. After the initial load of the app, you should get something like this:

Screenshot: Angular JavaScript files logged in Developer Tools.
Initial log of JavaScript downloads viewed in Developer Tools.

When you navigate to /blog, you will notice a new chunk, src_app_blog_blog_module_ts.js, is loaded. This means your module was requested only when you navigated to that route, and it is being lazily loaded. The network log should look something like this:

Screenshot: Updated view of Angular JavaScript files logged in Developer Tools.
Lazy-loaded module appearing in downloads logged by Developer Tools.

 

Lazy Loading vs Eager Loading

For comparison, let’s also create an eagerly loaded module and see how it impacts the file size and load time. To demonstrate this, you’ll create a module for authentication. Such a module might need to be loaded eagerly, as authentication is something you might require all users to do.

Generate an AuthModule by running this command in the CLI:

ng generate module auth --routing --module app.module

That generates the module and a routing file. It also adds the module to the app.module.ts file. However, unlike the command we used to generate a module last time, this one doesn’t add a lazy-loaded route. It uses the --routing parameter instead of --route <name>. That adds the authentication module to the imports array in app.module.ts:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AuthModule //added auth module
  ],
  providers: [],
  bootstrap: [AppComponent]
})

Adding AuthModule to your AppModule imports array means the authentication module is added to the initial chunk files and will be included with the main JavaScript bundle. To verify this, you can run ng serve again and observe the output:

Screenshot: Angular scripts after authentication module is added.
Output of Angular’s ng serve command after authentication module is added.

As you can see, the authentication module is not included as part of the lazy chunk files. Additionally, the size of the initial bundle has increased. The main.js file almost doubled in size, increasing from 8 KB to 15 KB. In this example, the increase is small, since the components don’t contain much code. But, as you fill the components with logic, this file size will increase, making a strong case for lazy loading.

Summary

You’ve learned how to use lazy loading in Angular to fetch modules only when they are required. Lazy loading is a great technique to improve load times, reduce data usage, and better utilize your frontend and backend resources.

Lazy loading, along with technology like content distribution networks and minifying JavaScript, will improve both your website’s performance and your users’ satisfaction.

If you’re developing a WordPress site and want to really crank up the speed, read about Kinsta Edge Caching to see some impressive numbers.

Michael Nyamande

A digital product manager by day, Michael is a tech enthusiast who is always tinkering with different technologies. His interests include web and mobile frameworks, NoCode development, and blockchain development.