Comment mettre en place une stratégie de chargement d'une page web Angular en se basant sur le débit de la connexion internet de l'utilisateur ?

Photo by Robynne Hu on Unsplash

Comment mettre en place une stratégie de chargement d'une page web Angular en se basant sur le débit de la connexion internet de l'utilisateur ?

Lorsque nous développons une application web, il y a souvent une question qui nous vient à l'esprit mais que nous négligeons généralement. La question est la suivante :

Comment notre application réagirait avec une connexion internet dont le débit est faible ?

La plupart d'entre nous ne se pose la question qu'à la fin du projet 😂

Dans cet article, nous verrons comment Angular nous permet de contrôler et de gérer le chargement de nos bundles (le code JS qui s'occupe de l'affichage de notre page web) en se basant sur le débit de la connexion internet.

Nous prendrons l'exemple d'une petite application Angular ayant trois composants à savoir HomeComponent, AboutComponent et ContactComponent qui seront chargés de façon paresseuse (lazy).

1- Création d'un nouveau projet Angular à l'aide de la CLI Angular :

ng new testing-internet-connection --routing

2- Création de trois composants Angular implémentant chacun le routing :

ng g m home --route home --module=app.module
ng g m about --route about --module=app.module
ng g m contact --route contact --module=app.module
import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `<h1>Home</h1>`
})
export class HomeComponent { }
import { Component } from '@angular/core';

@Component({
  selector: 'app-about',
  template: `<h1>About</h1>`
})
export class AboutComponent { }
import { Component } from '@angular/core';

@Component({
  selector: 'app-contact',
  template: `<h1>Contact</h1>`
})
export class ContactComponent { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';

@NgModule({
  declarations: [HomeComponent],
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: '', component: HomeComponent }])
  ]
})
export class HomeModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { AboutComponent } from './about.component';

@NgModule({
  declarations: [AboutComponent],
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: '', component: AboutComponent }])
  ]
})
export class AboutModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';

@NgModule({
  declarations: [ContactComponent],
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: '', component: ContactComponent }])
  ]
})
export class ContactModule { }

3- Création d'un service appelé InternetConnectionService qui nous permet de détecter la qualité de la connexion internet :

ng g s internet-connection
import { Injectable } from '@angular/core';

declare var navigator: any;

@Injectable({
  providedIn: 'root'
})
export class InternetConnectionService {

  constructor() { }

  getSpeed(): string {
    const connection = navigator.connection;
    const type = connection.effectiveType;
    const speed = connection.downlink;

    if (type === 'slow-2g' || speed < 0.5) {
      return '2G';
    } else if (type === '2g' || speed < 1) {
      return '3G';
    } else {
      return '5G';
    }
  }
}

4- Création d'une stratégie de préchargement personnalisée appelée InternetConnectionPreloadingStrategy :

import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
import { InternetConnectionService } from './internet-connection.service';

@Injectable({ providedIn: 'root' })
export class InternetConnectionPreloadingStrategy implements PreloadingStrategy {

  constructor(private connectionService: InternetConnectionService) { }

  preload(route: Route, load: () => Observable<any>): Observable<any> {
    const quality = this.connectionService.getSpeed();

    if (quality === '5G') {
      return load();
    } else {
      return of(null);
    }
  }
}
  • Notre stratégie InternetConnectionPreloadingStrategy implémente l'interface PreloadingStrategy parce que nous devons redéfinir la méthode preload() en y rajoutant la logique basée sur la qualité de la connexion internet.

5- Modification de app-routing.module.ts :

Dans notre fichier, app-routing.module.ts, voici ce que nous avons jusque-là :

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

const routes: Routes = [
  { path: '', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
  { path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) },
  { path: 'contact', loadChildren: () => import('./contact/contact.module').then(m => m.ContactModule) }
];

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

Comme nous pouvons le remarquer, c'est du classique. À présent, nous procéderons à quelques modifications afin d'ajouter notre stratégie de pré-chargement qui dépend de la qualité de notre connexion internet. Voici le résultat :

import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules, PreloadingStrategy, Route } from '@angular/router';
import { InternetConnectionPreloadingStrategy } from './internet-connection-preloading-strategy';

const routes: Routes = [
  { path: '', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
  { path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) },
  { path: 'contact', loadChildren: () => import('./contact/contact.module').then(m => m.ContactModule) }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: InternetConnectionPreloadingStrategy
  })],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • L'attribut preloadingStrategy nous permet d'indiquer notre stratégie de pré-chargement.

6- Modification du composant AppComponent :

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

@Component({
  selector: 'app-root',
  template: `
    <nav>
      <a routerLink="/" routerLinkActive="active">Home</a>
      <a routerLink="/about" routerLinkActive="active">About</a>
      <a routerLink="/contact" routerLinkActive="active">Contact</a>
    </nav>
    <router-outlet></router-outlet>
  `
})
export class AppComponent { }

7- Débogage avec un navigateur en simulant différents débits de connexion Internet :

En inspectant notre navigateur après avoir lancé la commande ng serve -o, nous pouvons nous rendre dans l'option Réseau et simuler le débit de la connexion internet que nous désirons à savoir (2G, 3G, 4G ou 5G). En fonction de ce débit, nous pourrons observer le comportement lié aux chargements des modules qui s'occupent de l'affichage de nos trois (03) pages web créés précédemment.

En somme, nous avons vu comment définir une stratégie de pré-chargement de nos bundles suivant le débit de la connexion internet de l'utilisateur afin de lui garantir une meilleure expérience utilisateur. Si vos utilisateurs sont susceptibles d'être mobiles et de bénéficier d'une faible bande passante ou d'un faible niveau de WiFi ou de données mobiles, cette stratégie de pré-chargement pourrait s'avérer bénéfique. Si vous n'êtes pas sûr de vous, vous pouvez consulter vos utilisateurs professionnels (les parties prenantes de votre application) pour vous en rendre compte. Vous pouvez également combiner cette stratégie avec l'une des autres stratégies personnalisées. Avant de choisir cette option, ou toute autre stratégie de pré-chargement, il est recommandé d'effectuer des tests à différentes vitesses de réseau dans le cadre de différents flux de travail d'utilisateurs valides et courants. Ces données pourrons vous aider à la prise de décision afin de garantir une meilleure expérience utilisateur à vos utilisateurs.

Pour plus d'informations :

👉 Angular Preloading Strategy

👉 Preload Angular Bundles by John Papa

Did you find this article valuable?

Support Ezéchiel Amen AGBLA by becoming a sponsor. Any amount is appreciated!