Optimiser le chargement des ressources

Dans le module précédent, nous avons exploré quelques théories sur le chemin critique du rendu et découvert comment les ressources qui bloquent l'affichage et les analyseurs peuvent retarder l'affichage initial d'une page. Maintenant que vous comprenez une partie de la théorie sous-jacente, vous êtes prêt à découvrir des techniques permettant d'optimiser le chemin de rendu critique.

Lors du chargement d'une page, de nombreuses ressources sont référencées dans son code HTML. Elles fournissent à la page son apparence et sa mise en page via CSS, ainsi que son interactivité via JavaScript. Ce module aborde un certain nombre de concepts importants liés à ces ressources et à leur incidence sur le temps de chargement d'une page.

Blocage du rendu

Comme nous l'avons vu dans le module précédent, CSS est une ressource qui bloque le rendu, car il empêche le navigateur d'afficher tout contenu jusqu'à la construction du CSS Object Model (CSSOM). Le navigateur bloque l'affichage pour empêcher l'affichage de contenu Flash of Unstyled Content (FOUC), ce qui est indésirable du point de vue de l'expérience utilisateur.

Dans la vidéo précédente, vous trouverez un bref FOUC qui vous permet de voir la page sans aucun style. Par la suite, tous les styles sont appliqués une fois le chargement du code CSS de la page terminé à partir du réseau, et la version sans style de la page est immédiatement remplacée par la version stylisée.

De manière générale, un FOUC est un élément que vous ne voyez pas normalement, mais il est important de comprendre ce concept afin de savoir pourquoi le navigateur bloque l'affichage de la page tant que le code CSS n'est pas téléchargé et appliqué à la page. Le blocage du rendu n'est pas nécessairement indésirable, mais il est préférable de réduire sa durée en maintenant l'optimisation de votre CSS.

Blocage de l'analyseur

Une ressource bloquant l'analyseur interrompt l'analyseur HTML, tel qu'un élément <script> sans attributs async ou defer. Lorsque l'analyseur rencontre un élément <script>, le navigateur doit évaluer et exécuter le script avant de passer à l'analyse du reste du code HTML. C'est normal, car les scripts peuvent modifier le DOM ou y accéder pendant un certain temps en cours de construction.

<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>

Lorsque vous utilisez des fichiers JavaScript externes (sans async ni defer), l'analyseur est bloqué entre le moment où le fichier est découvert et le moment où il est téléchargé, analysé et exécuté. Lorsque vous utilisez du code JavaScript intégré, l'analyseur est bloqué de la même manière jusqu'à ce que le script intégré soit analysé et exécuté.

L'outil d'analyse du préchargement

L'analyseur de préchargement est une optimisation du navigateur sous la forme d'un analyseur HTML secondaire qui analyse la réponse HTML brute pour trouver et extraire de manière spéculative des ressources avant que l'analyseur HTML principal ne les découvre autrement. Par exemple, l'analyseur de préchargement permet au navigateur de commencer à télécharger une ressource spécifiée dans un élément <img>, même lorsque l'analyseur HTML est bloqué lors de la récupération et du traitement de ressources telles que CSS et JavaScript.

Pour tirer parti de l'analyse de préchargement, les ressources critiques doivent être incluses dans le balisage HTML envoyé par le serveur. Les schémas de chargement de ressources suivants ne sont pas détectables par l'outil d'analyse de préchargement:

  • Images chargées par CSS à l'aide de la propriété background-image. Ces références d'image sont au format CSS et ne peuvent pas être découvertes par l'outil d'analyse de préchargement.
  • Scripts chargés dynamiquement sous la forme d'un balisage d'élément <script> injecté dans le DOM à l'aide de JavaScript ou de modules chargés à l'aide d'un import() dynamique.
  • Code HTML affiché sur le client à l'aide de JavaScript. Ce balisage est contenu dans des chaînes de ressources JavaScript et ne peut pas être identifié par l'analyseur de préchargement.
  • Déclarations CSS @import.

Ces modèles de chargement de ressources sont tous des ressources découvertes tardivement et ne bénéficient donc pas de l'outil d'analyse de préchargement. Évitez-les autant que possible. Toutefois, s'il n'est pas possible d'éviter de tels modèles, vous pouvez utiliser une indication preload pour éviter les retards de découverte des ressources.

CSS

Le CSS détermine la présentation et la mise en page d'une page. Comme décrit précédemment, CSS est une ressource qui bloque l'affichage. L'optimisation de votre CSS peut donc avoir un impact considérable sur le temps de chargement global des pages.

Réduction

La minification des fichiers CSS réduit la taille du fichier d'une ressource CSS, ce qui permet de les télécharger plus rapidement. Pour ce faire, la principale méthode consiste à supprimer le contenu d'un fichier CSS source, tel que les espaces et d'autres caractères invisibles, et à générer le résultat dans un fichier récemment optimisé:

/* Unminified CSS: */

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

Dans sa forme la plus élémentaire, la minimisation CSS est une optimisation efficace qui pourrait améliorer le FCP de votre site Web, voire le LCP dans certains cas. Des outils tels que les bundlers peuvent effectuer automatiquement cette optimisation dans les builds de production.

