Intégrer des ressources dans les frameworks JavaScript

Amélioration de Largest Contentful Paint dans l'écosystème JavaScript.

Dans le cadre du projet Aurora, Google a travaillé avec des frameworks Web populaires pour s'assurer qu'ils fonctionnent bien selon les Core Web Vitals. L'intégration des polices est déjà disponible pour Angular et Next.js, comme expliqué dans la première partie de cet article. La deuxième optimisation que nous allons aborder est l'intégration CSS critique, qui est désormais activée par défaut dans la CLI Angular et dont l'implémentation est en cours dans Nuxt.js.

Inlining de police

Après avoir analysé des centaines d'applications, l'équipe Aurora a constaté que les développeurs incluaient souvent des polices dans leurs applications en les référençant dans l'élément <head> de index.html. Voici un exemple de ce à quoi cela ressemblerait lorsque vous incluez des icônes Material:

<!doctype html>
<html lang="en">
<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  ...
</html>

Même si ce modèle est entièrement valide et fonctionnel, il bloque le rendu de l'application et introduit une requête supplémentaire. Pour mieux comprendre ce qui se passe, examinez le code source de la feuille de style référencée dans le code HTML ci-dessus:

/* fallback */
@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}

.material-icons {
  /*...*/
}

Notez que la définition de font-face fait référence à un fichier externe hébergé sur fonts.gstatic.com. Lors du chargement de l'application, le navigateur doit d'abord télécharger la feuille de style d'origine référencée dans la section "head".

Image montrant comment le site Web doit envoyer une requête au serveur et télécharger la feuille de style externe
Tout d'abord, le site Web charge la feuille de style de la police.

Ensuite, le navigateur télécharge le fichier woff2, puis peut afficher l'application.

Image montrant les deux requêtes effectuées, l&#39;une pour la feuille de style de police et l&#39;autre pour le fichier de police.
Ensuite, une requête est envoyée pour charger la police.

Une opportunité d'optimisation consiste à télécharger la feuille de style initiale au moment de la compilation et à l'intégrer dans index.html. Cela évite un aller-retour complet vers le CDN au moment de l'exécution, ce qui réduit le temps de blocage.

Lors de la création de l'application, une requête est envoyée au CDN, qui extrait la feuille de style et l'intègre dans le fichier HTML, en ajoutant un <link rel=preconnect> au domaine. En appliquant cette technique, nous obtiendrions le résultat suivant:

<!doctype html>
<html lang="en">
<head>
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
  <style type="text/css">
  @font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
  ...
</html>

L'intégration de polices est désormais disponible dans Next.js et Angular

Lorsque les développeurs de framework implémentent l'optimisation dans l'outil sous-jacent, ils facilitent l'activation de cette fonctionnalité pour les applications existantes et nouvelles, ce qui améliore l'ensemble de l'écosystème.

Cette amélioration est activée par défaut à partir de Next.js 10.2 et Angular 11. Les deux acceptent l'intégration de polices Google et Adobe. Angular prévoit de lancer ce dernier dans la version 12.2.

Vous trouverez l'implémentation de l'intégration de polices dans Next.js sur GitHub et la vidéo expliquant cette optimisation dans le contexte d'Angular.

Intégrer les fichiers CSS critiques

Une autre amélioration consiste à améliorer les métriques First Contentful Paint (FCP) et Largest Contentful Paint (LCP) en insérant du CSS critique. Le CSS essentiel d'une page inclut tous les styles utilisés lors de son rendu initial. Pour en savoir plus, consultez Différer le CSS non critique.

Nous avons constaté que de nombreuses applications chargent des styles de manière synchrone, ce qui bloque le rendu de l'application. Pour résoudre rapidement ce problème, chargez les styles de manière asynchrone. Plutôt que de charger les scripts avec media="all", définissez la valeur de l'attribut media sur print, puis remplacez la valeur de l'attribut par all une fois le chargement terminé:

<link rel="stylesheet" href="..." media="print" onload="this.media='all'">

Toutefois, cette pratique peut entraîner le clignotement du contenu non stylisé.

La page semble clignoter lorsque les styles sont chargés.

La vidéo ci-dessus montre le rendu d'une page, qui charge ses styles de manière asynchrone. Le scintillement se produit parce que le navigateur commence d'abord à télécharger les styles, puis affiche le code HTML qui suit. Une fois que le navigateur a téléchargé les styles, il déclenche l'événement onload de l'élément de lien, met à jour l'attribut media en all et applique les styles au DOM.

Pendant le temps écoulé entre le rendu du code HTML et l'application des styles, la page est partiellement sans style. Lorsque le navigateur utilise les styles, nous constatons un scintillement, ce qui nuit à l'expérience utilisateur et entraîne des régressions dans le CLS (Cumulative Layout Shift).

L'intégration CSS critique, ainsi que le chargement asynchrone des styles, peuvent améliorer le comportement de chargement. L'outil créatures identifie les styles utilisés sur la page en examinant les sélecteurs dans une feuille de style et en les mettant en correspondance avec le code HTML. Lorsqu'il trouve une correspondance, il considère les styles correspondants comme faisant partie du code CSS critique et les intègre.

Voyons un exemple :

À éviter
<head>
   <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>
/* styles.css */
section button.primary {
  /* ... */
}
.list {
  /* ... */
}

Exemple avant l'intégration.

Dans l'exemple ci-dessus, les critters lisent et analysent le contenu de styles.css, puis font correspondre les deux sélecteurs au code HTML et découvrent que nous utilisons section button.primary. Enfin, les critters insèreront les styles correspondants dans le <head> de la page, ce qui donne:

À faire
<head>
  <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
  <style>
  section button.primary {
    /* ... */
  }
  </style>
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>

Exemple après l'intégration.

Une fois le CSS critique intégré au code HTML, le scintillement de la page disparaît:

Chargement de la page après l'intégration du CSS.

L'intégration du CSS critique est désormais disponible dans Angular et activée par défaut dans la version 12. Si vous utilisez la version 11, activez-la en définissant la propriété inlineCritical sur true dans angular.json. Pour activer cette fonctionnalité dans Next.js, ajoutez experimental: { optimizeCss: true } à votre next.config.js.

Conclusions

Dans ce post, nous avons abordé une partie de la collaboration entre Chrome et les frameworks Web. Si vous êtes l'auteur d'un framework et que vous reconnaissez certains des problèmes que nous avons résolus dans votre technologie, nous espérons que nos conclusions vous inciteront à appliquer des optimisations de performances similaires.

En savoir plus sur les améliorations Vous trouverez une liste complète des optimisations que nous avons effectuées pour les Core Web Vitals dans l'article Présentation d'Aurora.