Affichage côté client du code HTML et de l'interactivité

Le rendu HTML avec JavaScript est différent du rendu HTML envoyé par le serveur, ce qui peut affecter les performances. Ce guide vous explique la différence entre ces deux concepts et ce que vous pouvez faire pour préserver les performances de rendu de votre site Web, en particulier en ce qui concerne les interactions.

L'analyse et le rendu du code HTML sont des tâches que les navigateurs effectuent très bien par défaut pour les sites Web qui utilisent la logique de navigation intégrée du navigateur, parfois appelée "chargements de page traditionnels" ou "navigations dures". Ces sites Web sont parfois appelés applications multipages (MPA).

Toutefois, les développeurs peuvent contourner les paramètres par défaut du navigateur pour répondre aux besoins de leur application. C'est certainement le cas pour les sites Web qui utilisent le modèle d'application monopage (SPA), qui crée dynamiquement de grandes parties du HTML/DOM sur le client avec JavaScript. Ce modèle de conception est appelé "rendu côté client". Il peut avoir des effets sur l'Interaction to Next Paint (INP) de votre site Web si la charge de travail est excessive.

Ce guide vous aidera à évaluer la différence entre l'utilisation du code HTML envoyé par le serveur au navigateur et sa création sur le client avec JavaScript. Il vous montrera également comment cette dernière méthode peut entraîner une latence d'interaction élevée à des moments cruciaux.

Comment le navigateur affiche le code HTML fourni par le serveur

Le modèle de navigation utilisé dans les chargements de page traditionnels implique de recevoir du code HTML du serveur à chaque navigation. Si vous saisissez une URL dans la barre d'adresse de votre navigateur ou si vous cliquez sur un lien dans une MPA, les événements suivants se produisent :

  1. Le navigateur envoie une requête de navigation pour l'URL fournie.
  2. Le serveur répond avec du code HTML par blocs.

La dernière étape est essentielle. Il s'agit également de l'une des optimisations de performances les plus fondamentales dans l'échange serveur/navigateur, appelée streaming. Si le serveur peut commencer à envoyer du code HTML dès que possible et que le navigateur n'attend pas que la réponse complète arrive, le navigateur peut traiter le code HTML par blocs au fur et à mesure de son arrivée.

Capture d'écran de l'analyse du code HTML envoyé par le serveur, visualisée dans le panneau "Performances" des outils pour les développeurs Chrome. À mesure que le code HTML est diffusé, des blocs sont traités dans plusieurs tâches plus courtes, et le rendu est incrémentiel.
Analyse et rendu du code HTML fourni par le serveur, tels qu'ils sont visualisés dans le panneau "Performances" des outils pour les développeurs Chrome. Les tâches liées à l'analyse et au rendu du code HTML sont divisées en blocs.

Comme la plupart des opérations qui se produisent dans le navigateur, l'analyse HTML se déroule dans des tâches. Lorsque le code HTML est diffusé en flux continu du serveur vers le navigateur, ce dernier optimise son analyse en le faisant petit à petit, à mesure que des blocs de ce flux arrivent. Par conséquent, le navigateur cède la place au thread principal de manière périodique après le traitement de chaque bloc, ce qui évite les tâches longues. Cela signifie que d'autres tâches peuvent être effectuées pendant l'analyse du code HTML, y compris le rendu incrémentiel nécessaire pour présenter une page à l'utilisateur, ainsi que le traitement des interactions utilisateur qui peuvent se produire pendant la période de démarrage cruciale de la page. Cette approche se traduit par un meilleur score Interaction to Next Paint (INP) pour la page.

Conclusion ? Lorsque vous diffusez du code HTML depuis le serveur, vous bénéficiez sans frais de l'analyse et du rendu incrémentiels du code HTML, ainsi que du transfert automatique vers le thread principal. Ce n'est pas le cas avec le rendu côté client.

Comment le navigateur affiche le code HTML fourni par JavaScript

Bien que chaque demande de navigation vers une page nécessite une certaine quantité de code HTML fourni par le serveur, certains sites Web utilisent le modèle SPA. Cette approche implique souvent que le serveur fournit une charge utile HTML initiale minimale, mais que le client remplit ensuite la zone de contenu principal d'une page avec du code HTML assemblé à partir des données récupérées sur le serveur. Les navigations suivantes (parfois appelées "navigations logicielles" dans ce cas) sont entièrement gérées par JavaScript pour remplir la page avec du nouveau code HTML.