Supprimer les ressources CSS inutilisées

Avant d'afficher du contenu, le navigateur doit télécharger et analyser toutes les feuilles de style. Le temps nécessaire pour effectuer l'analyse inclut également les styles inutilisés sur la page actuelle. Si vous utilisez un bundler qui combine toutes les ressources CSS en un seul fichier, vos utilisateurs téléchargent probablement plus de code CSS que nécessaire pour afficher la page actuelle.

Pour identifier les CSS inutilisés pour la page actuelle, utilisez l'outil de couverture dans les outils pour les développeurs Chrome.

Capture d&#39;écran de l&#39;outil de couverture dans les outils pour les développeurs Chrome. Un fichier CSS sélectionné dans son volet inférieur affiche une quantité considérable de code CSS inutilisé par la mise en page actuelle.
L'outil de couverture des outils pour les développeurs Chrome permet de détecter les ressources CSS (et JavaScript) inutilisées par la page actuelle. Il permet de diviser les fichiers CSS en plusieurs ressources à charger par différentes pages, au lieu d'expédier un lot CSS beaucoup plus volumineux qui peut retarder l'affichage de la page.

La suppression des CSS inutilisés a un double effet: en plus de réduire le temps de téléchargement, vous optimisez la construction de l'arborescence de rendu, car le navigateur doit traiter moins de règles CSS.

Éviter les déclarations CSS @import

Même si cela peut sembler pratique, évitez les déclarations @import en CSS:

/* Don't do this: */
@import url('style.css');

Comme pour l'élément <link> en HTML, la déclaration @import en CSS vous permet d'importer une ressource CSS externe à partir d'une feuille de style. La principale différence entre ces deux approches est que l'élément HTML <link> fait partie de la réponse HTML. Il est donc découvert beaucoup plus tôt qu'un fichier CSS téléchargé par une déclaration @import.

En effet, pour qu'une déclaration @import soit découverte, le fichier CSS qui la contient doit d'abord être téléchargé. Il en résulte ce que l'on appelle une chaîne de requête qui, dans le cas des CSS, retarde le temps nécessaire pour qu'une page s'affiche initialement. Un autre inconvénient est que les feuilles de style chargées à l'aide d'une déclaration @import ne peuvent pas être découvertes par l'outil d'analyse de préchargement et deviennent donc des ressources qui bloquent l'affichage tardivement.

<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">

Dans la plupart des cas, vous pouvez remplacer @import à l'aide d'un élément <link rel="stylesheet">. Les éléments <link> permettent de télécharger les feuilles de style simultanément et réduisent le temps de chargement global, par opposition aux déclarations @import, qui téléchargent les feuilles de style consécutivement.

Intégrer les fichiers CSS critiques

Le temps de téléchargement des fichiers CSS peut augmenter le FCP d'une page. L'intégration de styles critiques dans le <head> du document élimine la requête réseau pour une ressource CSS. Lorsqu'elle est effectuée correctement, elle peut améliorer le temps de chargement initial lorsque le cache du navigateur d'un utilisateur n'est pas amorcé. Le code CSS restant peut être chargé de manière asynchrone ou ajouté à la fin de l'élément <body>.

<head>
  <title>Page Title</title>
  <!-- ... -->
  <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
  <!-- Other page markup... -->
  <link rel="stylesheet" href="non-critical.css">
</body>

En revanche, l'intégration d'une grande quantité de code CSS ajoute davantage d'octets à la réponse HTML initiale. Étant donné que les ressources HTML ne peuvent souvent pas être mises en cache pendant une durée très longue, voire pas du tout, cela signifie que le CSS intégré n'est pas mis en cache pour les pages suivantes qui pourraient utiliser le même CSS dans des feuilles de style externes. Testez et mesurez les performances de votre page pour vous assurer que les compromis en valent la peine.

Démonstrations CSS

JavaScript

JavaScript est à l'origine de la majeure partie de l'interactivité sur le Web, mais cela a un coût. Si vous envoyez trop de code JavaScript, votre page Web peut ralentir le chargement pendant son chargement, voire causer des problèmes de réactivité qui ralentissent les interactions, ce qui peut être frustrant pour les utilisateurs.

Code JavaScript qui bloque l'affichage

Lorsque vous chargez des éléments <script> sans les attributs defer ou async, le navigateur bloque l'analyse et l'affichage jusqu'à ce que le script soit téléchargé, analysé et exécuté. De même, les scripts intégrés bloquent l'analyseur jusqu'à ce que le script soit analysé et exécuté.

async et defer

async et defer permettent aux scripts externes de se charger sans bloquer l'analyseur HTML, tandis que les scripts (y compris les scripts intégrés) avec type="module" sont automatiquement différés. Cependant, async et defer présentent des différences qu'il est important de comprendre.

Représentation de divers mécanismes de chargement de script, qui détaillent les rôles d&#39;analyseur, de récupération et d&#39;exécution en fonction de divers attributs utilisés tels que async, defer, type=&#39;module et une combinaison des trois.
Source : https://html.spec.whatwg.org/multipage/scripting.html

