Nouveautés de la directive Angular NgOptimizedImage

Alex Castle
Alex Castle

Il y a un peu plus d'un an, l'équipe Chrome Aurora a lancé la directive Angular NgOptimizedImage. Cette directive vise principalement à améliorer les performances, telles que mesurées par les métriques Core Web Vitals. Elle regroupe les bonnes pratiques et les optimisations d'images courantes dans une API destinée aux utilisateurs qui n'est guère plus compliquée qu'un élément <img> standard.

En 2023, nous avons amélioré la directive avec de nouvelles fonctionnalités. Cet article décrit les plus importantes de ces nouvelles fonctionnalités, en mettant l'accent sur les raisons pour lesquelles nous avons choisi de les hiérarchiser et sur la façon dont elles peuvent contribuer à améliorer les performances des applications Angular.

Nouvelles fonctionnalités

NgOptimizedImage s'est considérablement amélioré au fil du temps, avec les nouvelles fonctionnalités suivantes.

Mode de remplissage

Définir la taille de vos images en fournissant des attributs width et height est une optimisation extrêmement importante pour réduire le décalage de mise en page, car les navigateurs doivent connaître le format de l'image pour lui réserver de l'espace. Toutefois, la mise à l'échelle des images représente un travail supplémentaire pour les développeurs d'applications et n'a pas de sens dans certains cas d'utilisation des images.

Pour résoudre ce problème, il s'agit de la première fonctionnalité majeure ajoutée à l'aperçu post-développeur du composant Image: le mode de remplissage. Cela permet aux développeurs d'inclure des images sans les redimensionner explicitement et sans entraîner un décalage de mise en page.

Avec le mode "Remplissage", l'exigence de dimensionnement des images est désactivée et l'image est automatiquement stylisée pour remplir son élément contenant. Cela dissocie le format d'une image de l'espace qu'elle occupe sur la page et vous permet de mieux contrôler l'intégration des images dans votre mise en page.

Le mode de remplissage utilise NgOptimizedImage comme alternative plus performante à la propriété CSS background-image. Placez une image dans <div> ou un autre élément qui aurait reçu le style background-image, puis activez le mode de remplissage, comme illustré dans l'exemple de code précédent. Utilisez les propriétés CSS object-fit et object-position sur <div> pour contrôler la position de l'image en arrière-plan.

// Height and width are required
<img ngSrc="example.com" height="300" width="400">

// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
  <img ngSrc="example.com" fill>
</div>

Génération de srcset

L'une des techniques d'optimisation des images les plus efficaces consiste à utiliser l'attribut srcset pour vous assurer que des images de la bonne taille sont téléchargées pour tous les appareils qui accèdent à votre application. L'utilisation de srcset dans l'ensemble de votre application peut vous éviter de gaspiller de la bande passante et améliorer considérablement votre LCP Core Web Vital.

L'inconvénient de l'attribut srcset est qu'il peut être difficile à implémenter. Écrire manuellement des valeurs srcset signifie ajouter plusieurs lignes de balisage à chaque élément d'image de votre application, avec plusieurs URL personnalisées pour chaque srcset. Vous devez également choisir un ensemble de points d'arrêt, ce qui est compliqué, car ils peuvent représenter à la fois les densités d'écran et les tailles de fenêtre d'affichage des appareils courants.

C'est pourquoi l'ajout de la génération automatique de srcset dans la directive NgOptimizedImage a constitué un jalon important après le lancement. Avec cette addition, toute application utilisant un CDN compatible avec le redimensionnement d'image peut ajouter automatiquement des srcsets complets et personnalisables à chaque image générée avec la directive NgOptimizedImage.

Nous avons inclus une API simplifiée pour définir la propriété sizes, qui permet de s'assurer que chaque image reçoit le bon type de srcset. Si vous n'incluez pas d'attribut sizes, nous savons que l'image doit être de taille fixe et qu'elle doit recevoir un srcset dépendant de la densité, comme suit:

<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >

Ce type de srcset garantit que les images sont diffusées à une taille qui tient compte de la densité en pixels de l'appareil de l'utilisateur.

En revanche, si vous incluez la propriété sizes, NgOptimizedImage génère un srcset responsif qui inclut des points de rupture pour de nombreuses tailles d'appareils et d'images courantes, à l'aide de cette liste de points de rupture par défaut:

[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]

