Rendu sur le Web

Publié le 6 février 2019, dernière mise à jour le 5 janvier 2026

L'une des décisions fondamentales que les développeurs Web doivent prendre est de déterminer où implémenter la logique et le rendu dans leur application. Cela peut être difficile, car il existe de nombreuses façons de créer un site Web.

Notre compréhension de cet espace est basée sur notre travail dans Chrome, qui consiste à discuter avec de grands sites au cours des dernières années. De manière générale, nous encourageons les développeurs à envisager le rendu côté serveur ou le rendu statique plutôt qu'une approche de réhydratation complète.

Pour mieux comprendre les architectures parmi lesquelles nous choisissons lorsque nous prenons cette décision, nous avons besoin d'une terminologie cohérente et d'un framework partagé pour chaque approche. Vous pouvez ensuite mieux évaluer les compromis de chaque approche de rendu du point de vue des performances de la page.

Terminologie

Tout d'abord, nous définissons certains termes que nous utiliserons.

Affichage

Affichage côté serveur (SSR)
Affichage d'une application sur le serveur pour envoyer du code HTML plutôt que du code JavaScript au client.
Affichage côté client (CSR)
Affichage d'une application dans un navigateur, à l'aide de JavaScript pour modifier le DOM.
Prérendu
Exécution d'une application côté client au moment de la compilation pour capturer son état initial en tant que code HTML statique. Remarque : Le "prérendu" dans ce sens est différent du prérendu du navigateur pour les futures navigations.
Hydratation
Exécution de scripts côté client pour ajouter l'état de l'application et l'interactivité au code HTML affiché côté serveur. L'hydratation suppose que le DOM ne change pas.
Réhydratation
Bien qu'elle soit souvent utilisée pour désigner la même chose que l'hydratation, la réhydratation implique la mise à jour régulière du DOM avec le dernier état, y compris après l'hydratation initiale.

Performances

