Vous êtes sur la page 1sur 20

Lazy Loading avec

Angular 13
Guide Complet

23/12/2021

Nous allons implémenter le


Lazy loading dans notre
Application Web.

Nous utiliserons pour cela le


framework
javascript Angular version
13.1.1

Angular nous permettra de


charger les modules à la
demande.

ganatan.com
Qu’allons nous faire ?

Pour réaliser ce routage voici un résumé de ce que nous allons faire

Nous allons configurer le Lazy loading dans notre Application Web


avec Angular version 13.1.1

Il s'agit de l'étape 3 de notre guide Angular qui nous permettra d'obtenir une
Application Web de type PWA.
Nous allons utiliser un projet existant dont les caractéristiques sont

 Genéré avec Angular CLI


 Routing

Tous les sources créés sont indiqués en fin de tutoriel.

L' application est à l'adresse suivante

 https://angular.ganatan.com
Avant de commencer

La vitesse à laquelle s'affiche un site web est l'un des critères les plus essentiels
pour l'utilisateur.
Et cette vitesse s'apprécie en secondes.
Au-delà de 3 secondes 57% des utilisateurs quittent purement et simplement le
site.

Quelles méthodes ou techniques doit-on alors utiliser pour que notre site web se
charge rapidement ?

L'une des techniques est le lazy loading (“chargement fainéant ou paresseux”


en français).
Il a pour effet d'accélérer le fonctionnement d'un site web.
Il permet de spécifier quelles parties d'un site web doivent être chargées lors du
démarrage.

Théorie

Avant d'aller plus loin il nous faut comprendre comment fonctionne Angular.
La commande qui nous intéresse concerne la compilation de notre projet.

Dans notre fichier package.json il s'agit de la commande

 ng build

Sans rentrer dans les détails cette commande utilise Webpack (un module
bundler).
Grâce à Webpack angular utilise les fichiers de notre projet , les compile pour
générer dans le répertoire dist un certain nombre de fichiers que nous pourrons
déployer sur un serveur web.
Le projet qui nous sert de base dipose de 6 pages Web

 Home
 About
 Contact
 Login
 Signup
 notfound

La compilation de notre code source génère notamment un fichier main.js qui


contient le code de ces 5 pages.
Pour vérifier cette théorie il suffit d'ouvrir le fichier dist/angular-
starter/main.js faire une recherche sur le code utilisé dans chacune des
6 pages

 home works! (code utilisé dans home.component.html)


 not-found works! (code utilisé dans not-found.component.html)
 contact works! (code utilisé dans contact.component.html)
 login works! (code utilisé dans login.component.html)
 signup works! (code utilisé dans signin.component.html)
 about works! (code utilisé dans about.component.html)

Ce fichier et d'autres seront appelés lors de l'affichage du site Web.


Plus le nombre de pages sera grand, plus le fichier sera volumineux et plus
l'affichage sera lent.

Le principe du lazy loading va consister à scinder ce fichier en plusieurs


parties qui ne seront chargées qu'en temps voulu.

Passons donc à la pratique.

Pratique
Le lazy loading fonctionne en utilisant la notion de modules et non plus celle des
composants.

Nous utiliserons la documentation Angular pour appliquer cette technique.


https://angular.io/guide/lazy-loading-ngmodules

Nous allons adapter notre architecture, en créant un module pour chaque


élément à afficher.
Home et not-found resteront gérés de façon classique sous forme de
composants.

Utilisons la commande ng generate module que nous offre angular-cli.


# Création des modules
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

Les fichiers nécessaires à chaque composant sont créés automatiquement.

Par exemple pour le composant Contact

 contact-routing.module.ts
 contact.module.ts

Le fichier app.module.ts est automatiquement modifié comme suit.


