Rendering im Web

Veröffentlicht: 6. Februar 2019, zuletzt aktualisiert: 5. Januar 2026

Eine der wichtigsten Entscheidungen, die Webentwickler treffen müssen, ist, wo Logik und Rendering in ihrer Anwendung implementiert werden sollen. Das kann schwierig sein, weil es so viele Möglichkeiten gibt, eine Website zu erstellen.

Unser Verständnis dieses Bereichs basiert auf unserer Arbeit in Chrome und unseren Gesprächen mit großen Websites in den letzten Jahren. Allgemein empfehlen wir Entwicklern, serverseitiges oder statisches Rendering anstelle einer vollständigen Rehydration in Betracht zu ziehen.

Um die Architekturen, zwischen denen wir uns entscheiden, besser zu verstehen, benötigen wir eine einheitliche Terminologie und ein gemeinsames Framework für jeden Ansatz. Anschließend könnt ihr die Vor- und Nachteile der einzelnen Rendering-Ansätze im Hinblick auf die Seitenleistung besser beurteilen.

Terminologie

Zuerst definieren wir einige Begriffe, die wir verwenden werden.

Rendering

Serverseitiges Rendering (SSR)
Eine App wird auf dem Server gerendert, um HTML statt JavaScript an den Client zu senden.
Clientseitiges Rendering (CSR)
Eine App wird in einem Browser gerendert und das DOM wird mit JavaScript geändert.
Pre-Rendering
Ausführen einer clientseitigen Anwendung während des Build-Prozesses, um ihren ursprünglichen Zustand als statisches HTML zu erfassen. Hinweis: „Prerendering“ in diesem Sinne unterscheidet sich vom Browser-Prerendering zukünftiger Navigationen.
Durstlöscher
Ausführen von clientseitigen Skripts, um dem vom Server gerenderten HTML-Code Anwendungsstatus und Interaktivität hinzuzufügen. Bei der Hydratation wird davon ausgegangen, dass sich das DOM nicht ändert.
Rehydration
Der Begriff „Rehydrierung“ wird oft synonym mit „Hydrierung“ verwendet, bedeutet aber, dass das DOM regelmäßig mit dem neuesten Status aktualisiert wird, auch nach der ersten Hydrierung.

Leistung

Time to First Byte (TTFB)
Die Zeit zwischen dem Klicken auf einen Link und dem Laden des ersten Bytes des Inhalts auf der neuen Seite.
First Contentful Paint (FCP)
Der Zeitpunkt, zu dem der angeforderte Inhalt (Artikeltext usw.) sichtbar wird.
Interaction to Next Paint (INP)
Ein repräsentativer Messwert, mit dem bewertet wird, ob eine Seite einheitlich schnell auf Nutzereingaben reagiert.
Total Blocking Time (TBT)
Ein Proxy-Messwert für INP, der berechnet, wie lange der Hauptthread während des Seitenaufbaus blockiert war.

Serverseitiges Rendering

Beim serverseitigen Rendering wird der vollständige HTML-Code für eine Seite auf dem Server als Antwort auf die Navigation generiert. So werden zusätzliche Umläufe für das Abrufen von Daten und das Erstellen von Vorlagen auf dem Client vermieden, da der Renderer diese verarbeitet, bevor der Browser eine Antwort erhält.

Serverseitiges Rendering führt im Allgemeinen zu einem schnellen FCP. Wenn Sie die Seitenlogik und das Rendering auf dem Server ausführen, müssen Sie nicht so viel JavaScript an den Client senden. Dadurch wird die TBT einer Seite reduziert, was auch zu einem niedrigeren INP führen kann, da der Hauptthread beim Seitenaufbau nicht so oft blockiert wird. Wenn der Hauptthread seltener blockiert wird, können Nutzerinteraktionen schneller ausgeführt werden.