Time to First Byte (TTFB)
Temps écoulé entre le moment où vous cliquez sur un lien et le chargement du premier octet de contenu sur la nouvelle page.
First Contentful Paint (FCP)
Moment où le contenu demandé (corps de l'article, etc.) devient visible.
Interaction to Next Paint (INP)
Métrique représentative qui évalue si une page répond rapidement et de manière cohérente aux entrées de l'utilisateur.
Total Blocking Time (TBT)
Métrique proxy pour l'INP qui calcule la durée pendant laquelle le thread principal a été bloqué lors du chargement de la page.

Affichage côté serveur

L'affichage côté serveur génère le code HTML complet d'une page sur le serveur en réponse à la navigation. Cela évite les allers-retours supplémentaires pour la récupération des données et la création de modèles sur le client, car le moteur de rendu les gère avant que le navigateur ne reçoive de réponse.

L'affichage côté serveur produit généralement un FCP rapide. L'exécution de la logique de la page et l'affichage sur le serveur vous permet d'éviter d'envoyer beaucoup de code JavaScript au client. Cela permet de réduire le TBT d'une page, ce qui peut également entraîner une INP plus faible, car le thread principal n'est pas bloqué aussi souvent lors du chargement de la page. Lorsque le thread principal est bloqué moins souvent, les interactions de l'utilisateur ont plus de chances de s'exécuter plus tôt.

Cela est logique, car avec l'affichage côté serveur, vous n'envoyez que du texte et des liens au navigateur de l'utilisateur. Cette approche peut fonctionner correctement pour diverses conditions d'appareil et de réseau et ouvre des optimisations intéressantes pour le navigateur, telles que l'analyse de documents en streaming.

Diagramme montrant le rendu côté serveur et l'exécution de JavaScript affectant le FCP et le TTI.
FCP et TTI avec affichage côté serveur.

Avec l'affichage côté serveur, les utilisateurs sont moins susceptibles d'attendre l'exécution du code JavaScript lié au processeur avant de pouvoir utiliser votre site. Même lorsque vous ne pouvez pas éviter le code JavaScript tiers, l'utilisation de l'affichage côté serveur pour réduire vos propres coûts JavaScript propriétaires peut vous donner plus de budget pour le reste. Toutefois, cette approche présente un compromis potentiel : la génération de pages sur le serveur prend du temps, ce qui peut augmenter le TTFB de votre page.

La question de savoir si l'affichage côté serveur est suffisant pour votre application dépend en grande partie de ce type d'expérience que vous créez. Le débat sur les applications correctes de l'affichage côté serveur par rapport à l'affichage côté client est ancien, mais vous pouvez toujours choisir d'utiliser l'affichage côté serveur pour certaines pages et pas pour d'autres. Certains sites ont adopté des techniques d'affichage hybrides avec succès. Par exemple, Netflix affiche côté serveur ses pages de destination relativement statiques, tout en prefetching le code JavaScript pour les pages à forte interaction, ce qui donne à ces pages plus lourdes affichées côté client une meilleure chance de se charger rapidement.

Avec de nombreux frameworks, bibliothèques et architectures modernes, vous pouvez afficher la même application à la fois sur le client et sur le serveur. Vous pouvez utiliser ces techniques pour l'affichage côté serveur. Toutefois, les architectures dans lesquelles l'affichage se produit à la fois sur le serveur et sur le client constituent leur propre classe de solution avec de très différentes caractéristiques de performances et compromis. Les utilisateurs de React peuvent utiliser des API DOM côté serveur ou des solutions basées sur celles-ci, comme Next.js, pour l'affichage côté serveur. Les utilisateurs de Vue peuvent utiliser le guide d'affichage côté serveur de Vue ou Nuxt. Angular dispose d'Universal.

La plupart des solutions populaires utilisent une forme d'hydratation. Soyez donc conscient des approches utilisées par votre outil.

Affichage statique

L'affichage statique se produit au moment de la compilation. Cette approche offre un FCP rapide, ainsi qu'un TBT et une INP plus faibles, à condition de limiter la quantité de code JavaScript côté client sur vos pages. Contrairement à l'affichage côté serveur, elle permet également d'obtenir un TTFB rapide et cohérent, car le code HTML d'une page n'a pas besoin d'être généré dynamiquement sur le serveur. En règle générale, l'affichage statique consiste à produire un fichier HTML distinct pour chaque URL à l'avance. Avec les réponses HTML générées à l'avance, vous pouvez déployer des affichages statiques sur plusieurs CDN pour profiter de la mise en cache en périphérie.

Diagramme montrant le rendu statique et l'exécution JavaScript facultative affectant le FCP et le TTI.
FCP et TTI avec affichage statique.

Les solutions d'affichage statique sont de toutes formes et de toutes tailles. Des outils comme Gatsby sont conçus pour donner aux développeurs l'impression que leur application est affichée de manière dynamique, et non générée en tant qu'étape de compilation. Les outils de génération de sites statiques tels que 11ty, Jekyll, et Metalsmith adoptent leur nature statique, offrant une approche plus axée sur les modèles.

L'un des inconvénients de l'affichage statique est qu'il doit générer des fichiers HTML individuels pour chaque URL possible. Cela peut être difficile, voire impossible lorsque vous devez prédire ces URL à l'avance et pour les sites comportant un grand nombre de pages uniques.

Les utilisateurs de React connaissent peut-être l'exportation statique Gatsby, Next.js ou Navi, qui facilitent la création de pages à partir de composants. Toutefois, l'affichage statique et le prérendu se comportent différemment : les pages affichées de manière statique sont interactives sans avoir à exécuter beaucoup de code JavaScript côté client, tandis que le prérendu améliore le FCP d'une application à page unique qui doit être démarrée sur le client pour rendre les pages réellement interactives.

Si vous ne savez pas si une solution donnée est un affichage statique ou un prérendu, essayez de désactiver JavaScript et de charger la page que vous souhaitez tester. Pour les pages affichées de manière statique, la plupart des fonctionnalités interactives existent toujours sans JavaScript. Les pages prérendues peuvent toujours comporter certaines fonctionnalités de base, comme des liens avec JavaScript désactivé, mais la majeure partie de la page est inactive.

Un autre test utile consiste à utiliser la limitation du réseau dans les Outils pour les développeurs Chrome et à voir la quantité de code JavaScript téléchargée avant qu'une page ne devienne interactive. Le prérendu nécessite généralement plus de code JavaScript pour devenir interactif, et ce code JavaScript a tendance à être plus complexe que l' approche d'amélioration progressive utilisée dans l'affichage statique.

Affichage côté serveur ou affichage statique

L'affichage côté serveur n'est pas la meilleure solution pour tout, car sa nature dynamique peut entraîner des coûts de calcul importants. De nombreuses solutions d'affichage côté serveur ne vident pas tôt, retardent le TTFB ou doublent les données envoyées (par exemple, les états intégrés utilisés par JavaScript sur le client). Dans React, renderToString() peut être lent, car il est synchrone et monothread. Les API DOM côté serveur React plus récentes sont compatibles avec le streaming, ce qui permet d'obtenir plus rapidement la partie initiale d'une réponse HTML dans le navigateur, tandis que le reste est toujours généré sur le serveur.

Pour que l'affichage côté serveur soit "correct", il peut être nécessaire de trouver ou de créer une solution pour la mise en cache des composants, la gestion de la consommation de mémoire, l'utilisation de techniques de mémorisation, et d'autres problèmes. Vous traitez ou recréez souvent la même application deux fois, une fois sur le client et une fois sur le serveur. L'affichage plus rapide du contenu côté serveur ne vous donne pas nécessairement moins de travail à faire. Si vous avez beaucoup de travail sur le client après l'arrivée d'une réponse HTML générée par le serveur, cela peut toujours entraîner un TBT et une INP plus élevés pour votre site Web.

L'affichage côté serveur génère du code HTML à la demande pour chaque URL, mais il peut être plus lent que la simple diffusion de contenu affiché statiquement. Si vous pouvez effectuer le travail supplémentaire, l'affichage côté serveur et la mise en cache HTML peuvent réduire considérablement le temps d'affichage du serveur. L'avantage de l'affichage côté serveur est la possibilité d'extraire davantage de données "en direct" et de répondre à un ensemble de requêtes plus complet que ce qui est possible avec l'affichage statique. Les pages qui nécessitent une personnalisation sont un exemple concret du type de requête qui ne fonctionne pas bien avec l'affichage statique

L'affichage côté serveur peut également présenter des décisions intéressantes lors de la création d'une PWA. Est-il préférable d'utiliser la mise en cache du service worker sur toute la page ou d'afficher côté serveur des éléments de contenu individuels ?

Affichage côté client

L'affichage côté client signifie afficher des pages directement dans le navigateur avec JavaScript. Toutes les logiques, la récupération des données, la création de modèles et le routage sont gérés sur le client plutôt que sur le serveur. Le résultat effectif est que davantage de données sont transmises à l'appareil de l'utilisateur depuis le serveur, ce qui présente ses propres compromis.

L'affichage côté client peut être difficile à créer et à maintenir rapide pour les appareils mobiles. En travaillant un peu pour maintenir un budget JavaScript serré et apporter de la valeur en aussi peu d'allers-retours que possible, vous pouvez faire en sorte que l'affichage côté client reproduise presque les performances de l'affichage côté serveur pur. Vous pouvez accélérer le fonctionnement de l'analyseur en fournissant des scripts et des données critiques à l'aide de <link rel=preload> Nous vous recommandons également d'envisager d'utiliser des modèles tels que PRPL pour vous assurer que les navigations initiales et suivantes sont instantanées.

Diagramme montrant le rendu côté client affectant le FCP et le TTI.
FCP et TTI avec affichage côté client.

Le principal inconvénient de l'affichage côté client est que la quantité de code JavaScript requise a tendance à augmenter à mesure qu'une application se développe, ce qui peut avoir un impact sur l'INP d'une page. Cela devient particulièrement difficile avec l'ajout de nouvelles bibliothèques JavaScript, de polyfills et de code tiers, qui se font concurrence pour la puissance de traitement et doivent souvent être traités avant que le contenu d'une page ne puisse être affiché.

Les expériences qui utilisent l'affichage côté client et reposent sur de grands groupes JavaScript doivent envisager une division agressive du code pour réduire le TBT et l'INP lors du chargement de la page, ainsi que le chargement différé de JavaScript pour ne diffuser que ce dont l'utilisateur a besoin, au moment où il en a besoin. Pour les expériences avec peu ou pas d'interactivité, l'affichage côté serveur peut représenter une solution plus évolutive à ces problèmes.

Pour les personnes qui créent des applications à page unique, l'identification des parties principales de l'interface utilisateur partagées par la plupart des pages vous permet d'appliquer la technique de mise en cache de l'interface de l'application. Combinée aux service workers, cela peut améliorer considérablement les performances perçues lors des visites répétées, car la page peut charger très rapidement son code HTML et ses dépendances depuis CacheStorage.

La réhydratation combine l'affichage côté serveur et côté client

L'hydratation est une approche qui atténue les compromis entre l'affichage côté client et côté serveur en effectuant les deux. Les requêtes de navigation, telles que les chargements ou rechargements de pages complètes, sont gérées par un serveur qui affiche l'application au format HTML. Le code JavaScript et les données utilisés pour l'affichage sont ensuite intégrés au document résultant. Lorsqu'elle est effectuée avec soin, cette opération permet d'obtenir un FCP rapide comme l'affichage côté serveur, puis "reprendre" en affichant à nouveau sur le client.

Il s'agit d'une solution efficace, mais elle peut présenter des inconvénients considérables en termes de performances

Le principal inconvénient de l'affichage côté serveur avec réhydratation est qu'il peut avoir un impact négatif important sur le TBT et l'INP, même s'il améliore le FCP. Les pages affichées côté serveur peuvent sembler chargées et interactives, mais ne peuvent pas réellement répondre aux entrées tant que les scripts côté client des composants ne sont pas exécutés et que les gestionnaires d'événements n'ont pas été associés. Sur mobile, cela peut prendre minutes, ce qui est déroutant et frustrant pour l'utilisateur.

Problème de réhydratation : une application au prix de deux

Pour que le code JavaScript côté client prenne le relais avec précision là où le serveur s'est arrêté, sans avoir à demander à nouveau toutes les données avec lesquelles le serveur a affiché son code HTML, la plupart des solutions d'affichage côté serveur sérialisent la réponse des dépendances de données d'une interface utilisateur en tant que balises de script dans le document. Comme cela duplique beaucoup de code HTML, la réhydratation peut entraîner plus de problèmes qu'une simple interactivité retardée.

Document HTML contenant une interface utilisateur sérialisée, des données intégrées et un script bundle.js.

Le serveur renvoie une description de l'interface utilisateur de l'application en réponse à une requête de navigation, mais il renvoie également les données sources utilisées pour composer cette interface utilisateur, ainsi qu'une copie complète de l'implémentation de l'interface utilisateur qui démarre ensuite sur le client. L'interface utilisateur ne devient interactive qu'une fois le chargement et l'exécution de bundle.js terminés.

Les métriques de performances collectées à partir de sites Web réels utilisant l'affichage côté serveur et la réhydratation indiquent que ce n'est que rarement la meilleure option. La raison la plus importante est son effet sur l'expérience utilisateur, lorsqu'une page semble prête, mais qu'aucune de ses fonctionnalités interactives ne fonctionne.

Effets négatifs de l'affichage côté client sur le TTI.

Il y a de l'espoir pour l'affichage côté serveur avec réhydratation. À court terme, l'utilisation de l'affichage côté serveur uniquement pour le contenu hautement mis en cache peut réduire le TTFB, ce qui produit des résultats similaires au prérendu. La réhydratation incrémentale, progressive ou partielle pourrait être la clé pour rendre cette technique plus viable à l'avenir.

Diffuser l'affichage côté serveur et réhydrater progressivement

L'affichage côté serveur a connu un certain nombre d'évolutions au cours des dernières années.

L'affichage côté serveur en streaming vous permet d'envoyer du code HTML par blocs que le navigateur peut afficher progressivement à mesure qu'il est reçu. Cela permet d'obtenir plus rapidement le balisage pour vos utilisateurs, ce qui accélère votre FCP. Dans React, les flux étant asynchrones dans renderToPipeableStream(), par rapport à synchrone renderToString(), la contre-pression est bien gérée.

La réhydratation progressive mérite également d'être envisagée (React l'a implémentée). Avec cette approche, les éléments individuels d'une application affichée côté serveur sont "démarrés" au fil du temps, au lieu de l'approche courante actuelle qui consiste à initialiser l'ensemble de l' application en une seule fois. Cela peut aider à réduire la quantité de code JavaScript nécessaire pour rendre les pages interactives, car cela vous permet de différer la mise à niveau côté client des parties de la page à faible priorité pour éviter qu'elle ne bloque le thread principal, ce qui permet aux interactions de l'utilisateur de se produire plus tôt après qu'il les a initiées.

