# 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 :**

```plaintext
ng new testing-internet-connection --routing
```

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

```plaintext
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
```

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

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

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

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

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

@Component({
  selector: 'app-contact',
  template: `<h1>Contact</h1>`
})
export class ContactComponent { }
```

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

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

```typescript
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 :**

```plaintext
ng g s internet-connection
```

```typescript
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` **:**

```typescript
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à :

```typescript
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 :

```typescript
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 :**

```typescript
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](https://angular.io/api/router/PreloadingStrategy)
> 
> 👉 [Preload Angular Bundles by John Papa](https://www.johnpapa.net/preload-angular-bundles-when-good-network-connectivity-is-detected/)