Le rendu côté client peut également se produire dans des cas plus limités où du code HTML est ajouté dynamiquement au DOM via JavaScript.

Voici quelques méthodes courantes pour créer du code HTML ou l'ajouter au DOM via JavaScript :

  1. La propriété innerHTML vous permet de définir le contenu d'un élément existant à l'aide d'une chaîne que le navigateur analyse dans le DOM.
  2. La méthode document.createElement vous permet de créer des éléments à ajouter au DOM sans utiliser l'analyse HTML du navigateur.
  3. La méthode document.write vous permet d'écrire du code HTML dans le document (et le navigateur l'analyse, comme dans l'approche 1). Toutefois, pour plusieurs raisons, l'utilisation de document.write est fortement déconseillée.
Capture d'écran de l'analyse du code HTML rendu via JavaScript visualisée dans le panneau "Performances" des outils pour les développeurs Chrome. Le travail s'effectue dans une seule et longue tâche qui bloque le thread principal.
Analyse et rendu du code HTML via JavaScript sur le client, tels qu'ils sont visualisés dans le panneau "Performances" des outils pour les développeurs Chrome. Les tâches impliquées dans l'analyse et le rendu ne sont pas segmentées, ce qui entraîne une tâche longue qui bloque le thread principal.

Les conséquences de la création de code HTML/DOM via JavaScript côté client peuvent être importantes :

  • Contrairement au code HTML diffusé par le serveur en réponse à une requête de navigation, les tâches JavaScript sur le client ne sont pas automatiquement segmentées, ce qui peut entraîner de longues tâches qui bloquent le thread principal. Cela signifie que l'INP de votre page peut être affecté négativement si vous créez trop de code HTML/DOM à la fois sur le client.
  • Si le code HTML est créé sur le client au démarrage, les ressources référencées dans celui-ci ne seront pas découvertes par le scanner de préchargement du navigateur. Cela aura certainement un impact négatif sur le Largest Contentful Paint (LCP) d'une page. Bien qu'il ne s'agisse pas d'un problème de performances d'exécution (mais plutôt d'un problème de latence réseau lors de la récupération de ressources importantes), vous ne souhaitez pas que le temps LCP de votre site Web soit affecté en contournant cette optimisation fondamentale des performances du navigateur.

Que faire face à l'impact sur les performances du rendu côté client ?

Si votre site Web dépend fortement du rendu côté client et que vous avez observé de mauvaises valeurs INP dans vos données de terrain, vous vous demandez peut-être si le rendu côté client est lié au problème. Par exemple, si votre site Web est une SPA, vos données de champ peuvent révéler des interactions responsables d'un travail de rendu considérable.

Quelle que soit la cause, voici quelques pistes à explorer pour résoudre le problème.

Fournissez autant de code HTML du serveur que possible.

Comme indiqué précédemment, le navigateur gère le code HTML du serveur de manière très performante par défaut. Il fractionne l'analyse et le rendu du code HTML de manière à éviter les longues tâches et à optimiser la durée totale du thread principal. Cela entraîne une diminution du Total Blocking Time (TBT), qui est fortement corrélé à l'INP.