La réhydratation progressive peut également vous aider à éviter l'un des pièges les plus courants de la réhydratation de l'affichage côté serveur : un arbre DOM affiché côté serveur est détruit, puis immédiatement reconstruit, le plus souvent parce que l'affichage initial synchrone côté client nécessitait des données qui n'étaient pas tout à fait prêtes, souvent une Promise qui n'a pas encore été résolue.

Réhydratation partielle

La réhydratation partielle s'est avérée difficile à implémenter. Cette approche est une extension de la réhydratation progressive qui analyse les éléments individuels de la page (composants, vues ou arborescences) et identifie les éléments peu interactifs ou non réactifs. Pour chacune de ces parties principalement statiques, le code JavaScript correspondant est ensuite transformé en références inertes et en fonctionnalités décoratives, ce qui réduit leur empreinte côté client à presque zéro.

L'approche de réhydratation partielle présente ses propres problèmes et compromis. Elle pose des défis intéressants pour la mise en cache, et la navigation côté client signifie que nous ne pouvons pas supposer que le code HTML affiché côté serveur pour les parties inertes de l'application est disponible sans chargement complet de la page.

Affichage trisomorphe

Si les service workers sont une option pour vous, envisagez l'affichage trisomorphe. Cette technique vous permet d'utiliser l'affichage côté serveur en streaming pour les navigations initiales ou non JavaScript, puis de faire en sorte que votre service worker prenne en charge l'affichage du code HTML pour les navigations après son installation. Cela permet de maintenir à jour les composants et les modèles mis en cache, et d'activer les navigations de type SPA pour afficher de nouvelles vues dans la même session. Cette approche fonctionne mieux lorsque vous pouvez partager le même code de création de modèles et de routage entre le serveur, la page client et le service worker.

