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. Il regroupe les optimisations d'image courantes et les bonnes pratiques dans une API destinée aux utilisateurs qui n'est pas beaucoup plus compliquée qu'un élément <img> standard.

En 2023, nous avons enrichi cette directive avec de nouvelles fonctionnalités. Cet article décrit les principaux avantages de ces nouvelles fonctionnalités, en insistant sur les raisons pour lesquelles nous avons choisi de les prioriser et sur la façon dont elles peuvent 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

Le dimensionnement de vos images à l'aide 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 les proportions de l'image afin de faire de la place. Toutefois, le dimensionnement des images représente un travail supplémentaire pour les développeurs d'applications et n'a aucun sens dans certains cas d'utilisation d'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 de remplissage, l'exigence de taille de l'image est désactivée, et l'image est automatiquement stylisée pour remplir l'élément qui la contient. Cela dissocie le format d'une image de l'espace qu'elle occupe sur la page et vous permet de mieux contrôler la façon dont les images s'intègrent à votre mise en page.

Le mode 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 le positionnement 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 scsets

L'une des techniques d'optimisation d'image les plus efficaces consiste à utiliser l'attribut srcset pour vous assurer que des images de taille correcte sont téléchargées pour tout appareil qui accède à 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 statistique LCP Core Web.

L'inconvénient de l'attribut srcset est qu'il peut être fastidieux à implémenter. Écrire manuellement les valeurs srcset signifie ajouter plusieurs lignes de balisage à chaque élément 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 automatisée de srcset à la directive NgOptimizedImage a été une étape majeure après le lancement. Grâce à cet ajout, toute application utilisant un CDN compatible avec le redimensionnement des images peut obtenir des ensembles de données srcsets complets et personnalisables, qui sont ajoutés automatiquement à 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 type de srcset approprié. Si vous n'incluez pas d'attribut sizes, nous savons que l'image est censée avoir une taille fixe et que vous devez obtenir un attribut 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 d'attribut 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 attribut srcset responsif qui inclut des points d'arrêt pour de nombreuses tailles d'appareils et d'images courantes, à l'aide de cette liste de points d'arrêt 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 LCP. Dans la section précédente, vous avez vu comment srcset peut vous aider en transférant des fichiers image plus petits, mais une optimisation tout aussi importante consiste à démarrer le transfert dès que possible. Pour ce faire, vous pouvez utiliser des tags link rel="preconnect" pour lancer la connexion au domaine de votre image.

Dès le départ, NgOptimizedImage vous avertit si vous ne parvenez pas à vous préconnecter au domaine de votre image LCP, mais l'avertissement n'est pas la solution idéale : nous préférons résoudre le problème pour vous. Et c'est exactement ce que fait désormais NgOptimizedImage, avec la génération automatisée 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 générer automatiquement des tags de lien de préconnexion pour ces domaines. Dans certains cas, il peut être nécessaire d'associer manuellement des liens de préconnexion. Toutefois, pour la plupart des utilisateurs, la préconnexion automatique nécessite une étape de moins pour obtenir de bonnes performances d'image.

Compatibilité améliorée 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 de l'image 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 moment du lancement, ces chargeurs personnalisés avaient une portée limitée et ne pouvaient lire l'attribut width qu'à partir de l'élément image. En réponse 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 extension, 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 simple chargeur personnalisé peut utiliser l'API loaderParams pour choisir entre deux autres domaines d'image:

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, chaque alerte de performances des images que nous avons ajoutée à Angular faisait partie de la directive "NgOptimizedImage". Si vous n'utilisez pas cette directive dans l'application, vous ne recevrez aucune aide concernant les problèmes de performances des images.

Dans Angular 17, nous étendons le champ d'application des conseils sur les performances des images à toutes les applications Angular. Désormais, si nous détectons des modèles d'image qui nuisent aux performances, comme le chargement différé d'une image LCP ou le téléchargement d'un fichier 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, et nous sommes heureux de continuer à mettre en place des garde-fous pour éviter les erreurs courantes dans les applications Angular.

Et demain ?

Nous travaillons déjà dur pour développer la prochaine série 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 font partie de nos priorités. Ils sont couramment utilisés pour améliorer l'apparence du chargement des images dans les applications Web, mais peuvent nuire aux performances s'ils sont mal implémentés. Nous espérons créer un système d'espace réservé d'images axé sur les performances dans NgOptimizedImage. Consultez notre blog pour en savoir plus.