Angular is a great framework. It provides a lot of options to the users and it is upto the user to make use of it. Unlike React, Angular being a framework gives a lot functionalities out of the box like routing. So today, I am gonna write about a very common topic in Angular called Lazy Loading.

What is Lazy Loading?

Lazy loading is a technique in which you load some part of the web page at a later point of time when it is actually needed. But why do someone do that? Angular is a SPA (Single Page Application) meaning it has only a single page…all the other content on the DOM and rendered using JavaScript. I have also wrote a small article about How I got started with Angular where i try to explain How a person can start with Angular and some of the Good Angular Extensions for VS Code.

If your app is pretty big, and you have a single JavaScript bundle, then your app will probably a failure when in production. This is were you need lazy-loading. You should be splitting up the application into smaller bundles and then load these bundles when you need to.

Lazy Loading in Angular

In Angular, you don’t have to put in a lot of effort to implement Lazy loading. Everything is available out of the box. Implementation of lazy loading in Angular is easier than most of the people who doesn’t know about it. I will try to cover how I actually came to know about lazy loading and started using it in all the projects that I am working on.

By default all the modules in Angular will be bundled to a single main bundle JavaScript file. So when you open the application, it has to fetch that main.js file from the server. Internet is not always reliable or the speeds that you experience is not what most of the people actually get. So considering all these factors, If your main file is more than 1 MB, It will take time to load.

All this time till the bundle is downloaded and parsed, the web application shows nothing but a blank white screen. This is not good user experience. When it comes to websites or web-apps, the time taken to show the initial content is very critical. So improving the user experience by loading only the required piece of code is a good idea. When the user want to go to a new page, the JavaScript associated with that particular page can be downloaded from the server.

Now you might be thinking, how can I split code like mentioned? It is very simple and easy to implement and is a must when you are actually having a big application.


How to Lazy Load in Angular 7/8

The first thing you have to do before implementing lazy loading is to actually find and split the applications into smaller modules. Make sure to add only the necessary stuff in the main module and then later implement other parts of the application into its on modules.

We can use Angular CLI for creating feature modules with routing. So lets first look at the normal way of implementing a new page in an Angular application.

Example application

For the purpose of this tutorial, I am using Angular v7 since it is the LTS release at the time of writing the article. There is one breaking change in how we implement lazy loading. I’ll make sure that I cover that part too.

For this particular example, let me take an example of a streaming platform which will stream movies, series and music to its users. Let us assume that there are 4 main pages in the application:

  1. Home Page
  2. Movies Page
  3. Series Page
  4. Music Page

Normal Way of without Lazy-Loading

The normal approach that someone new to the concept would follow a pattern were they create 3 new components one for each of the pages and the Home page being the main page.

1. Generate the Application using the CLI

So the first thing is to generate a new application using the angular CLI:

ng new lazy-loading --routing
2.  Generate the Required Components

After that we can start by creating components for the pages:

ng g c pages/movies
ng g c pages/series
ng g c pages/music

Now we have the main App Component which will be the Home Page and then we have 3 pages which will be linked from the Header in the Home page.

3. Configure the Routes

The next thing we do is to add the routes so that we can navigate to these pages from the header. For that, we add the routes in the app-routing.module.ts file like so:


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MoviesComponent } from './pages/movies/movies.component';
import { SeriesComponent } from './pages/series/series.component';
import { MusicComponent } from './pages/music/music.component';

const routes: Routes = [
  {
    path: 'movies',
    component: MoviesComponent,
  },
  {
    path: 'series',
    component: SeriesComponent,
  },
  {
    path: 'music',
    component: MusicComponent,
  },
];

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

Now when we serve the application, we will be able to see that the application is now able to go to these pages when we navigate to the respective links.

Now lets build the application and see the output files that are being generate by the CLI. So we use the following command:

ng build --prod

Once the build process is completed, we can see that the files generated contains a main.js file. This file contains all the different components that we created in the same bundle.

The problem

Since only the home page will be shown to user when the application is first loaded and not the inner pages, there is no use in loading everything at once. It will increase the time the application takes to first load. The first load time is always important.

We should be able to show some kind of content to the users when they enter the web application. Instead if the user have to wait for few seconds to just see the landing page because we are loading all the related inner pages together with the main landing page the first time.

The Solution

The solution to the problem is lazy loading the inner pages once the user actually needs to see it. By this way we separate the main landing page code and the other pages. So the initial bundle size becomes less which means it can load faster which means the user will be able to see some content faster.


Implementing Lazy Loading in Angular 7 and 8

Angular 8 actually brought some breaking changes to how we implement lazy loading in Angular applications. In Angular 8, they have added a new syntax for importing feature modules lazily to the application. The changes is just in the way we write the piece of code.

Now that we have seen, how the example app is written without lazy loading, its time to create the same application with lazy loading.

Lazy Loading in Angular 8

1. Generate the Application using the CLI

So the first thing is to generate a new application using the angular CLI:

ng new lazy-loading --routing
2.  Generate the Required Components with Modules and Routing

The new thing in Angular 8 is that now we can create a feature module with its routing module and component all with a single command. Unlike in Angular 7 were we have to first create the feature module with routing and then create the component itself.

The command is like:

ng g m <module> --route <name_of_route> --module <feature_module_part_of_which_module>

Generate the movies module, routing and component

ng g m pages/movies --route movies --module app

Generate the movies module, routing and component

ng g m pages/series --route series --module app

Generate the movies module, routing and component

ng g m pages/music --route music --module app

Now if you check the main app-routing.module.ts file you can see something like below. Angular CLI automatically added the feature modules to be lazy loaded in the routing module of the application.

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


const routes: Routes = [
     { 
       path: 'movies', 
       loadChildren: () => import('./pages/movies/movies.module')
                           .then(m => m.MoviesModule) 
     },
     { 
       path: 'series', 
       loadChildren: () => import('./pages/series/series.module')
                           .then(m => m.SeriesModule) 
     },
     { 
       path: 'music', 
       loadChildren: () => import('./pages/music/music.module')
                           .then(m => m.MusicModule) 
     }
];

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

Also In the feature module’s routing file, you can see that a route is added, Lets take movie-routing.module.ts file:

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

import { MoviesComponent } from './movies.component';

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

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

Like so there will routes added to the series and music feature modules as well.

Now if you build your application and go to the routes, you can see that the bundles will be lazily loaded.


Lazy Loading in Angular 7

1. Generate the Application using the CLI

So the first thing is to generate a new application using the angular CLI:

ng new lazy-loading --routing
2. Generate the Feature Modules and Routing Files

In Angular 7, you have to create the feature modules and routing files first, and then create the component.

Now we need to create different module files and their corresponding routing files:

ng g m pages/movies --routing
ng g m pages/series --routing
ng g m pages/music --routing

Now we have the main App Component which will be the Home Page and then we have 3 pages which will be linked from the Header in the Home page.

3. Generate the Required Components

After that we can start by creating components for the pages:

ng g c pages/movies --module movies
ng g c pages/series --module series
ng g c pages/music --module music

I have added the –module flag so that the component will be declared in that mentioned module. You don’t have to specify it if the component and module is going to be in the same folder. The CLI automatically adds the component to the nearest module file.

4. Add Routes to the 3 Feature Modules

Now that we have 3 feature modules and 3 components, we need to setup routing in each of the feature modules like we would normally do in the app-routing file:

In the movies-routing.module.ts change the routes to this:

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

In the series-routing.module.ts change the routes to this:

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

In the music-routing.module.ts change the routes to this:

const routes: Routes = [
  {
    path: '',
    component: MusicComponent,
  },
];
5. Add Routes in the Main Routing Module

Now that we have setup all the feature modules and their routes, the main application is still left to do. Follow the method to add the feature modules to routes:

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

const routes: Routes = [
  {
    path: 'movies',
    loadChildren: './pages/movies/movies.module#MoviesModule',
  },
  {
    path: 'series',
    loadChildren: './pages/series/series.module#SeriesModule',
  },
  {
    path: 'music',
    loadChildren: './pages/music/music.module#MusicModule',
  },
];

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

Notice that normally we would use path and component in the routes array. Now instead we use loadChildren.

We specify the path of the module file and then put a ‘#’ and then Enter the name of the feature module class.

For Eg: I have movies.module.ts and the class of the module is MoviesModule, So the loadChildren string becomes :

./pages/movies/movies.module#MoviesModule

We have successfully implemented Lazy Loading in our small application.


What Changes in Lazy Loading

If you see the app-routing.module.ts file without lazy loading, the imports statements have:

import { MoviesComponent } from './pages/movies/movies.component';
import { SeriesComponent } from './pages/series/series.component';
import { MusicComponent } from './pages/music/music.component';

We are importing the component into the main application bundle. In the lazy loaded application, you will not be able to see the import statements, instead we specify the feature module using ```loadChildren``. This means that the JavaScript for the pages that we have here will not be part of the main bundle but instead will be on a separate file.

Now lets build the application and see the output files that are being generate by the CLI. So we use the following command:

ng build --prod
Bundle size comparison with and without lazy loading

Once the build process is completed, we can see that the files generated contains a main.js file and also some other .js files which was not there in the non lazy loaded angular application example.

Lazy Loading in Action

Let us see lazy loading in action and how it only loads the initial bundle. And when the other routes are clicked, you can see that their bundle is later downloaded separately.

Example without lazy loading
Angular application without lazy loading

If you see the Network panel, you can see that there is a main.js file which is loaded when the application is loaded. When you go to other routes, there is no other network requests made since everything is bundled together in the main bundle. You can see that the time it took for the main bundle to load is 60ms and the size is ~20KB.

Example with lazy loading
Angular application with lazy loading

In the case of lazy loaded example, the Initial load of the application downloads the main.js file which is only ~12KB in size. Later when we go to a route, the JavaScript associated with the route is downloaded from the server.

The difference that you see here is very less, but there is a difference. This will grow exponentially when the application grows. This load time is low since it is server locally.  But when the application is deployed, the load time will be much higher that this.

Final Thoughts on Lazy Loading in Angular

I think, I was able to give an idea about How to lazy load routes in Angular. If you are not doing this at the moment, I suggest you take some time and learn about it and start implementing it. It is a really good way to reduce the initial load time of the application.

If you need any kind of help or assistance or you just want to have chat, feel free to ping me on my socials.