Das ist sinnvoll, da beim serverseitigen Rendering nur Text und Links an den Browser des Nutzers gesendet werden. Dieser Ansatz kann für eine Vielzahl von Geräte- und Netzwerkbedingungen gut funktionieren und ermöglicht interessante Browseroptimierungen, z. B. das Parsen von Streaming-Dokumenten.

Diagramm, das zeigt, wie sich serverseitiges Rendering und die JavaScript-Ausführung auf FCP und TTI auswirken.
FCP und TTI mit serverseitigem Rendering.

Beim serverseitigen Rendering müssen Nutzer seltener warten, bis CPU-gebundenes JavaScript ausgeführt wurde, bevor sie deine Website verwenden können. Auch wenn Sie JavaScript von Drittanbietern nicht vermeiden können, können Sie durch die Verwendung von serverseitigem Rendering Ihre eigenen JavaScript-Kosten reduzieren und so mehr Budget für den Rest haben. Dieser Ansatz hat jedoch einen potenziellen Nachteil: Das Generieren von Seiten auf dem Server nimmt Zeit in Anspruch, was die TTFB Ihrer Seite erhöhen kann.

Ob serverseitiges Rendering für deine Anwendung ausreicht, hängt weitgehend davon ab, welche Art von Nutzererfahrung du erstellen möchtest. Es gibt eine langjährige Debatte über die korrekte Anwendung von serverseitigem Rendering im Vergleich zu clientseitigem Rendering. Du kannst aber auch serverseitiges Rendering für einige Seiten verwenden und für andere nicht. Einige Websites haben erfolgreich hybride Rendering-Techniken eingeführt. Netflix rendert beispielsweise seine relativ statischen Landingpages serverseitig, während das JavaScript für interaktionsintensive Seiten prefetching wird. Dadurch können diese umfangreicheren clientseitig gerenderten Seiten schneller geladen werden.

Mit vielen modernen Frameworks, Bibliotheken und Architekturen können Sie dieselbe Anwendung sowohl auf dem Client als auch auf dem Server rendern. Sie können diese Techniken für das serverseitige Rendering verwenden. Architekturen, bei denen das Rendering sowohl auf dem Server als auch auf dem Client erfolgt, sind jedoch eine eigene Klasse von Lösungen mit sehr unterschiedlichen Leistungsmerkmalen und Kompromissen. React-Nutzer können Server-DOM-APIs oder darauf basierende Lösungen wie Next.js für das serverseitige Rendering verwenden. Vue-Nutzer können den Leitfaden zum serverseitigen Rendering von Vue oder Nuxt verwenden. Angular hat Universal.

Die meisten gängigen Lösungen verwenden jedoch eine Form der Hydratation. Sie sollten sich also mit den Ansätzen Ihres Tools vertraut machen.

Statisches Rendering

Statisches Rendering erfolgt während der Erstellung. Dieser Ansatz bietet einen schnellen FCP sowie einen niedrigeren TBT und INP, solange Sie die Menge an clientseitigem JavaScript auf Ihren Seiten begrenzen. Im Gegensatz zum serverseitigen Rendering wird auch eine durchgängig schnelle TTFB erreicht, da der HTML-Code für eine Seite nicht dynamisch auf dem Server generiert werden muss. Im Allgemeinen bedeutet statisches Rendering, dass für jede URL im Voraus eine separate HTML-Datei erstellt wird. Wenn HTML-Antworten im Voraus generiert werden, können Sie statische Renderings auf mehreren CDNs bereitstellen, um das Edge-Caching zu nutzen.

Diagramm, das statisches Rendering und optionale JavaScript-Ausführung zeigt, die sich auf FCP und TTI auswirken.
FCP und TTI mit statischem Rendering.

Lösungen für statisches Rendering gibt es in allen Formen und Größen. Tools wie Gatsby sind so konzipiert, dass Entwickler das Gefühl haben, ihre Anwendung wird dynamisch gerendert und nicht als Build-Schritt generiert. Tools zur Generierung statischer Websites wie 11ty, Jekyll und Metalsmith nutzen die statische Natur und bieten einen eher vorlagenbasierten Ansatz.