src/app/app.module.ts

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 { 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
],
imports: [
BrowserModule,
AppRoutingModule,
ContactModule,
LoginModule,
SignupModule,
AboutModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Nous devons procéder à certaines modifications sur les fichiers suivants.

 app-routing.module.ts
 app.module.ts
 about-routing.module.ts
 about.module.ts
 contact-routing.module.ts
 contact.module.ts

Le lazy loading sera appliqué sur Contact, About Login et Signup


Au niveau de AppRoutingModule, nous devons mettre à jour les routes en
utilisant loadchildren.

src/app/app-routing.module.ts

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 { }
Il nous faut modifier le module AppModule et ne laisser que les composants
HomeComponent et NotFoundComponent

src/app/app.module.ts

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 { }

Il ne reste plus qu'à modifier les fichiers de routing et module pour Contact,
Login, Signup et About.
src/app/modules/general/about/about-routing.module.ts

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 { }

src/app/modules/general/about/about.module.ts

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 { }
src/app/modules/general/about/contact-routing.module.ts

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 { }

src/app/modules/general/about/contact.module.ts

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 { }
src/app/modules/general/signup/ signup-routing.module.ts

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 { }

src/app/modules/general/signup/signup.module.ts

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 { }
src/app/modules/general/login/login-routing.module.ts

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 { }

src/app/modules/general/login/login.module.ts

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 { }
Vérification

Pour vérifier la théorie du lazy loading nous devons effectuer une nouvelle
compilation (npm run build)

Dans le répertoire dist/angular-starter nous obtenons cette fois 4 fichiers

 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

Remarque:
Les noms peuvent être différents notamment avec des numéros c'est webpack
qui gère le nommage.

Le code de chacune de nos 5 pages est maintenant disposé de la façon


suivante

 home works! (code trouvé dans main.js)


 not-found works! (code trouvé dans main.js)

 contact works! (code trouvé dans modules-general-contact-contact-


module.js)
 login works! (code trouvé dans modules-general-login-login-module.js)
 signup works! (code trouvé dans modules-general-signup-signup-
module.js)
 about works! (code utilisé modules-general-about-about-module.js)

Si nous exécutons l'application (npm run start) nous pouvons voir dans Chrome
(F12) au niveau de l'onglet Network comment les fichiers sont chargés.

 Au lancement du site : main.js est appelé.


 A la sélection de About : modules-general-about-about-module.js est
appelé une seule fois
 A la sélection de login: modules-general-login-login-module.js est appelé
une seule fois
 A la sélection de signup: modules-general-signup-signup-module.js est
appelé une seule fois
 A la sélection de Contact : modules-general-contact-contact-module.js
est appelé une seule fois

Si nous lançons l'url localhost/contact

 Dans ce cas main.js et seulement modules-general-contact-contact-


module.js sont appelés

Conclusion :
Quelle que soit le nombre de pages, le fichier main.js aura toujours la même
taille.
Le lancement du site qui charge le fichier main.js se fera toujours à la même
vitesse.

Child Routes
Cette application contient aussi la gestion des Child routes.

Cette question est évoquée dans la documentation


https://angular.io/guide/router#child-route-configuration

Vous retrouverez dans le dépôt sur github l'ajout de la notion de routing avec
Children.

De façon pratique deux composants sont rajoutés dans Contact

 mailing
 map

6 fichiers seront notamment modifiés pour en prendre compte.

 contact.component.html
 contact-routing.module.ts
 mailing-routing.module.ts
 map-routing.module.ts
 contact.component.spec.ts
 app.module.ts

# Rajout des composants et module mailing


ng generate module modules/general/contact/mailing --routing --module=app
ng generate component modules/general/contact/mailing --module=app

# Rajout des composants et module map


ng generate module modules/general/contact/map --routing --module=app
ng generate component modules/general/contact/map --module=app
src/app/modules/general/contact/contact.component.html
<div class="row">
<div class="col-12 col-sm-12 col-md-3 col-lg-3 col-xl-3">
<p>contact works!</p>
<ul>
<li><a routerLink="/contact/mailing">Mailing</a></li>
<li><a routerLink="/contact/map">Map</a></li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-9 col-lg-9 col-xl-9">
<router-outlet></router-outlet>
</div>
</div>

src/app/modules/general/contact/contact-routing.module.ts

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(m => m.MailingModule)
},
{
path: 'mailing',
loadChildren: () => import(`./mailing/mailing.module`)
.then(m => m.MailingModule)
},
{
path: 'map',
loadChildren: () => import(`./map/map.module`)
.then(m => m.MapModule)
},
{
path: '**',
loadChildren: () => import(`./mailing/mailing.module`)
.then(m => m.MailingModule)
},

]
},
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ContactRoutingModule { }
src/app/modules/general/contact/mailing/mailing-routing.module.ts

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 { }

src/app/modules/general/contact/map/map-routing.module.ts

import { NgModule } from '@angular/core';


import { Routes, RouterModule } from '@angular/router';
import { MapComponent } from './map.component';

const routes: Routes = [


{ path: '', component: MapComponent, children: [] }
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MapRoutingModule { }
src/app/modules/general/contact/contact.component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';


import { RouterTestingModule } from '@angular/router/testing';

import { ContactComponent } from './contact.component';

describe('ContactComponent', () => {
let component: ContactComponent;
let fixture: ComponentFixture<ContactComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [ContactComponent]
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(ContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {


expect(component).toBeTruthy();
});
});
src/app/app.module.ts

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
Il ne reste plus qu' à tester l'application.

# Développement
npm run start
http://localhost:4200/

# Tests
npm run lint
npm run test
npm run e2e

# Production
npm run build

Code source
Le code source utilisé en début de tutoriel est disponible sur github
https://github.com/ganatan/angular-routing

Le code source obtenu à la fin de ce tutoriel est disponible sur github


https://github.com/ganatan/angular-lazy-loading

Les étapes suivantes vous permettront d'obtenir une application prototype

 Etape 1 : Démarrer avec Angular


 Etape 2 : Routing avec Angular
 Etape 3 : Lazy loading avec Angular
 Etape 4 : Bootstrap avec Angular
 Etape 5 : Architecture avec Angular
 Etape 6 : Components avec Angular
 Etape 7 : Services avec Angular
 Etape 8 : Template Driven Forms avec Angular
 Etape 9 : Charts avec Angular
 Etape 10 : Server Side Rendering avec angular
 Etape 11 : HttpClient avec Angular
 Etape 12 : Transfer State avec Angular
 Etape 13 : Progressive Web App avec Angular
 Etape 14 : Search Engine Optimization avec Angular

Le code source de cette application finale est disponible sur GitHub


https://github.com/ganatan/angular-app

La dernière étape permet d'obtenir un exemple d'application


Etape 15 : Créer une application Web complète avec Angular

Vous aimerez peut-être aussi