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. Elle vise principalement à améliorer les performances, telles que mesurées par les métriques Core Web Vitals. Il regroupe des optimisations d'image courantes et des 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 la directive avec de nouvelles fonctionnalités. Cet article décrit la plus importante de ces nouvelles fonctionnalités, en insistant sur les raisons pour lesquelles nous avons choisi de donner la priorité à chacune d'entre elles et sur la manière 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, y compris grâce aux nouvelles fonctionnalités suivantes.

Mode de remplissage

Le dimensionnement de vos images à l'aide des attributs width et height constitue une optimisation extrêmement importante pour réduire le décalage de mise en page. En effet, les navigateurs doivent connaître le format de l'image pour lui libérer de l'espace. Toutefois, le dimensionnement des images représente un travail supplémentaire pour les développeurs d'applications et n'a aucun sens pour certains cas d'utilisation d'images.

La première fonctionnalité majeure ajoutée à l'aperçu post-développeur du composant Image vise à résoudre ce problème: le mode de remplissage. Il s'agit d'un moyen pour les développeurs d'inclure des images sans les dimensionner explicitement ni subir de décalage de mise en page.

Avec le mode de remplissage, les exigences de dimensionnement des images sont désactivées, et l'image est automatiquement stylisée pour remplir l'élément qui la contient. Cela permet de dissocier 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 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 dans un autre élément qui aurait eu 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 le <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 Srcset

L'une des techniques d'optimisation d'image les plus efficaces consiste à utiliser l'attribut srcset pour vous assurer que des images au format approprié 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 vos métriques LCP Core Web Vitals.

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 srcset automatisée à la directive NgOptimizedImage a été une étape importante après le lancement. Grâce à cet ajout, toute application utilisant un CDN prenant en charge le redimensionnement des images peut bénéficier de srcsets complets et personnalisables, automatiquement ajoutés à 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 est de taille fixe et qu'elle doit obtenir un attribut srcset dépendant de la densité, comme dans l'exemple suivant:

<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 d'arrêt pour de nombreuses tailles d'image et d'appareils courantes, en utilisant 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éconnexions

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 à transférer des fichiers image plus petits, mais il est tout aussi important de l'optimiser pour commencer le transfert dès que possible. Pour ce faire, vous pouvez utiliser des balises link rel="preconnect" pour établir la connexion au domaine de votre image.

Dès le départ, NgOptimizedImage vous avertit si vous ne parvenez pas à établir une préconnexion au domaine de votre image LCP. Toutefois, cet avertissement n'est pas la solution idéale. Nous préférons simplement résoudre le problème pour vous. Et c'est exactement ce que fait désormais NgOptimizedImage, avec la génération automatique de préconnexions.

Pour prendre en charge cette fonctionnalité, nous utilisons l'analyse de code statique afin d'essayer 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 encore y avoir des cas où des liens de préconnexion manuelle sont nécessaires, mais pour la plupart des utilisateurs, une 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'application sous forme d'images. Un ensemble de chargeurs intégrés est inclus pour les CDN couramment utilisés. Vous pouvez également utiliser des chargeurs personnalisés, qui vous permettent d'intégrer NgOptimizedImage dans presque toutes les solutions d'hébergement d'images.

Au lancement, ces chargeurs personnalisés avaient une portée limitée et ne pouvaient lire que l'attribut width à 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 expansion, les chargeurs personnalisés peuvent être aussi simples ou aussi complexes que nécessaire pour 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 domaines d'image différents:

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 détaillés sur les performances des images

Jusqu'à présent, toutes les alertes liées aux performances des images que nous avions ajoutées à Angular étaient incluses dans la directive NgOptimizedImage. Si vous n'utilisez pas la directive dans l'application, vous n'obtiendrez aucune aide sur les problèmes de performances des images.

Dans Angular 17, nous étendons la portée des conseils sur les performances des images afin d'inclure toutes les applications Angular. Désormais, si nous détectons des modèles d'image dont nous savons qu'ils nuisent aux performances, tels que 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, et nous sommes ravis de continuer à créer des garde-fous pour éviter les erreurs courantes dans les applications Angular.

Et demain ?

Nous mettons tout en œuvre pour développer la prochaine série de fonctionnalités pour NgOptimizedImage. Bien que les performances des images restent notre préoccupation majeure, 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 attrayante pour inclure des images dans les applications Angular.

L'une de nos priorités est les espaces réservés aux images. Ils sont couramment utilisés pour améliorer l'apparence du chargement d'image sur les applications Web, mais peuvent nuire aux performances s'ils sont mal implémentés. Nous espérons intégrer un système d'espace réservé aux images axé sur les performances dans NgOptimizedImage. Consultez régulièrement notre blog pour vous tenir informé.