Einer der Nachteile des statischen Renderings ist, dass für jede mögliche URL eine eigene HTML-Datei generiert werden muss. Das kann schwierig oder sogar unmöglich sein, wenn ihr diese URLs im Voraus vorhersagen müsst und für Websites mit einer großen Anzahl von einzelnen Seiten.

React-Nutzer kennen möglicherweise Gatsby, den statischen Export von Next.js oder Navi. Mit diesen Tools lassen sich Seiten ganz einfach aus Komponenten erstellen. Statisches Rendering und Prerendering verhalten sich jedoch unterschiedlich: Statisch gerenderte Seiten sind interaktiv, ohne dass viel clientseitiges JavaScript ausgeführt werden muss. Prerendering verbessert dagegen den FCP einer Single-Page-Anwendung, die auf dem Client gestartet werden muss, damit Seiten wirklich interaktiv sind.

Wenn ihr euch nicht sicher seid, ob eine bestimmte Lösung statisches Rendering oder Prerendering ist, deaktiviert JavaScript und ladet die Seite, die ihr testen möchtet. Bei statisch gerenderten Seiten sind die meisten interaktiven Funktionen auch ohne JavaScript verfügbar. Vorgerenderte Seiten haben möglicherweise noch einige grundlegende Funktionen wie Links, wenn JavaScript deaktiviert ist, aber der größte Teil der Seite ist inaktiv.

Ein weiterer nützlicher Test ist die Netzwerkdrosselung in den Chrome-Entwicklertools. Damit können Sie sehen, wie viel JavaScript heruntergeladen wird, bevor eine Seite interaktiv wird. Beim Prerendering ist im Allgemeinen mehr JavaScript erforderlich, um Interaktivität zu erreichen. Dieses JavaScript ist in der Regel komplexer als der Ansatz der progressiven Verbesserung, der beim statischen Rendering verwendet wird.

Serverseitiges Rendering im Vergleich zu statischem Rendering

Das serverseitige Rendering ist nicht für alles die beste Lösung, da die dynamische Natur erhebliche Rechenkosten verursachen kann. Viele serverseitige Rendering-Lösungen leeren nicht frühzeitig, verzögern die TTFB oder verdoppeln die gesendeten Daten (z. B. Inline-Zustände, die von JavaScript auf dem Client verwendet werden). In React kann renderToString() langsam sein, da es synchron und Single-Threaded ist. Neuere React-Server-DOM-APIs unterstützen Streaming, wodurch der erste Teil einer HTML-Antwort schneller an den Browser gesendet werden kann, während der Rest noch auf dem Server generiert wird.

Um das serverseitige Rendering „richtig“ zu machen, müssen Sie möglicherweise eine Lösung für das Komponenten-Caching finden oder erstellen, den Arbeitsspeicherverbrauch verwalten, Memoization-Techniken verwenden und andere Aspekte berücksichtigen. Sie verarbeiten oder erstellen dieselbe App oft zweimal, einmal auf dem Client und einmal auf dem Server. Wenn Inhalte durch serverseitiges Rendering schneller angezeigt werden, bedeutet das nicht unbedingt, dass Sie weniger Arbeit haben. Wenn Sie nach dem Eintreffen einer vom Server generierten HTML-Antwort auf dem Client viel Arbeit haben, kann dies trotzdem zu höheren TBT- und INP-Werten für Ihre Website führen.

Beim serverseitigen Rendering wird HTML für jede URL bei Bedarf erstellt. Das kann jedoch langsamer sein als die Bereitstellung von statisch gerenderten Inhalten. Wenn Sie den zusätzlichen Aufwand betreiben können, können Sie mit serverseitigem Rendering und HTML-Caching die Renderingzeit des Servers erheblich reduzieren. Der Vorteil des serverseitigen Renderings besteht darin, dass mehr „Live“-Daten abgerufen und mehr Anfragen beantwortet werden können als beim statischen Rendering. Seiten, die personalisiert werden müssen, sind ein konkretes Beispiel für die Art von Anfrage, die mit statischem Rendering nicht gut funktioniert.