Vous utilisez peut-être un framework frontend pour créer votre site Web. Si c'est le cas, assurez-vous d'afficher le code HTML du composant sur le serveur. Cela limitera la quantité de rendu côté client initial dont votre site Web aura besoin, ce qui devrait améliorer l'expérience.

  • Pour React, vous devez utiliser l'API Server DOM pour afficher le code HTML sur le serveur. Toutefois, sachez que la méthode traditionnelle de rendu côté serveur utilise une approche synchrone, ce qui peut entraîner un temps de latence du premier octet (TTFB) plus long, ainsi que des métriques ultérieures telles que First Contentful Paint (FCP) et LCP. Dans la mesure du possible, assurez-vous d'utiliser les API de streaming pour Node.js ou d'autres environnements d'exécution JavaScript afin que le serveur puisse commencer à diffuser du code HTML au navigateur le plus rapidement possible. Next.js, un framework basé sur React, fournit de nombreuses bonnes pratiques par défaut. En plus d'afficher automatiquement le code HTML sur le serveur, il peut également générer statiquement le code HTML pour les pages qui ne changent pas en fonction du contexte utilisateur (comme l'authentification).
  • Vue effectue également le rendu côté client par défaut. Toutefois, comme React, Vue peut également rendre le code HTML de votre composant sur le serveur. Profitez de ces API côté serveur lorsque cela est possible, ou envisagez une abstraction de niveau supérieur pour votre projet Vue afin de faciliter l'implémentation des bonnes pratiques.
  • Svelte affiche le code HTML sur le serveur par défaut. Toutefois, si le code de votre composant a besoin d'accéder à des espaces de noms exclusifs au navigateur (window, par exemple), vous ne pourrez peut-être pas afficher le code HTML de ce composant sur le serveur. Explorez d'autres approches chaque fois que possible afin d'éviter le rendu côté client inutile. SvelteKit, qui est à Svelte ce que Next.js est à React, intègre autant de bonnes pratiques que possible dans vos projets Svelte. Vous pouvez ainsi éviter les pièges potentiels dans les projets qui utilisent Svelte seul.

Limiter le nombre de nœuds DOM créés sur le client

Lorsque les DOM sont volumineux, le traitement nécessaire pour les afficher a tendance à augmenter. Que votre site Web soit une SPA à part entière ou qu'il injecte de nouveaux nœuds dans un DOM existant à la suite d'une interaction pour une MPA, pensez à conserver ces DOM aussi petits que possible. Cela permettra de réduire le travail requis lors du rendu côté client pour afficher ce code HTML, ce qui devrait vous aider à maintenir l'INP de votre site Web à un niveau bas.

Envisager une architecture de service worker de streaming

Il s'agit d'une technique avancée qui ne fonctionne pas forcément facilement dans tous les cas d'utilisation. Toutefois, elle peut transformer votre MPA en un site Web qui semble se charger instantanément lorsque les utilisateurs passent d'une page à l'autre. Vous pouvez utiliser un service worker pour prémettre en cache les parties statiques de votre site Web dans CacheStorage tout en utilisant l'API ReadableStream pour récupérer le reste du code HTML d'une page à partir du serveur.

Lorsque vous utilisez cette technique avec succès, vous ne créez pas de code HTML sur le client. Toutefois, le chargement instantané des partiels de contenu à partir du cache donnera l'impression que votre site se charge rapidement. Les sites Web qui utilisent cette approche peuvent donner l'impression d'être des SPA, mais sans les inconvénients du rendu côté client. Il réduit également la quantité de code HTML que vous demandez au serveur.

En bref, une architecture de service worker de streaming ne remplace pas la logique de navigation intégrée du navigateur, mais elle y ajoute des éléments. Pour savoir comment y parvenir avec Workbox, consultez Applications multipages plus rapides avec les flux.

Conclusion

La façon dont votre site Web reçoit et affiche le code HTML a un impact sur ses performances. Lorsque vous vous appuyez sur le serveur pour envoyer tout (ou la majeure partie) du code HTML nécessaire au fonctionnement de votre site Web, vous bénéficiez de nombreux avantages : analyse et rendu incrémentaux, et cession automatique au thread principal pour éviter les tâches longues.

Le rendu HTML côté client introduit un certain nombre de problèmes de performances potentiels qui peuvent être évités dans de nombreux cas. Toutefois, en raison des exigences de chaque site Web, il n'est pas possible de l'éviter à 100 % du temps. Pour atténuer les tâches longues potentielles qui peuvent résulter d'un rendu excessif côté client, assurez-vous d'envoyer autant de code HTML de votre site Web que possible depuis le serveur, de maintenir la taille de votre DOM aussi petite que possible pour le code HTML qui doit être rendu côté client, et d'envisager des architectures alternatives pour accélérer la diffusion du code HTML au client tout en tirant parti de l'analyse et du rendu incrémentaux que le navigateur fournit pour le code HTML chargé depuis le serveur.

Si vous parvenez à réduire au maximum le rendu côté client de votre site Web, vous améliorerez non seulement son INP, mais aussi d'autres métriques telles que le LCP, le TBT et, dans certains cas, même le TTFB.

Image principale d'Unsplash, par Maik Jonietz.