Veröffentlicht am 6. Februar 2019, zuletzt aktualisiert am 5. Januar 2026
Eine der wichtigsten Entscheidungen, die Webentwickler treffen müssen, ist, wo sie Logik und Rendering in ihrer Anwendung implementieren. Das kann schwierig sein, da es so viele Möglichkeiten gibt, eine Website zu erstellen.
Unser Verständnis dieses Bereichs basiert auf unserer Arbeit in Chrome mit großen Websites in den letzten Jahren. Im Allgemeinen empfehlen wir Entwicklern, serverseitiges oder statisches Rendering anstelle eines vollständigen Rehydration -Ansatzes in Betracht zu ziehen.
Um die Architekturen besser zu verstehen, aus denen wir bei dieser Entscheidung auswählen, benötigen wir eine konsistente Terminologie und ein gemeinsames Framework für jeden Ansatz. So können Sie die Kompromisse der einzelnen Rendering Ansätze besser aus der Perspektive der Seitenleistung bewerten.
Terminologie
Zuerst definieren wir einige Begriffe, die wir verwenden werden.
Rendering
- Serverseitiges Rendering (SSR)
- Eine App auf dem Server rendern, um HTML anstelle von JavaScript an den Client zu senden.
- Clientseitiges Rendering (CSR)
- Eine App in einem Browser rendern und JavaScript verwenden, um das DOM zu ändern.
- Pre-Rendering
- Eine clientseitige Anwendung zur Build-Zeit ausführen, um ihren ursprünglichen Zustand als statisches HTML zu erfassen. Hinweis: „Pre-Rendering“ in diesem Sinne unterscheidet sich vom Browser-Pre-Rendering zukünftiger Navigationen.
- Hydration
- Clientseitige Skripts ausführen, um serverseitig gerendertem HTML Anwendungsstatus und Interaktivität hinzuzufügen. Bei der Hydration wird davon ausgegangen, dass sich das DOM nicht ändert.
- Rehydration
- Wird oft als Synonym für Hydration verwendet, impliziert aber, dass das DOM regelmäßig mit dem neuesten Status aktualisiert wird, auch nach der ersten Hydration.
Leistung
- Time to First Byte (TTFB)
- Die Zeit zwischen dem Klicken auf einen Link und dem Laden des ersten Byte Inhalts auf der neuen Seite.
- First Contentful Paint (FCP)
- Die Zeit, zu der der angeforderte Inhalt (Artikeltext usw.) sichtbar wird.
- Interaction to Next Paint (INP)
- Ein repräsentativer Messwert, der bewertet, ob eine Seite durchgehend 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 das vollständige HTML für eine Seite auf dem Server als Reaktion auf die Navigation generiert. So werden zusätzliche Roundtrips für das Abrufen von Daten und die Vorlagenerstellung auf dem Client vermieden, da der Renderer diese verarbeitet, bevor der Browser eine Antwort erhält.
Serverseitiges Rendering führt in der Regel zu einem schnellen FCP. Wenn Sie die Seitenlogik und das Rendering auf dem Server ausführen, müssen Sie nicht viel JavaScript an den Client senden. So lässt sich die TBT einer Seite reduzieren, was auch zu einem niedrigeren INP führen kann, da der Hauptthread während des Seitenaufbaus nicht so oft blockiert wird. Wenn der Hauptthread seltener blockiert wird, können Nutzerinteraktionen früher ausgeführt werden.
Das ist sinnvoll, da beim serverseitigen Rendering nur Text und Links an den Browser des Nutzers gesendet werden. Dieser Ansatz funktioniert gut bei verschiedenen Geräte- und Netzwerkbedingungen und ermöglicht interessante Browseroptimierungen, wie das Streaming von Dokumenten.
Beim serverseitigen Rendering müssen Nutzer seltener warten, bis CPU-lastiges JavaScript ausgeführt wird, bevor sie Ihre Website verwenden können. Auch wenn Sie Drittanbieter-JavaScript nicht vermeiden können, können Sie mit serverseitigem Rendering Ihre eigenen JavaScript-Kosten reduzieren und so mehr Budget für den Rest haben. Es gibt jedoch einen potenziellen Nachteil bei diesem Ansatz: Das Generieren von Seiten auf dem Server dauert Zeit, was die TTFB Ihrer Seite erhöhen kann.
Ob serverseitiges Rendering für Ihre Anwendung ausreicht, hängt weitgehend davon ab, welche Art von Nutzererfahrung Sie erstellen. Es gibt eine lange Debatte über die korrekten Anwendungen von serverseitigem und clientseitigem Rendering, aber Sie können serverseitiges Rendering immer für einige Seiten verwenden und für andere nicht. Einige Websites haben mit Hybrid-Rendering-Techniken Erfolg. prefetching
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 serverseitiges 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 serverseitiges Rendering verwenden. Vue Nutzer können die Anleitung zum serverseitigen Rendering von Vue oder Nuxt verwenden. Angular hat Universal.
Die meisten gängigen Lösungen verwenden jedoch eine Form der Hydration. Achten Sie daher auf die Ansätze, die Ihr Tool verwendet.
Statisches Rendering
Statisches Rendering erfolgt zur Build-Zeit. Dieser Ansatz bietet einen schnellen FCP sowie eine niedrigere TBT und INP, solange Sie die Menge an clientseitigem JavaScript auf Ihren Seiten begrenzen. Im Gegensatz zum serverseitigen Rendering wird auch eine gleichbleibend schnelle TTFB erreicht, da das HTML für eine Seite nicht dynamisch auf dem Server generiert werden muss. Im Allgemeinen bedeutet statisches Rendering, dass für jede URL vorab eine separate HTML-Datei erstellt wird. Da HTML-Antworten im Voraus generiert werden, können Sie statische Renderings auf mehreren CDNs bereitstellen, um Edge-Caching zu nutzen.
Es gibt Lösungen für statisches Rendering in allen Formen und Größen. Tools wie Gatsby sind so konzipiert, dass Entwickler den Eindruck haben, ihre Anwendung werde dynamisch gerendert und nicht als Build-Schritt generiert. Tools zur statischen Websitegenerierung wie 11ty, Jekyll und Metalsmith nutzen ihre statische Natur und bieten einen vorlagenbasierten Ansatz.
Einer der Nachteile des statischen Renderings ist, dass für jede mögliche URL einzelne HTML-Dateien generiert werden müssen. Das kann schwierig oder sogar unmöglich sein wenn Sie diese URLs vorab vorhersagen müssen und für Websites mit einer großen Anzahl eindeutiger Seiten.
React-Nutzer kennen vielleicht Gatsby, den statischen Export von Next.js oder Navi, mit denen sich Seiten einfach aus Komponenten erstellen lassen. Statisches Rendering und Pre-Rendering verhalten sich jedoch unterschiedlich: Statisch gerenderte Seiten sind interaktiv, ohne dass viel clientseitiges JavaScript ausgeführt werden muss. Pre-Rendering verbessert dagegen den FCP einer Single-Page-Anwendung, die auf dem Client gestartet werden muss, um Seiten wirklich interaktiv zu machen.
Wenn Sie sich nicht sicher sind, ob eine bestimmte Lösung statisches Rendering oder Pre-Rendering ist, deaktivieren Sie JavaScript und laden Sie die Seite, die Sie testen möchten. Bei statisch gerenderten Seiten sind die meisten interaktiven Funktionen auch ohne JavaScript verfügbar. Vorab gerenderte Seiten haben möglicherweise noch einige grundlegende Funktionen wie Links mit JavaScript deaktiviert, aber der Großteil der Seite ist inaktiv.
Ein weiterer nützlicher Test ist die Verwendung der Netzwerkdrosselung in den Chrome-Entwicklertools , um zu sehen, wie viel JavaScript heruntergeladen wird, bevor eine Seite interaktiv wird. Für das Pre-Rendering ist in der Regel mehr JavaScript erforderlich, um interaktiv zu werden. Dieses JavaScript ist in der Regel komplexer als der progressive Enhancement Ansatz, der beim statischen Rendering verwendet wird.
Serverseitiges Rendering im Vergleich zu statischem Rendering
Serverseitiges Rendering ist nicht für alles die beste Lösung, da seine
dynamische Natur erhebliche Kosten für die Rechenleistung verursachen kann. Viele serverseitige
Rendering-Lösungen leeren den Puffer nicht frühzeitig, verzögern die TTFB oder verdoppeln die gesendeten Daten
(z. B. Inline-Status, die von JavaScript auf dem Client verwendet werden). In React,
renderToString() kann 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 serverseitiges Rendering "richtig" zu implementieren, müssen Sie möglicherweise eine Lösung für das Komponenten-Caching finden oder erstellen, den Speicherverbrauch verwalten, Memoization-Techniken verwenden und andere Aspekte berücksichtigen. Oft wird dieselbe App zweimal verarbeitet oder neu erstellt, einmal auf dem Client und einmal auf dem Server. Wenn Inhalte beim serverseitigen Rendering früher angezeigt werden, bedeutet das nicht unbedingt, dass Sie weniger Arbeit haben. Wenn auf dem Client viel Arbeit anfällt, nachdem eine serverseitig generierte HTML-Antwort auf dem Client eingegangen ist, kann dies immer noch zu einer höheren TBT und INP für Ihre Website führen.
Beim serverseitigen Rendering wird HTML bei Bedarf für jede URL generiert. Das kann jedoch langsamer sein als das Bereitstellen statisch gerenderter Inhalte. Wenn Sie den zusätzlichen Aufwand in Kauf nehmen, kann serverseitiges Rendering in Kombination mit HTML-Caching die Rendering-Zeit auf dem Server erheblich reduzieren. Der Vorteil des serverseitigen Renderings besteht darin, dass mehr "Live"-Daten abgerufen und eine vollständigere Reihe von Anfragen beantwortet werden kann als beim statischen Rendering. Seiten, die personalisiert werden müssen, sind ein konkretes Beispiel für Anfragen, die mit statischem Rendering nicht gut funktionieren.
Serverseitiges Rendering kann auch interessante Entscheidungen bei der Erstellung einer PWA mit sich bringen. Ist es besser, das Caching von Service Workern für die gesamte Seite zu verwenden oder einzelne Inhaltselemente serverseitig zu rendern?
Clientseitiges Rendering
Beim clientseitigen Rendering werden Seiten direkt im Browser mit JavaScript gerendert. Alle Logik, das Abrufen von Daten, die Vorlagenerstellung 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 mit eigenen Kompromissen verbunden ist.
Clientseitiges Rendering kann für Mobilgeräte schwierig zu erstellen und schnell zu halten sein.
Mit etwas Aufwand, um ein knappes JavaScript-Budget
einzuhalten und in möglichst wenigen Roundtrips
Wert zu liefern, können Sie mit clientseitigem Rendering fast die Leistung des reinen serverseitigen Renderings erreichen. Sie können den Parser schneller für sich arbeiten lassen,
indem Sie kritische Skripts und Daten mit <link rel=preload>
bereitstellen. Wir empfehlen außerdem, Muster wie PRPL
zu verwenden, damit sich die erste und nachfolgende Navigationen sofort anfühlen.
Der Hauptnachteil des clientseitigen Renderings besteht darin, dass die Menge an erforderlichem JavaScript mit dem Wachstum einer Anwendung zunimmt, was sich auf den INP einer Seite auswirken kann. Das wird besonders schwierig, wenn neue JavaScript-Bibliotheken, Polyfills und Drittanbietercode hinzugefügt werden, die um Rechenleistung konkurrieren und oft verarbeitet werden müssen, bevor der Inhalt einer Seite gerendert werden kann.
Bei Anwendungen, die clientseitiges Rendering verwenden und auf große JavaScript-Bundles angewiesen sind, sollte aggressives Code-Splitting in Betracht gezogen werden, um die TBT und INP während des Seitenaufbaus zu senken. Außerdem sollte JavaScript verzögert geladen werden, um nur das bereitzustellen, was der Nutzer benötigt, wenn es benötigt wird. Bei Anwendungen mit wenig oder keiner Interaktivität kann serverseitiges 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 verwenden, indem Sie die wichtigsten Teile der Benutzeroberfläche
identifizieren, die von den meisten Seiten gemeinsam genutzt werden.
Anwendungsshell-Caching
In Kombination mit Service Workern kann dies die
wahrgenommene Leistung bei wiederholten Besuchen erheblich verbessern, da die Seite ihre
Anwendungsshell-HTML und Abhängigkeiten sehr schnell aus CacheStorage laden kann.
Bei der Rehydration werden serverseitiges und clientseitiges Rendering kombiniert
Die Hydration ist ein Ansatz, der die Kompromisse zwischen clientseitigem und serverseitigem Rendering durch die Kombination beider Ansätze minimiert. Navigationsanfragen wie vollständige Seitenaufrufe oder ‑neuladungen 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 erfolgt, wird ein schneller FCP wie beim serverseitigen Rendering erreicht. Anschließend wird das Rendering auf dem Client fortgesetzt.
Das ist eine effektive Lösung, kann aber erhebliche Leistungseinbußen mit sich bringen.
Der Hauptnachteil 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 sehen möglicherweise geladen und interaktiv aus, können aber erst auf Eingaben reagieren, wenn die clientseitigen Skripts für Komponenten ausgeführt und Ereignishandler angehängt wurden. Auf Mobilgeräten kann das Minuten dauern, was für den Nutzer verwirrend und frustrierend ist.
Ein Rehydration-Problem: eine App zum Preis von zwei
Damit das clientseitige JavaScript genau dort weitermachen kann, wo der Server aufgehört hat, ohne alle Daten noch einmal anzufordern, mit denen der Server sein HTML gerendert hat, serialisieren die meisten serverseitigen Rendering-Lösungen die Antwort von den Datenabhängigkeiten einer Benutzeroberfläche als Skript-Tags im Dokument. Da dadurch viel HTML dupliziert wird, kann die Rehydration mehr Probleme verursachen als nur eine verzögerte Interaktivität.
Der Server gibt als Antwort auf eine
Navigationsanfrage eine Beschreibung der Benutzeroberfläche der Anwendung zurück, aber auch die Quelldaten, die zum Erstellen dieser
Benutzeroberfläche verwendet wurden, und eine vollständige Kopie der Implementierung der Benutzeroberfläche, die dann auf dem
Client gestartet wird. Die Benutzeroberfläche wird erst interaktiv, nachdem bundle.js geladen und ausgeführt wurde.
Leistungsmesswerte, die von echten Websites mit serverseitigem Rendering und Rehydration erfasst wurden, deuten darauf hin, dass dies selten die beste Option ist. Der wichtigste Grund ist die Auswirkung auf die Nutzererfahrung, wenn eine Seite fertig aussieht, aber keine der interaktiven Funktionen funktioniert.
Es gibt Hoffnung für serverseitiges Rendering mit Rehydration. Kurzfristig kann die Verwendung von serverseitigem Rendering nur für stark cachebare Inhalte die TTFB reduzieren und ähnliche Ergebnisse wie Pre-Rendering erzielen. Inkrementelle progressiveoder teilweise Rehydration könnte der Schlüssel sein, um diese Technik in Zukunft praktikabler zu machen.
Serverseitiges Streaming-Rendering und progressive Rehydration
Das serverseitige Rendering hat in den letzten Jahren einige Entwicklungen durchlaufen.
Beim serverseitigen Streaming-Rendering
können Sie HTML in Blöcken senden, die der Browser nach und nach rendern kann, sobald sie
empfangen werden. So können Sie Markup schneller an Ihre Nutzer senden und den FCP beschleunigen. In
React werden Streams in renderToPipeableStream() asynchron verarbeitet, im Gegensatz zu
synchronem renderToString(). Dadurch wird der Backpressure gut gehandhabt.
Progressive Rehydration ist ebenfalls eine Überlegung wert (React hat sie implementiert). Bei diesem Ansatz werden einzelne Teile einer serverseitig gerenderten Anwendung nach und nach gestartet, 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 Teilen der Seite mit niedriger Priorität aufschieben, um zu verhindern, dass der Hauptthread blockiert wird. So können Nutzerinteraktionen früher erfolgen, nachdem der Nutzer sie initiiert hat.
Mit der progressiven Rehydration können Sie auch eine der häufigsten
Fallstricke bei der Rehydration von serverseitigem Rendering vermeiden: Ein serverseitig gerenderter DOM-Baum wird
zerstört und dann sofort neu aufgebaut, meistens weil das anfängliche
synchrone clientseitige Rendering Daten erfordert, die noch nicht ganz bereit sind, oft ein
Promise das noch nicht aufgelöst wurde.
Teilweise Rehydration
Die teilweise Rehydration hat sich als schwierig zu implementieren erwiesen. Dieser Ansatz ist eine Erweiterung der progressiven Rehydration, bei der einzelne Teile der Seite (Komponenten, Ansichten oder Bäume) analysiert und die Teile mit wenig Interaktivität oder keiner Reaktivität identifiziert werden. Für jeden dieser meist statischen Teile wird der entsprechende JavaScript-Code dann in inerte Referenzen und dekorative Elemente umgewandelt, wodurch der clientseitige Speicherbedarf auf nahezu null reduziert wird.
Der Ansatz der teilweisen Rehydration hat seine eigenen Probleme und Kompromisse. Er stellt einige interessante Herausforderungen für das Caching dar. Bei der clientseitigen Navigation bedeutet dies, dass wir nicht davon ausgehen können, dass serverseitig gerendertes HTML für inerte Teile der Anwendung ohne vollständigen Seitenaufbau verfügbar ist.
Trisomorphes Rendering
Wenn Service Worker für Sie eine Option sind, sollten Sie trisomorphes Rendering in Betracht ziehen. Mit dieser Technik können Sie serverseitiges Streaming-Rendering für anfängliche oder nicht JavaScript-basierte Navigationen verwenden. Anschließend übernimmt Ihr Service Worker das Rendering von HTML für Navigationen, nachdem er installiert wurde. So können Sie zwischengespeicherte Komponenten und Vorlagen auf dem neuesten Stand halten und SPA-ähnliche Navigationen für das Rendering neuer Ansichten in derselben Sitzung ermöglichen. Dieser Ansatz funktioniert am besten, wenn Sie denselben Vorlagen- und Routing-Code zwischen Server, Clientseite und Service Worker verwenden können.
SEO-Überlegungen
Bei der Auswahl einer Web-Rendering-Strategie berücksichtigen Teams oft die Auswirkungen auf die SEO. Serverseitiges Rendering ist eine beliebte Wahl, um eine „vollständig aussehende“ Nutzererfahrung zu bieten, die Crawler interpretieren können. Crawler können JavaScript verstehen, aber es gibt oft Einschränkungen beim Rendering. Clientseitiges Rendering kann funktionieren, erfordert aber oft zusätzliche Tests und Aufwand. In letzter Zeit ist auch das dynamische Rendering eine Option, die in Betracht gezogen werden sollte, wenn Ihre Architektur stark von clientseitigem JavaScript abhängt.
Fazit
Wenn Sie sich für einen Rendering-Ansatz entscheiden, müssen Sie messen und verstehen, wo Ihre Engpässe liegen. Überlegen Sie, ob Sie mit statischem oder serverseitigem Rendering die meisten Ihrer Ziele erreichen können. Es ist in Ordnung, hauptsächlich HTML mit minimalem JavaScript zu senden, um eine interaktive Nutzererfahrung zu bieten. Hier ist eine praktische Infografik, die das Server-Client-Spektrum zeigt:
Gutschriften
Vielen Dank an alle für ihre Rezensionen und Inspiration:
Jeffrey Posnick, Houssein Djirdeh, Shubhie Panicker, Chris Harrelson und Sebastian Markbåge.