Génération de préconnexion

Pour améliorer le LCP, il est important de réduire le temps que vos utilisateurs passent à télécharger l'image du LCP. Dans la section précédente, vous avez vu comment srcset peut vous aider à transférer des fichiers image plus petits. Toutefois, une optimisation tout aussi importante consiste à démarrer le transfert dès que possible. Pour ce faire, vous pouvez utiliser des balises link rel="preconnect" pour accélérer la connexion à votre domaine d'images.

Dès le départ, NgOptimizedImage vous a averti si vous ne parvenez pas à préconnecter au domaine de votre image LCP. Toutefois, cette alerte n'est pas la solution idéale. Nous préférons résoudre le problème pour vous. C'est exactement ce que fait NgOptimizedImage désormais, avec la génération automatique de préconnexions.

Pour prendre en charge cette fonctionnalité, nous utilisons l'analyse de code statique pour tenter de détecter les domaines d'image dans les chargeurs NgOptimizedImage et de générer automatiquement des balises de lien de préconnexion pour ces domaines. Il peut arriver que des liens de préconnexion manuels soient toujours nécessaires, mais pour la plupart des utilisateurs, la préconnexion automatique signifie une étape de moins pour obtenir de bonnes performances d'image.

Amélioration de la compatibilité avec les chargeurs personnalisés

L'architecture du chargeur est un élément clé de NgOptimizedImage. Elle permet à la directive de générer automatiquement des URL adaptées au CDN d'images de l'application. Un ensemble de chargeurs intégrés est inclus pour les CDN couramment utilisés. Nous proposons également l'utilisation de chargeurs personnalisés, qui vous permettent d'intégrer NgOptimizedImage dans presque toutes les solutions d'hébergement d'images.

Au lancement, le champ d'application de ces chargeurs personnalisés était limité et ne pouvait lire que l'attribut width de l'élément image. Suite aux commentaires des utilisateurs, nous avons ajouté la prise en charge d'une structure de données loaderParams personnalisable, qui permet de transmettre des données arbitraires de l'élément Image au chargeur personnalisé. Grâce à cette expansion, les chargeurs personnalisés peuvent s'avérer aussi simples ou aussi complexes que l'exige l'infrastructure d'images d'une application.

L'exemple suivant montre comment un chargeur personnalisé simple peut utiliser l'API loaderParams pour choisir entre deux domaines d'images alternatifs:

const myCustomLoader = (config: ImageLoaderConfig) => {
  if (config.loaderParams?.alternateDomain) {
    return `https://alternate.domain.com/images/${config.src}`
  }
  return `https://primary.domain.com/images/${config.src}`;
};

Vous trouverez un exemple de chargeur personnalisé plus complexe dans la documentation Angular.

Conseils étendus sur les performances des images

Jusqu'à présent, toutes les alertes de performances des images que nous avons ajoutées à Angular faisaient partie de la directive NgOptimizedImage. Si vous n'utilisez pas la directive dans l'application, vous ne recevrez aucune recommandation concernant les problèmes de performances des images.

Dans Angular 17, nous élargissons le champ d'application des conseils sur les performances des images pour inclure toutes les applications Angular. Désormais, si nous détectons des modèles d'images qui, selon nous, sont des erreurs nuisant aux performances, comme le chargement différé de votre image LCP ou le téléchargement d'un fichier beaucoup trop volumineux pour la page, nous vous en informerons, même si vous n'utilisez pas NgOptimizedImage.

Les performances des images sont importantes pour toutes les applications. Nous sommes ravis de continuer à développer des garde-fous pour éviter les erreurs courantes dans les applications Angular.

Et demain ?

Nous travaillons déjà dur sur le prochain ensemble de fonctionnalités pour NgOptimizedImage. Bien que les performances des images restent notre priorité, nous aimerions également ajouter des fonctionnalités qui améliorent l'expérience des développeurs, afin de nous assurer que NgOptimizedImage reste une option intéressante pour inclure des images dans les applications Angular.

Les espaces réservés aux images sont une fonctionnalité prioritaire pour nous. Ils sont couramment utilisés pour améliorer le chargement d'images dans les applications Web, mais peuvent nuire aux performances s'ils ne sont pas implémentés correctement. Nous espérons créer un système d'espace réservé d'image axé sur les performances dans NgOptimizedImage. Pour en savoir plus, consultez notre blog.