Das serverseitige Rendering kann auch beim Erstellen einer PWA zu interessanten Entscheidungen führen. Ist es besser, ganzseitiges Service Worker-Caching zu verwenden oder einzelne Inhalte serverseitig zu rendern?

Clientseitiges Rendering

Clientseitiges Rendering bedeutet, dass Seiten mit JavaScript direkt im Browser gerendert werden. Die gesamte Logik, der Datenabruf, die Vorlagen und das Routing werden auf dem Client und nicht auf dem Server verarbeitet. Das Ergebnis ist, dass mehr Daten vom Server an das Gerät des Nutzers übertragen werden, was wiederum eigene Nachteile mit sich bringt.

Es kann schwierig sein, clientseitiges Rendering für Mobilgeräte zu erstellen und schnell zu halten. Mit ein wenig Aufwand, um ein knappes JavaScript-Budget einzuhalten und mit möglichst wenigen Roundtrips einen Mehrwert zu bieten, könnt ihr mit clientseitigem Rendering fast die Leistung von rein serverseitigem Rendering erreichen. Sie können den Parser schneller für sich arbeiten lassen, indem Sie wichtige Skripts und Daten mit <link rel=preload> bereitstellen. Wir empfehlen außerdem, Muster wie PRPL zu verwenden, damit die erste und nachfolgende Navigationen sofort erfolgen.

Diagramm, das zeigt, wie sich clientseitiges Rendering auf FCP und TTI auswirkt.
FCP und TTI mit clientseitigem Rendering.

Der größte Nachteil des clientseitigen Renderings besteht darin, dass die Menge an erforderlichem JavaScript mit der Größe einer Anwendung zunimmt, was sich auf den INP einer Seite auswirken kann. Dies wird besonders schwierig, wenn neue JavaScript-Bibliotheken, Polyfills und Drittanbietercode hinzukommen, die um Rechenleistung konkurrieren und oft verarbeitet werden müssen, bevor der Inhalt einer Seite gerendert werden kann.

Bei Websites, die clientseitiges Rendering verwenden und auf große JavaScript-Bundles angewiesen sind, sollte eine aggressive Codeaufteilung in Betracht gezogen werden, um die TBT und den INP während des Seitenaufbaus zu senken. Außerdem sollte JavaScript per Lazy Loading geladen werden, damit nur das bereitgestellt wird, was der Nutzer benötigt, wenn es benötigt wird. Für Erlebnisse mit wenig oder gar keiner Interaktivität kann das serverseitige Rendering eine skalierbarere Lösung für diese Probleme darstellen.

Wenn Sie Single-Page-Anwendungen erstellen, können Sie die Caching-Technik für die Anwendungsshell anwenden, indem Sie die wichtigsten Teile der Benutzeroberfläche identifizieren, die von den meisten Seiten gemeinsam genutzt werden. In Kombination mit Service Workern kann dies die wahrgenommene Leistung bei wiederholten Besuchen erheblich verbessern, da die Seite den HTML-Code der Anwendungsshell und die Abhängigkeiten von CacheStorage sehr schnell laden kann.

Rehydration kombiniert serverseitiges und clientseitiges Rendering

Hydration ist ein Ansatz, der die Nachteile des clientseitigen und serverseitigen Renderings durch die Kombination beider Methoden minimiert. Navigationsanfragen wie der Seitenaufbau oder das erneute Laden einer ganzen Seite werden von einem Server verarbeitet, der die Anwendung in HTML rendert. Anschließend werden das JavaScript und die Daten, die für das Rendering verwendet werden, in das resultierende Dokument eingebettet. Wenn dies sorgfältig durchgeführt wird, wird ein schneller FCP wie beim serverseitigen Rendering erreicht und dann durch erneutes Rendern auf dem Client „fortgesetzt“.

