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 métriques Core Web Vitals. Angular et Next.js ont déjà intégré une police, ce qui est expliqué dans la première partie de cet article. La deuxième optimisation que nous allons aborder concerne l'intégration CSS essentielle, qui est désormais activée par défaut dans la CLI Angular et est en cours d'implémentation dans Nuxt.js.

Incorporation 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 l'affichage 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 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 l'en-tête.

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 police.

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

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

Pour l'optimiser, vous pouvez télécharger la feuille de style initiale au moment de la compilation et l'intégrer dans index.html. Cela permet d'ignorer 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, ajoutant ainsi 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 des polices est désormais disponible dans Next.js et Angular

Lorsque les développeurs de frameworks implémentent l'optimisation dans les outils sous-jacents, ils permettent aux applications nouvelles et existantes de l'activer plus facilement, ce qui apporte des améliorations à l'ensemble de l'écosystème.

Cette amélioration est activée par défaut à partir de Next.js v10.2 et d'Angular v11. Tous deux sont compatibles avec l'intégration des polices Google et Adobe. Angular prévoit d'introduire ce dernier dans la version 12.2.

Pour découvrir comment mettre en œuvre l'intégration de polices dans Next.js, consultez la vidéo expliquant cette optimisation dans le contexte d'Angular.

Intégrer le CSS critique

Une autre amélioration concerne les métriques First Contentful Paint (FCP) et Largest Contentful Paint (LCP) en intégrant le CSS critique. Le CSS essentiel d'une page inclut tous les styles utilisés lors de son affichage initial. Pour en savoir plus sur ce sujet, consultez la section Différer les fichiers CSS non critiques.

Nous avons observé que de nombreuses applications chargent les styles de manière synchrone, ce qui bloque l'affichage des applications. Une solution rapide consiste à charger 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, une fois le chargement terminé, remplacez la valeur de l'attribut par all:

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

Toutefois, cette pratique peut entraîner un clignotement des contenus sans style.

La page s'affiche 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. Ce clignotement se produit lorsque le navigateur commence à 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 "link", en mettant à jour l'attribut media sur all, puis il applique les styles au DOM.

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

L'intégration CSS critique, ainsi que le chargement de style asynchrone, peuvent améliorer le comportement de chargement. L'outil Critères identifie les styles utilisés sur la page en examinant les sélecteurs d'une feuille de style et en les comparant au code HTML. Lorsqu'il trouve une correspondance, il considère les styles correspondants comme faisant partie du 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 bestioles lisent et analysent le contenu de styles.css, puis font correspondre les deux sélecteurs avec le code HTML et découvrent que nous utilisons section button.primary. Enfin, les créatures intègrent 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.

Après avoir intégré le code CSS essentiel dans le code HTML, vous constaterez que le clignotement de la page a disparu:

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

L'intégration CSS essentielle 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 cet article, nous avons abordé certaines des collaborations 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 Pour obtenir la liste complète du travail d'optimisation que nous avons effectué pour les métriques Core Web Vitals, consultez l'article Présentation d'Aurora.