Lazy loading with Angular 16
We will implement lazy loading in our Web Application .
For this we will use the Angular javascript framework version 16.2.3
Angular will allow us to load modules on demand.

What are we going to do
We will configure Lazy loading in our Web Application with Angular version 16.2.3
This is step 3 of our Angular guide which will allow us to obtain a PWA type Web Application .
We will use an existing project whose characteristics are
- Generated with Angular CLI
- Routing
All sources created are indicated at the end of the tutorial.
The application is at the following address
Before you start
The speed at which a website is displayed is one of the most essential criteria for the user.
And this speed is measured in seconds.
Beyond 3 seconds 57% of users simply leave the site.
What methods or techniques should we use to make our website load quickly?
One of the techniques is lazy loading (“lazy or lazy loading” in French).
It has the effect of speeding up the operation of a website.
It allows you to specify which parts of a website should be loaded on startup.
Theory
Before going any further we need to understand how Angular works.
The command that interests us concerns the compilation of our project.
In our package.json file this is the command
- ng-build
Without going into details this command uses Webpack (a bundler module).
Thanks to Webpack angular uses the files of our project, compiles them to generate in the dist directory a number of files that we can deploy on a web server.
The project which serves as our basis has 6 web pages
- Home
- About
- Contact
- Login
- sign-up
- not found
The compilation of our source code generates a main.js file which contains the code of these 6 pages (or a main.xxxxxxx.js type file)
To check this theory just open the dist/angular-starter/main.js file do a search on the code used in each of the 6 pages
- home works! (code used in home.component.html)
- not-found works! (code used in not-found.component.html)
- contact works! (code used in contact.component.html)
- login works! (code used in login.component.html)
- signup works! (code used in signup.component.html)
- about works! (code used in about.component.html)
This file and others will be called when displaying the website.
The greater the number of pages, the larger the file and the slower the display.
The principle of lazy loading will consist of splitting this file into several parts which will only be loaded in due time.
So let's move on to practice.
Creation of the project
Rather than recreate everything we will use a project which contains the routing.
I give you the commands to run, Git is obviously mandatory to retrieve the source code.
# Créez un répertoire demo (le nom est ici arbitraire)
mkdir demo
# Allez dans ce répertoire
cd demo
# Récupérez le code source sur votre poste de travail
git clone https://github.com/ganatan/angular-react-routing
# Allez dans le répertoire qui a été créé
cd angular-react-routing
cd angular
# Exécutez l'installation des dépendances (ou librairies)
npm install
# Exécutez le programme
npm run start
# Vérifiez son fonctionnement en lançant dans votre navigateur la commande
http://localhost:4200/
Practical
Lazy loading works using the concept of modules and no longer that of components.
We will use the Angular documentation to apply this technique.
https://angular.io/guide/lazy-loading-ngmodules
We will adapt our architecture, by creating a module for each element to display.
Home and not-found will remain managed in the classic way as components.
Let's use the ng generate module command that angular-cli offers us.
# Création des modules (méthode 1)
ng generate module modules/general/contact --routing --module=app
ng generate module modules/general/login --routing --module=app
ng generate module modules/general/signup --routing --module=app
ng generate module modules/general/about --routing --module=app
# Création des modules (méthode 2)
ng g m modules/general/contact --routing --module=app
ng g m modules/general/login --routing --module=app
ng g m modules/general/signup --routing --module=app
ng g m modules/general/about --routing --module=app
The files needed for each component are created automatically.
For example for the Contact component
- contact-routing.module.ts
- contact.module.ts
The app.module.ts file is automatically modified as follows.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { ContactComponent } from './modules/general/contact/contact.component';
import { AboutComponent } from './modules/general/about/about.component';
import { LoginComponent } from './modules/general/login/login.component';
import { SignupComponent } from './modules/general/signup/signup.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';
import { MailingComponent } from './modules/general/contact/mailing/mailing.component';
import { MappingComponent } from './modules/general/contact/mapping/mapping.component';
import { WebsiteComponent } from './modules/general/contact/website/website.component';
import { ContactModule } from './modules/general/contact/contact.module';
import { LoginModule } from './modules/general/login/login.module';
import { SignupModule } from './modules/general/signup/signup.module';
import { AboutModule } from './modules/general/about/about.module';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ContactComponent,
AboutComponent,
LoginComponent,
SignupComponent,
NotFoundComponent,
MailingComponent,
MappingComponent,
WebsiteComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ContactModule,
LoginModule,
SignupModule,
AboutModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
We need to make some changes to the following files.
- app-routing.module.ts
- app.module.ts
- about-routing.module.ts
- about.module.ts
- contact-routing.module.ts
- contact.module.ts
Lazy loading will be applied to Contact, About, Login and Signup
At the AppRoutingModule level, we need to update the routes using loadchildren.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
const routes: Routes = [
{ path: '', component: HomeComponent, },
{
path: 'contact',
loadChildren: () => import('./modules/general/contact/contact.module')
.then(mod => mod.ContactModule)
},
{
path: 'about',
loadChildren: () => import('./modules/general/about/about.module')
.then(mod => mod.AboutModule)
},
{
path: 'login',
loadChildren: () => import('./modules/general/login/login.module')
.then(mod => mod.LoginModule)
},
{
path: 'signup',
loadChildren: () => import('./modules/general/signup/signup.module')
.then(mod => mod.SignupModule)
},
{ path: '**', component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
declarations: []
})
export class AppRoutingModule { }
We need to modify the AppModule module and leave only the HomeComponent and NotFoundComponent components
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
NotFoundComponent
],
imports: [
BrowserModule,
AppRoutingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
All that remains is to modify the routing and module files for Contact, Login, Signup and About.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './about.component';
const routes: Routes = [
{ path: '', component: AboutComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AboutRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AboutComponent } from './about.component';
import { AboutRoutingModule } from './about-routing.module';
@NgModule({
imports: [
CommonModule,
AboutRoutingModule
],
exports: [
AboutComponent
],
declarations: [
AboutComponent
],
providers: [
],
})
export class AboutModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';
const routes: Routes = [
{ path: '', component: ContactComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ContactRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ContactComponent } from './contact.component';
import { ContactRoutingModule } from './contact-routing.module';
@NgModule({
imports: [
CommonModule,
ContactRoutingModule
],
exports: [
ContactComponent
],
declarations: [
ContactComponent
],
providers: [
],
})
export class ContactModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SignupComponent } from './signup.component';
const routes: Routes = [
{ path: '', component: SignupComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SignupRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SignupComponent } from './signup.component';
import { SignupRoutingModule } from './signup-routing.module';
@NgModule({
imports: [
CommonModule,
SignupRoutingModule
],
exports: [
SignupComponent
],
declarations: [
SignupComponent
],
providers: [
],
})
export class SignupModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login.component';
const routes: Routes = [
{ path: '', component: LoginComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LoginRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoginComponent } from './login.component';
import { LoginRoutingModule } from './login-routing.module';
@NgModule({
imports: [
CommonModule,
LoginRoutingModule
],
exports: [
LoginComponent
],
declarations: [
LoginComponent
],
providers: [
],
})
export class LoginModule { }
Verification
To verify the lazy loading theory we must perform a new compilation (npm run build)
In the dist/angular-starter directory this time we obtain 5 files
- main.js
- modules-general-about-about-module.js
- modules-general-contact-contact-module.js
- modules-general-login-login-module.js
- modules-general-signup-signup-module.js
Noticed:
The names can be different, especially with numbers; webpack manages the naming.
The code for each of our 5 pages is now arranged as follows:
- home works! (code found in main.js )
- not-found-works! (code found in main.js )
- contact works! (code found in modules-general-contact-contact-module.js )
- login works! (code found in modules-general-login-login-module.js )
- signup works! (code found in modules-general-signup-signup-module.js )
- about works! (code used modules-general-about-about-module.js )
If we run the application (npm run start) we can see in Chrome (F12) at the Network tab how the files are loaded.
- When launching the site: main.js is called.
- When About is selected: modules-general-about-about-module.js is called only once
- When selecting login: modules-general-login-login-module.js is called only once
- When selecting signup: modules-general-signup-signup-module.js is called only once
- When Contact is selected: modules-general-contact-contact-module.js is called only once
If we launch the url localhost/contact
- In this case main.js and only modules-general-contact-contact-module.js are called
Conclusion :
Regardless of the number of pages, the main.js file will always be the same size.
Launching the site that loads the main.js file will always be done at the same speed.
Child Routes
This application also contains the management of Child routes.
This issue is discussed in the documentation
https://angular.io/guide/router#child-route-configuration
You will find in the repository on github the addition of the concept of routing with Children.
In the routing tutorial, three components have been added to Contact
- mailing
- mapping
- website
We need to add the notion of modules to these components.
7 files will be modified in particular to take this into account.
- contact-routing.module.ts
- mailing-routing.module.ts
- mapping-routing.module.ts
- website-routing.module.ts
- app.module.ts
# Rajout du module mailing
ng generate module modules/general/contact/mailing --routing --module=app
# Rajout du module mapping
ng generate module modules/general/contact/mapping --routing --module=app
# Rajout du module website
ng generate module modules/general/contact/website --routing --module=app
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';
const routes: Routes = [
{
path: '', component: ContactComponent, children: [
{
path: '',
loadChildren: () => import(`./mailing/mailing.module`)
.then(mod => mod.MailingModule)
},
{
path: 'mailing',
loadChildren: () => import(`./mailing/mailing.module`)
.then(mod => mod.MailingModule)
},
{
path: 'mapping',
loadChildren: () => import(`./mapping/mapping.module`)
.then(mod => mod.MappingModule)
},
{
path: 'website',
loadChildren: () => import(`./website/website.module`)
.then(mod => mod.WebsiteModule)
},
{
path: '**',
loadChildren: () => import(`./mailing/mailing.module`)
.then(mod => mod.MailingModule)
},
]
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ContactRoutingModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MailingComponent } from './mailing.component';
const routes: Routes = [
{ path: '', component: MailingComponent, children: [] }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MailingRoutingModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MappingComponent } from './mapping.component';
const routes: Routes = [
{ path: '', component: MappingComponent, children: [] }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MappingRoutingModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { WebsiteComponent } from './website.component';
const routes: Routes = [
{ path: '', component: WebsiteComponent, children: [] }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class WebsiteRoutingModule { }
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
NotFoundComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Tests
All that remains is to test the application.
# Développement
npm run start
http://localhost:4200/
# Tests
npm run lint
npm run test
# Production
npm run build
Source code
The source code used at the start of the tutorial is available on github
https://github.com/ganatan/angular-react-routing
The source code obtained at the end of this tutorial is available on github
https://github.com/ganatan/angular-react-lazy-loading
The following steps will allow you to obtain a prototype application.
- Step 4: Bootstrap with Angular
- Step 5: Modules with Angular
- Step 6: Server Side Rendering with Angular
- Step 7: Progressive Web App with Angular
- Step 8: Search Engine Optimization with Angular
- Step 9: HttpClient with Angular
This last step allows you to obtain an example application
The source code for this final application is available on GitHub
https://github.com/ganatan/angular-app