Fermer

mai 6, 2024

Améliorer les performances angulaires : Lazy Loading, @defer, Kendo UI

Améliorer les performances angulaires : Lazy Loading, @defer, Kendo UI


Nous pouvons tirer parti du chargement paresseux et de @defer avec une puissante interface utilisateur Kendo pour les composants angulaires pour indiquer qu’une page est en cours de chargement, pour une meilleure UX.

Lors du développement de notre application, nous nous concentrons souvent uniquement sur la mise en œuvre de nouvelles fonctionnalités et pages sans accorder suffisamment d’attention aux performances. Par exemple, nous pourrions créer des pages comme Accueil et Produits avec une liste de produits, et même si elles semblent fonctionner correctement, avons-nous pris en compte leurs implications en termes de performances ?

À mesure que notre application grandit avec plus de pages et de sections, l’impact sur les performances devient plus important si nous ne comprenons pas comment Angular gère le bundle final.

Alors, comment ça marche? Le constructeur Angular rassemble tous les composants et les regroupe dans un seul fichier. Cela signifie qu’Angular envoie l’ensemble complet, y compris tous les composants, au client, que l’utilisateur navigue ou non vers cette page spécifique. Cela revient à proposer un repas complet avant que l’utilisateur n’ait consulté le menu. 😟

Aujourd’hui, nous allons explorer quelques techniques pour améliorer les performances et améliorer l’expérience utilisateur en utilisant les fonctionnalités angulaires en combinaison avec Kendo UI. Comme toujours, la meilleure façon d’apprendre est d’appliquer ces concepts dans un scénario réel.

Cet article fait référence au code d’autres articles présentant des fonctionnalités intéressantes d’Angular 17, telles que Sans module et Utiliser RxJS et les signauxoù vous pourrez découvrir quelques fonctionnalités étonnantes d’Angular 17.

Scénario

Vous avez été embauché en tant que développeur frontend pour poursuivre le projet Kendo Store, précédemment construit par un autre développeur, qui comprend une page produits avec des filtres. Votre tâche consiste à améliorer les performances et l’expérience utilisateur des pages d’accueil et de produits.

Comment pouvons-nous améliorer les performances et l’expérience utilisateur ? C’est simple! Nous pouvons exploiter les fonctionnalités angulaires ainsi que certains composants de l’interface utilisateur de Kendo pour obtenir des améliorations significatives dans les deux domaines.

Commençons!

Configurer le projet

Tout d’abord, clonez le projet en exécutant la commande suivante dans le terminal :