Affichage trisomorphe, montrant un navigateur et un service worker communiquant avec le serveur.

Considérations SEO

Lors du choix d'une stratégie d'affichage Web, les équipes tiennent souvent compte de l'impact du SEO. L'affichage côté serveur est un choix populaire pour offrir une expérience "complète" que les robots d'exploration peuvent interpréter. Les robots d'exploration peuvent comprendre JavaScript, mais leur affichage est souvent limité. L'affichage côté client peut fonctionner, mais nécessite souvent des tests et une surcharge supplémentaires. Plus récemment, l'affichage dynamique est également devenu une option intéressante si votre architecture dépend fortement du code JavaScript côté client.

Conclusion

Lorsque vous choisissez une approche d'affichage, mesurez et comprenez vos goulots d'étranglement. Déterminez si l'affichage statique ou l'affichage côté serveur peuvent vous aider à atteindre la plupart de vos objectifs. Il est tout à fait possible de fournir principalement du code HTML avec un minimum de code JavaScript pour obtenir une expérience interactive. Voici une infographie pratique présentant le spectre client-serveur :

Options d'affichage et leurs compromis.

Crédits

Merci à tous pour vos commentaires et votre inspiration :

Jeffrey Posnick, Houssein Djirdeh, Shubhie Panicker, Chris Harrelson et Sebastian Markbåge.