Dies ist eine effektive Lösung, kann aber erhebliche Leistungseinbußen mit sich bringen.

Der größte Nachteil des serverseitigen Renderings mit Rehydration besteht darin, dass es sich erheblich negativ auf TBT und INP auswirken kann, auch wenn es den FCP verbessert. Serverseitig gerenderte Seiten können so aussehen, als wären sie geladen und interaktiv, können aber erst auf Eingaben reagieren, wenn die clientseitigen Skripts für Komponenten ausgeführt und Event-Handler angehängt wurden. Auf Mobilgeräten kann dies Minuten dauern, was Nutzer verwirrt und frustriert.

Ein Problem mit der Rehydrierung: Eine App zum Preis von zwei

Damit das clientseitige JavaScript genau dort weitermachen kann, wo der Server aufgehört hat, ohne alle Daten, mit denen der Server seinen HTML-Code gerendert hat, noch einmal anzufordern, serialisieren die meisten serverseitigen Rendering-Lösungen die Antwort aus den Datenabhängigkeiten einer Benutzeroberfläche als Script-Tags im Dokument. Da dadurch viele HTML-Elemente dupliziert werden, kann die Rehydrierung mehr Probleme als nur eine verzögerte Interaktivität verursachen.

HTML-Dokument mit serialisierter Benutzeroberfläche, Inline-Daten und einem bundle.js-Skript.

Der Server gibt als Antwort auf eine Navigationsanfrage eine Beschreibung der Benutzeroberfläche der Anwendung zurück. Er gibt aber auch die Quelldaten zurück, die zum Erstellen dieser Benutzeroberfläche verwendet wurden, sowie eine vollständige Kopie der Implementierung der Benutzeroberfläche, die dann auf dem Client gestartet wird. Die Benutzeroberfläche wird erst interaktiv, wenn bundle.js vollständig geladen und ausgeführt wurde.

Leistungsmesswerte, die von echten Websites mit serverseitigem Rendering und Rehydrierung erhoben wurden, deuten darauf hin, dass dies selten die beste Option ist. Der wichtigste Grund ist die Auswirkung auf die Nutzerfreundlichkeit, wenn eine Seite fertig aussieht, aber keine der interaktiven Funktionen funktioniert.

Die negativen Auswirkungen des clientseitigen Renderings auf die TTI.

Es gibt Hoffnung für serverseitiges Rendering mit Rehydration. Kurzfristig kann die Verwendung von serverseitigem Rendering nur für cachefähige Inhalte die TTFB reduzieren und ähnliche Ergebnisse wie das Prerendering erzielen. Eine inkrementelle, schrittweise oder teilweise Rehydrierung könnte der Schlüssel sein, um diese Technik in Zukunft praktikabler zu machen.

Serverseitiges Rendering streamen und progressiv rehydrieren

Beim serverseitigen Rendering gab es in den letzten Jahren einige Entwicklungen.

Serverseitiges Streaming-Rendering ermöglicht das Senden von HTML in Blöcken, die der Browser nach und nach rendern kann, während sie empfangen werden. So kann das Markup schneller an die Nutzer gesendet werden, was den FCP beschleunigt. In React sind Streams in renderToPipeableStream() asynchron, im Gegensatz zu synchronen renderToString(). Das bedeutet, dass Backpressure gut verarbeitet wird.

Auch die progressive Rehydrierung ist eine Überlegung wert (React hat sie implementiert). Bei diesem Ansatz werden einzelne Teile einer serverseitig gerenderten Anwendung im Laufe der Zeit „hochgefahren“, anstatt die gesamte Anwendung auf einmal zu initialisieren, wie es derzeit üblich ist. So lässt sich die Menge an JavaScript reduzieren, die erforderlich ist, um Seiten interaktiv zu machen. Sie können das clientseitige Upgrade von Seitenbereichen mit niedriger Priorität aufschieben, damit der Hauptthread nicht blockiert wird. Nutzerinteraktionen können so schneller erfolgen, nachdem der Nutzer sie initiiert hat.