git clone https://github.com/danywalls/moduless-with-kendo.git
Cloning into 'moduless-with-kendo'...
remote: Enumerating objects: 149, done.
remote: Counting objects: 100% (149/149), done.
remote: Compressing objects: 100% (90/90), done.
remote: Total 149 (delta 86), reused 115 (delta 54), pack-reused 0Receiving objects:  93% (139/149Receiving objects:  95% (142/149)
Receiving objects: 100% (149/149), 158.84 KiB | 2.24 MiB/s, done.
Resolving deltas: 100% (86/86), done.

Assurez-vous de retirer toutes les branches distantes et de passer à la branche feature/filter_signal_rxjs en suivant ces étapes :

cd moduless-with-kendo
git fetch --all
git checkout feature/filter_signal_rxjs
Switched to a new branch 'feature/filter_signal_rxjs'
branch 'feature/filter_signal_rxjs' set up to track 'origin/feature/filter_signal_rxjs'.

Ensuite, installez toutes les dépendances du projet, en exécutant le npm install dans le moduless-with-kendo.

npm i
added 956 packages, and audited 957 packages in 9s
119 packages are looking for funding
  run `npm fund` for details
1 moderate severity vulnerability
To address all issues, run:
  npm audit fix
Run `npm audit` for details.

Enfin pour voir l’application en action ng serve :

ng serve -o

Initial Chunk Files | Names         |  Raw Size
styles.css          | styles        | 839.10 kB |
polyfills.js        | polyfills     |  85.41 kB |
main.js             | main          |  11.18 kB |

                    | Initial Total | 935.70 kB

Application bundle generation complete. [11.748 seconds]
Watch mode enabled. Watching for file changes...
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help

Nous pouvons naviguer vers http://localhost:4200 pour voir la boutique :

La page Produits charge d'abord

Super! Concentrons-nous sur l’amélioration des performances et la mise en œuvre du chargement différé.

Le bundle et le chargement paresseux

Si tu te souviens, quand tu cours ng serve, il fournit une sortie avec des informations sur le morceau initial de fichiers. Cependant, ces informations ne sont pas optimisées car elles sont en mode développement. Courons ng build pour générer la version de production de l’application.

$ ng build

Initial Chunk Files   | Names         |  Raw Size | Estimated Transfer Size
styles-CMDE3YWI.css   | styles        | 704.30 kB |                81.21 kB
main-VV7UTEN6.js      | main          | 568.48 kB |               137.16 kB
polyfills-CG2UM2YX.js | polyfills     |  33.96 kB |                11.03 kB

                      | Initial Total |   1.28 MB |               229.39 kB

Application bundle generation complete. [4.965 seconds][WARNING] 1 rules skipped due to selector errors:
  .k-input-label:dir(rtl) -> Unknown pseudo-class :dir

Pas de soucis pour le .k-input avertissement sur l’étiquette. Cela se produit parce que le :dir le pseudo-sélecteur n’est pas pris en charge dans le navigateur Chrome. Vous pouvez le vérifier sur le lien suivant : caniuse.com/css-dir-pseudo. Pour plus d’informations, vous pouvez lire la suite dans ce forum Kendo UI.

Après avoir examiné toutes les informations, concentrons-nous sur le fichier principal, qui a une taille de 568 Ko. C’est assez substantiel. Est-il vraiment nécessaire que l’utilisateur télécharge une telle quantité de code lorsqu’il entre dans le magasin ?

Le main.js le fichier bundle contient app.component, home.component et products.component. Cependant, si nous ouvrons seulement le products.component lors de l’utilisation du kendo-card, pourquoi devrions-nous envoyer tous ces composants à l’utilisateur, qu’il navigue ou non vers la section produit ? Ce n’est pas optimisé.

Améliorons cela en utilisant une fonctionnalité angulaire intéressante appelée « importation dynamique » !

Importation dynamique

L’application du magasin charge tout dans le main.js fichier, nous n’avons donc actuellement pas de fractionnement de code ni de chargement paresseux. Cependant, nous pouvons apporter un petit changement dans le app.route.ts déposer.

Dans le app.route.ts nous importons les composants Home et Product pour faire une référence à ces fichiers.

import { Routes } from '@angular/router';
import {HomeComponent} from "./pages/home/home.component";
import {ProductsComponent} from "./pages/products/products.component";

export const routes: Routes = [
  {
    path: '',
    component:  HomeComponent,
  },
  {
    path: 'products',
    component: ProductsComponent,
  }
];

Au lieu d’importer en haut et d’utiliser la propriété du composant, nous pouvons la remplacer par un loadComponent fonction. Cette fonction utilise le import instruction pour résoudre le composant du chemin et supprime la référence dans les fichiers de route.

Le code final ressemble à :

import { Routes } from '@angular/router';
export const routes: Routes = [
  {
    path: '',
    loadComponent: () =>
      import('./pages/home/home.component').then((h) => h.HomeComponent),
  },
  {
    path: 'products',
    loadComponent: () =>
      import('./pages/products/products.component').then(
        (p) => p.ProductsComponent
      ),
  },
];

Code complet : https://github.com/danywalls/moduless-with-kendo/blob/feature/performance-defer-loading/src/app/app.routes.ts

Enregistrez les modifications, puis exécutez le ng serve -o commande. Vous remarquerez un résultat légèrement différent :

le fichier principal est passé de 568,48 Ko à 104,51 Ko

Jetez un œil au fichier principal ; il est passé de 568,48 Ko à 104,51 Ko ! C’est un 81% diminution de taille, ce qui est assez impressionnant. De plus, nous disposons désormais de deux offres groupées différentes qui sont chargées paresseusement : le produit et les composants domestiques. Cela signifie que les modifications apportées au produit n’auront pas d’impact sur le composant domestique. 🎉

Mais nous devons continuer à améliorer notre magasin. Naviguons vers la zone des produits avec une connexion 3G et voyons ce qui se passe ! 🤔

chargement avec 3g - aucun produit affiché au début

Pourquoi n’affiche-t-il initialement aucun produit, puis, après quelques secondes, affiche-t-il les produits ? Cette UX n’est pas bonne, mais c’est quelque chose que nous pouvons facilement améliorer. Les composants de l’interface utilisateur de Kendo peuvent nous aider à résoudre tous ces problèmes rapidement et facilement ! Commençons!

Indicateurs de chargement

Nous souhaitons améliorer notre interface utilisateur, et Kendo UI fournit un ensemble de composants prêts à faire exactement cela ! Nous pouvons facilement les combiner avec notre code existant. Dans notre cas, nous utiliserons Kendo UI pour les indicateurs angulairesqui propose des composants tels que des chargeurs et plus encore.

Tout d’abord, installons le kendo-angular-indicators package utilisant les schémas.

 ng add @progress/kendo-angular-indicators
i Using package manager: npm
√ Found compatible package version: @progress/kendo-angular-indicators@14.3.0.
√ Package information loaded.

Ouvrez le products.component.ts fichier, et dans la section importations, ajoutez le IndicatorsModule pour accéder à tous les composants fournis par les indicateurs angulaires Kendo UI. Voici à quoi ressemble le code :

import { IndicatorsModule } from '@progress/kendo-angular-indicators';
@Component({
  selector: 'app-products',
  standalone: true,
  imports: [CardModule, IndicatorsModule, CurrencyPipe],
  templateUrl: './products.component.html',
  styleUrl: './products.component.scss',
})
....

Dans le modèle products.component.htmlutilisez le @if contrôler le flux avec le $products variable. Si $products n’a pas de valeur, puis affichez un composant de chargement de l’interface utilisateur Kendo. Sinon, s’il y a $productspuis montrez-les (dans le @else emballage.

En savoir plus sur Angulaire Flux de contrôle.

Le code ressemble à :

@if(!$products()) {
<div class="text-center">
  <kendo-loader type="pulsing" size="medium">
  </kendo-loader>
</div>
}
@else {
<section id="products">
  @for (product of $products(); track product.id) {
  <kendo-card width="200px">
    <img [src]="product.image" kendoCardMedia alt="cover_img" />
    <kendo-card-body>
      <h4>{{ product.title }}</h4>
    </kendo-card-body>
    <kendo-card-footer>
      <span>Price {{ product.price | currency }}</span>
      <span (click)="addFavorite(product)"></span>
    </kendo-card-footer>
  </kendo-card>
  }
</section>
}

Enregistrez les modifications, si le $products La variable n’est pas encore disponible, le composant du chargeur sera affiché. Une fois $products a une valeur, la section produits sera affichée. 🤌

le symbole de chargement aide les utilisateurs à comprendre que les produits sont en cours de chargement

Pensez-vous que cela fonctionne ? Approfondissons un peu. Rouvrez les outils de développement et accédez à l’onglet Réseau. Filtrez les résultats pour afficher les images. Ensuite, accédez à la page des produits et observez le nombre d’images que nous envoyons à l’utilisateur, même si l’utilisateur ne voit pas ces produits. Pourquoi cela pourrait-il se produire ? 🤔

plusieurs images se chargent dans la vue console

Cela a un impact sur les performances de l’utilisateur car nous envoyons des images à l’utilisateur même s’il ne souhaite pas les voir. Comment pouvons-nous résoudre ce problème ? Eh bien, Angular 17 est livré avec une fonctionnalité très intéressante appelée Vues différées ! Jouons avec !

Vues différées

Les vues différées permettent de différer la charge des composants et des dépendances, comme les composants enfants, les directives, les canaux et les CSS. Nous pouvons les ajouter à notre application, de manière déclarative, en enveloppant le composant avec un @defer bloc.

Les vues différées aident à retarder le chargement des composants et des parties associées, comme les composants enfants, les directives, les canaux et les CSS. Nous pouvons ajouter cette fonctionnalité à notre application en enveloppant le composant avec un @defer bloc.

Les vues différées fonctionnent avec déclencheurs, prélectureet des sous-blocs comme espace réservé, chargement et erreur. Ils réduisent la taille initiale du bundle de votre application ou retardent le chargement de composants lourds qui pourraient ne être nécessaires que plus tard. 🎆

Exemple:

@defer {
  <my-dashboard-heavy/>
}

Le contenu principal du @defer Le bloc est chargé paresseusement et n’est pas affiché initialement. Il apparaît uniquement lorsqu’un déclenchement ou when la condition est remplie et les dépendances nécessaires ont été récupérées. Par défaut, un @defer le blocage est déclenché lorsque l’état du navigateur devient inactif.

@placeholder

Le @placeholder Le bloc est facultatif et affiche le contenu avant que le bloc différé ne soit déclenché. Ce contenu d’espace réservé est remplacé par le contenu principal une fois le chargement terminé. Vous pouvez utiliser n’importe quel contenu dans la section d’espace réservé, y compris du HTML brut, des composants, des directives et des canaux. Notez cependant que les dépendances du bloc placeholder sont chargées avec impatience.

Le @placeholder Le bloc accepte un paramètre facultatif pour spécifier le minimum heure à laquelle l’espace réservé doit être affiché. Ce minimum Le paramètre est spécifié en millisecondes (ms) ou en secondes (s). Cela empêche le scintillement rapide du contenu de l’espace réservé si les dépendances différées sont récupérées rapidement. Le minimum minuterie pour le @placeholder Le bloc commence après le rendu initial du @placeholder le bloc est terminé.

@defer {
  <large-component />
} @placeholder (minimum 500ms) {
  <p>Placeholder content</p>
}

En savoir plus sur d’autres blocs comme @loading et @error.

Déclencheurs

Lorsqu’un @defer Le bloc est déclenché, il remplace le contenu de l’espace réservé par du contenu chargé paresseusement. Il existe deux options pour configurer le moment où cet échange est déclenché : on et when.

on spécifie une condition de déclenchement à l’aide d’un déclencheur de la liste des déclencheurs disponiblesmais dans notre cas, nous nous concentrerons sur la fenêtre d’affichage.

viewport déclencherait le bloc différé lorsque le contenu spécifié entre dans la fenêtre en utilisant le IntersectionObserver API. Il peut s’agir du contenu d’un espace réservé ou d’une référence d’élément.

Un point intéressant est que plusieurs déclencheurs d’événements peuvent être définis à la fois. Par exemple: on viewport; on timer(5s) signifie que le bloc de report sera déclenché si l’utilisateur interagit avec l’espace réservé, ou après 5 secondes.

Exemple:

@defer (on viewport; on timer(5s)) {
  <nice-heavy-component />
} @placeholder {
 <div>Loading....</div>
}

Utilisez également les deux when et on ensemble dans une seule instruction, et le swap sera déclenché si l’une ou l’autre des conditions est remplie.

@defer (on viewport; when cond) {
  <calendar-cmp />
} @placeholder {
  <img src="placeholder.png" />
}

OK, avec cet aperçu, nous pouvons combiner le report et l’espace réservé pour améliorer les performances de notre application.

Utilisation du report et des espaces réservés

Dans notre cas, nous souhaitons charger la carte uniquement lorsqu’elle devient visible dans la fenêtre. Pour y parvenir, ouvrez le products.component.html et enveloppez la carte avec un @defer bloc qui déclenche on viewport.

@defer (on viewport) {
  <kendo-card width="200px">
    <img [src]="product.image" kendoCardMedia alt="cover_img" />
    <kendo-card-body>
      <h4>{{ product.title }}</h4>
    </kendo-card-body>
    <kendo-card-footer class="k-hstack">
      <span>Price {{ product.price | currency }}</span>
      <span (click)="addFavorite(product)"></span>
    </kendo-card-footer>
  </kendo-card>
  } 

Dans l’espace réservé d’un minimum de 2 secondes, nous ajouterons un div pour simuler l’apparence du <kendo-card> boîte. Voici le HTML :

@placeholder(minimum 2s) {
  <div class="loading-area">
  </div>
}

Dans le product.component.scssajouter le loading-area classe:

.loading-area {
  width: 350px;
  height: 350px;
  opacity: 0.5;
  border-radius: 5px;
  background-color: lightblue;
}

Enregistrez les modifications et observez comment cela fonctionne. Ce sont des changements importants ! Maintenant, nous avons une zone pour les cartes à venir, et nous chargeons uniquement les images visibles. Au fur et à mesure que nous continuons le défilement, de nouvelles images sont chargées dynamiquement. Cette approche accélère considérablement le temps de chargement et réduit la quantité de trafic dans notre application ! Ce sont des améliorations fantastiques !

la page des produits comporte désormais des cases bleu clair où les images apparaîtront une fois chargées

Encore une chose !

Nous avons créé un joli div bleu, mais et si je vous disais que vous pouvez facilement créer une carte de chargement sans avoir besoin d’apprendre à créer des figures fantaisistes en CSS ou en animations ? 😏

Le Kendo UI pour les indicateurs angulaires le module fournit un Squelette composant qui vous permet de créer une animation de carte de chargement sophistiquée. Je ne veux pas vous submerger de tout ce que nous pouvons faire en combinant Angular et Kendo UI, mais voyons à quelle vitesse nous pouvons créer un joli squelette animé.

Tout d’abord, donnons à notre fichier products.components.ts l’accès au module de l’indicateur Kendo UI :

@Component({
selector: 'app-products',
standalone: true,
imports: [CardModule, CurrencyPipe, IndicatorsModule],

Maintenant, ouvrez le products.component.html fichier à nouveau et accédez au @placeholder(minimum 2s) zone. Supprimez le div avec loading-area cours avec un kendo-card et pied de page.

<kendo-card width="350px" style="margin: 1rem; height:350px;">
  <kendo-card-footer>
  </kendo-card-footer>
</kendo-card>

À l’intérieur de <kendo-card> composant, nous allons utiliser des composants squelettes avec des formes pour chaque cas. Par exemple, nous utiliserons une forme rectangulaire pour l’image et du texte pour le nom et le prix du produit.

<kendo-skeleton
  shape="rectangle"
  animation="wave"
  width="100%"
  height="143.86px"
></kendo-skeleton>

Le code final de la carte ressemble à ceci :

<kendo-card width="350px" style="margin: 1rem; height:350px;">
  <kendo-skeleton
    shape="rectangle"
    animation="wave"
    width="100%"
    height="143.86px"
  ></kendo-skeleton>

  <kendo-card-footer>
    <kendo-skeleton
      shape="text"
      animation="wave"
      width="100%"
    ></kendo-skeleton>
    <kendo-skeleton
      shape="text"
      animation="pulse"
      width="80%"
    ></kendo-skeleton>
  </kendo-card-footer>
</kendo-card>

Code complet : https://github.com/danywalls/moduless-with-kendo/blob/feature/performance-defer-loading/src/app/pages/products/products.component.html

Enregistrez les modifications et observez la belle animation !

Un chargeur squelette montrant des cartes avec image et texte sera chargé.  Une UX plus agréable, c'est sûr !

Conclusion

C’était un article tellement amusant : nous avons pu améliorer les performances d’Angular en tirant parti du chargement différé et du @reporter fonctionnalité en conjonction avec certains puissants Composants de l’interface utilisateur du Kendo.

Tout d’abord, nous avons découvert les importations dynamiques et le chargement paresseux, qui peuvent réduire considérablement la taille initiale du bundle de notre application. Cela améliore non seulement les temps de chargement, mais améliore également l’expérience utilisateur en fournissant uniquement le code nécessaire en cas de besoin, plutôt que de surcharger l’utilisateur de données inutiles.

L’interface utilisateur a été améliorée en intégrant des composants de l’interface utilisateur Kendo tels que des chargeurs et des squelettes, qui ont encore amélioré l’expérience utilisateur en fournissant des espaces réservés visuellement attrayants pendant le chargement du contenu, fournissant ainsi un excellent retour à l’utilisateur et maintenant également l’engagement pendant les périodes de chargement. 👌 Souvent, les commentaires des utilisateurs pendant le chargement sont plus importants que le temps de chargement lui-même. Grâce à la puissance des indicateurs Kendo UI, nous pouvons facilement et rapidement l’ajouter à notre application !

N’hésitez pas à jouer avec le code source et à lire quelques ressources :

Et n’oubliez pas : vous pouvez essayez Kendo UI pour Angular gratuit pendant 30 jours !

Bon codage !




Source link