Les scripts chargés avec async sont analysés et exécutés immédiatement une fois téléchargés, tandis que ceux chargés avec defer sont exécutés une fois l'analyse du document HTML terminée. Cela se produit en même temps que l'événement DOMContentLoaded du navigateur. En outre, les scripts async peuvent s'exécuter dans le désordre, tandis que les scripts defer sont exécutés dans l'ordre dans lequel ils apparaissent dans le balisage.

Affichage côté client

En règle générale, vous devez éviter d'utiliser JavaScript pour afficher le contenu critique ou l'élément LCP d'une page. C'est ce qu'on appelle le rendu côté client. Il s'agit d'une technique très utilisée dans les applications monopages (SPA).

Le balisage rendu par JavaScript ignore l'outil d'analyse de préchargement, car celui-ci ne peut pas voir les ressources contenues dans le balisage affiché par le client. Cela pourrait retarder le téléchargement de ressources essentielles, telles qu'une image LCP. Le navigateur ne commence à télécharger l'image LCP qu'une fois le script exécuté et ajouté l'élément au DOM. Par conséquent, le script ne peut être exécuté qu'une fois qu'il a été découvert, téléchargé et analysé. C'est ce qu'on appelle une chaîne de requête critique, qui doit être évitée.

En outre, le balisage de rendu à l'aide de JavaScript est plus susceptible de générer des tâches longues que le balisage téléchargé à partir du serveur en réponse à une requête de navigation. Une utilisation intensive du rendu côté client du code HTML peut avoir un impact négatif sur la latence des interactions. Cela est particulièrement vrai lorsque le DOM d'une page est très volumineux, ce qui déclenche un travail d'affichage important lorsque JavaScript modifie le DOM.

Réduction

Comme pour les CSS, la minification des ressources JavaScript réduit la taille du fichier d'une ressource de script. Cela peut accélérer les téléchargements et permettre au navigateur de passer plus rapidement au processus d'analyse et de compilation de JavaScript.

De plus, la minimisation de JavaScript va plus loin que la minimisation d'autres éléments, tels que CSS. Lorsque le code JavaScript est réduit, les éléments tels que les espaces, les tabulations et les commentaires ne sont pas seulement supprimés. Les symboles du code JavaScript source sont également raccourcis. Ce processus est parfois appelé uglification. Pour voir la différence, utilisez le code source JavaScript suivant:

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}

Lorsque le code source JavaScript précédent est uglifié, le résultat peut ressembler à l'extrait de code suivant:

// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

Dans l'extrait de code précédent, vous pouvez voir que la variable lisible scriptElement dans la source a été raccourcie en t. Lorsqu'elle est appliquée à un grand nombre de scripts, les économies réalisées peuvent être considérables sans affecter les fonctionnalités fournies par le code JavaScript de production d'un site Web.

Si vous utilisez un bundler pour traiter le code source de votre site Web, l'uglification est souvent effectuée automatiquement pour les builds de production. Les utilitaires tels que Terser sont également hautement configurables, ce qui vous permet d'ajuster l'agressivité de l'algorithme d'uglification afin de réaliser des économies maximales. Cependant, les valeurs par défaut de tout outil d'uglification sont généralement suffisantes pour trouver le juste équilibre entre la taille de la sortie et la préservation des fonctionnalités.

Démonstrations JavaScript

Tester vos connaissances

Quel est le meilleur moyen de charger plusieurs fichiers CSS dans le navigateur ?

La déclaration CSS @import
Réessayez.
Plusieurs éléments <link>
Bonne réponse !

À quoi sert l'outil d'analyse de préchargement du navigateur ?

Il s'agit d'un analyseur HTML secondaire qui examine le balisage brut afin d'identifier les ressources avant que l'analyseur DOM puisse les découvrir plus rapidement.
Bonne réponse !
Détecte les éléments <link rel="preload"> dans une ressource HTML.
Réessayez.

Pourquoi le navigateur bloque-t-il temporairement l'analyse HTML par défaut lors du téléchargement de ressources JavaScript ?

Pour éviter la présence de flashs de contenu non stylisé (FOUC).
Réessayez.
Parce que l'évaluation du code JavaScript est une tâche très gourmande en ressources processeur, et que la mise en pause de l'analyse HTML alloue davantage de bande passante au processeur pour terminer le chargement des scripts.
Réessayez.
Parce que les scripts peuvent modifier le DOM ou y accéder.
Bonne réponse !

Prochaine étape: Aider le navigateur avec des indices de ressources

Maintenant que vous savez comment les ressources chargées dans l'élément <head> peuvent affecter le chargement initial de la page et différentes métriques, il est temps de passer à autre chose. Dans le module suivant, les suggestions de ressources sont explorées et la manière dont elles peuvent fournir au navigateur des indications précieuses pour commencer à charger des ressources et à ouvrir des connexions aux serveurs multi-origines plus rapidement que le navigateur sans elles.