Mit der progressiven Rehydrierung können Sie auch eine der häufigsten Fallen bei der Rehydrierung des serverseitigen Renderings vermeiden: Ein vom Server gerenderter DOM-Baum wird zerstört und dann sofort neu erstellt. Das liegt meist daran, dass für das anfängliche synchrone clientseitige Rendering Daten erforderlich waren, die noch nicht ganz bereit waren, oft ein Promise, das noch nicht aufgelöst wurde.

Teilweise Rehydrierung

Die teilweise Rehydrierung hat sich als schwierig erwiesen. Dieser Ansatz ist eine Erweiterung der progressiven Rehydrierung, bei der einzelne Teile der Seite (Komponenten, Ansichten oder Bäume) analysiert und die Teile mit geringer Interaktivität oder ohne Reaktivität identifiziert werden. Für jeden dieser größtenteils statischen Teile wird der entsprechende JavaScript-Code dann in inerte Referenzen und dekorative Funktionen umgewandelt, wodurch der clientseitige Speicherbedarf auf fast null reduziert wird.

Der Ansatz der partiellen Rehydrierung bringt eigene Probleme und Kompromisse mit sich. Das stellt einige interessante Herausforderungen für das Caching dar. Außerdem bedeutet die clientseitige Navigation, dass wir nicht davon ausgehen können, dass serverseitig gerendertes HTML für inaktive Teile der Anwendung ohne vollständigen Seitenaufbau verfügbar ist.

Trisomorphes Rendering

Wenn Service Worker für dich infrage kommen, solltest du das trisomorphe Rendering in Betracht ziehen. Mit dieser Technik können Sie das serverseitige Streaming-Rendering für die erste Navigation oder die Navigation ohne JavaScript verwenden und dann den Service Worker das Rendering von HTML für die Navigation übernehmen lassen, nachdem er installiert wurde. So können im Cache gespeicherte Komponenten und Vorlagen auf dem neuesten Stand gehalten und SPA-ähnliche Navigationen zum Rendern neuer Ansichten in derselben Sitzung ermöglicht werden. Dieser Ansatz funktioniert am besten, wenn Sie denselben Vorlagen- und Routingcode für den Server, die Clientseite und den Service Worker verwenden können.

Trisomorphes Rendering, das zeigt, wie ein Browser und ein Service Worker mit dem Server kommunizieren.

SEO-Überlegungen

Bei der Auswahl einer Web-Rendering-Strategie berücksichtigen Teams häufig die Auswirkungen auf die Suchmaschinenoptimierung (SEO). Das serverseitige Rendering ist eine beliebte Option, um eine „vollständig aussehende“ Seite bereitzustellen, die von Crawlern interpretiert werden kann. Crawler können JavaScript verstehen, aber es gibt oft Einschränkungen beim Rendering. Clientseitiges Rendering kann funktionieren, erfordert aber oft zusätzliche Tests und Mehraufwand. In letzter Zeit ist auch das dynamische Rendering eine Option, die Sie in Betracht ziehen sollten, wenn Ihre Architektur stark von clientseitigem JavaScript abhängt.

Fazit

Wenn Sie sich für einen Rendering-Ansatz entscheiden, sollten Sie Ihre Engpässe messen und verstehen. Überlegen Sie, ob Sie mit statischem oder serverseitigem Rendering den Großteil der Anforderungen erfüllen können. Es ist in Ordnung, hauptsächlich HTML mit minimalem JavaScript zu senden, um eine interaktive Oberfläche zu erhalten. Hier ist eine praktische Infografik, die das Server-Client-Spektrum zeigt:

Rendering-Optionen und ihre Vor- und Nachteile

Gutschriften

Vielen Dank an alle für ihre Rezensionen und Inspirationen:

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