Lazy Loading In Angular

Introduction 

The Angular creates SPA (Single Page Application), so all the components, modules, and other files are compiled in a single file and loaded at once. The unnecessary modules might get loaded as well. For example, if we created a single application for front-end and back-end office, then both the module files are get loaded even front-end office user get logged-in. Here, back-end office module files are unnecessarily downloaded. This is fine if our application is small and has limited functionality but for the large application, this will increase the initial load time for the application.  

Lazy loading feature allows loading components, modules, and other files of Angular application when required. This helps to keep the initial bundle size small, so the initial load time is decreased.

In Angular, every application made using at least one NgModule class that is root module of the application. The application is Bootstrapping using the root module. Angular app may have multiple modules based on the nature of the application. The root module or app module is created under /src/app.

The lazy load of the modules can be done using the root routing module. This loads the modules lazily using loadChildren method. The loadChildren can be defined using string or LoadChildrenCallback. In Angular 8.0, the string based loadChildren method was deprecated so, we have to use LoadChildrenCallback method. 

Step by Step Example,

Step 1: Create Angular App with Routing

If you are using Angular CLI, create Angular App using "--routing" flag

ng new LazyLoadingTestApp --routing

The above command creates Angular app with name "LazyLoadingTestApp" and here we have passed "--routing" flag, so "app-routing.module.ts" is also get generated that contains all routes. This file is used to define lazy loading for our feature module.

Step 2: Create feature module "FeatureModuleExample"

ng generate module FeatureModuleExample --route exp1 --module app.module

The above command creates "feature-module-example" folder that is new lazy-loadable feature module "feature-module-example.module.ts".

Step 3: Create Demo component inside the "feature-module-example"

ng g c .\feature-module-example\demoComponent

The above command creates the new component inside "feature-module-example" folder and registers this component inside "feature-module-example.module".

Step 4: Add Route for the new module

The "app-routing.module" contains all the routes required in the application. The lazy loaded module have their own route file, so lazy loaded module can be defined in main routing file using "loadChildren" method. 

There are two ways to define loadChildren method: dynamic import (LoadChildrenCallback) and string based.

The lazy loaded module is not referenced to the application root module so, we need to use browser's built-in import ('...') syntax for dynamic imports. 

const routes: Routes = [
  {
    path: 'demo',
    loadChildren: () => import('./feature-module-example/feature-module-example.module').then(m => m.FeatureModuleExampleModule)
  }
];

You might get the compilation error when you use dynamic import method. Change the "target" and "module" properties value to "esnext"  in tsconfig.json file.

{
	...
	"module": "esnext",
    "target": "esnext",
	....
}

The loadChildren method can specify with the string as well but this method was deprecated in Angular version 8. 

const routes: Routes = [
  {
    path: 'demo',
	loadChildren:'./feature-module-example/feature-module-example.module#FeatureModuleExampleModule'
  }
];

The Next step would be to create a separate route file inside the new module. Define all required routes for the new lazy loaded module inside Route array.

feature-module-example-routing.module.ts

import { NgModule } from '@angular/core';  
import { RouterModule, Routes } from '@angular/router';  
import { DemoComponentComponent } from './demo-component/demo-component.component';  

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

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

Step 5: Set up navigation link

You can either type the URL into browser's address bar or define navigation to load the component defined under lazy loaded module. Using the following code, we can add navigation to the app.component.html to load demo component.

app.component.html

Defining the lazy loaded module is almost done. Now, it's time to run the application. When we run the application and look at the network tab, only "main.js" file is get loaded. It does not contain HTML and code for feature module and demo component.

When we click on "lazy loading" link, angular routing module loads the feature module and its component as a single file to the user's browser.

When you create a build of your application, you can see two different main.js files: one contains the root modules and another contains the feature component

When we create the application the root route file (app-routing.module.ts), the CLI adds RouterModule.forRoot(routes) to the AppRoutingModule imports array. Using this, Angular comes to know that this is root routing module for the application. Angular allows using forRoot() only once in the application. The CLI adds RouterModule.forChild(routes) to feature routing modules. Using this, Angular comes to know that this is additional routes that need to load with feature module. 

Summary

Lazy loading feature allows to load components, modules, and other files of Angular application when required. This helps to keep the initial bundle size small, so initial load time is decreased. However, it required additional server trip to load the feature module. It is recommended to not use lazy loaded module if it is visited frequently by the user. 

You can view or download the source code from the GitHub link here