Routen vorab rendern – mit Reaktions-Snap

Sie nutzen kein serverseitiges Rendering, möchten aber die Leistung Ihrer React-Website beschleunigen? Teste das Pre-Rendering.

react-snap ist eine Drittanbieterbibliothek, die Seiten auf Ihrer Website vorab in statische HTML-Dateien rendert. Dadurch lassen sich die First Paint-Zeiten in Ihrer Anwendung verbessern.

Hier ein Vergleich derselben App mit und ohne Pre-Rendering, die auf eine simulierte 3G-Verbindung und ein Mobilgerät geladen wurde:

Ein Vergleich, der nebeneinander geladen wird. Die Version mit Pre-Rendering wird 4,2 Sekunden schneller geladen.

Welchen Nutzen bieten sie?

Das wichtigste Leistungsproblem bei großen Anwendungen mit nur einer Seite besteht darin, dass der Nutzer warten muss, bis die JavaScript-Bundles, aus denen die Website besteht, vollständig heruntergeladen sind, bevor er echte Inhalte sehen kann. Je größer die Pakete, desto länger müssen Nutzende warten.

Um dieses Problem zu lösen, rendern viele Entwickler die Anwendung auf dem Server, anstatt sie nur im Browser zu starten. Bei jedem Seiten-/Routenübergang wird der vollständige HTML-Code auf dem Server generiert und an den Browser gesendet. Dadurch verringert sich die Zeit bis zum ersten Mal für First Paint, allerdings wird die Zeit bis zum ersten Byte verlangsamt.

Das Pre-Rendering ist eine separate Technik, die weniger komplex ist als das Server-Rendering, bietet aber auch eine Möglichkeit, First Paint-Zeiten in Ihrer Anwendung zu verbessern. Ein monitorloser Browser oder ein Browser ohne Benutzeroberfläche wird verwendet, um während der Build-Zeit statische HTML-Dateien jeder Route zu generieren. Diese Dateien können dann zusammen mit den JavaScript-Bundles geliefert werden, die für die Anwendung benötigt werden.

Reaktionsnap

react-snap verwendet Puppeteer, um vorgerenderte HTML-Dateien verschiedener Routen in Ihrer Anwendung zu erstellen. Installieren Sie ihn zuerst als Entwicklungsabhängigkeit:

npm install --save-dev react-snap

Fügen Sie dann ein postbuild-Skript in der package.json ein:

"scripts": {
  //...
  "postbuild": "react-snap"
}

Dadurch würde der Befehl react-snap jedes Mal automatisch ausgeführt, wenn ein neuer Build der Anwendungen erstellt wird (npm build).

Als Letztes müssen Sie die Startmethode der Anwendung ändern. Ändern Sie die Datei src/index.js so:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");

if (rootElement.hasChildNodes()) {
  ReactDOM.hydrate(<App />, rootElement);
} else {
  ReactDOM.render(<App />, rootElement);
}

Anstatt nur ReactDOM.render zu verwenden, um das React-Stammelement direkt im DOM zu rendern, wird geprüft, ob bereits untergeordnete Knoten vorhanden sind. So wird festgestellt, ob HTML-Inhalte vorab gerendert (oder auf dem Server gerendert wurden). In diesem Fall wird stattdessen ReactDOM.hydrate verwendet, um Event-Listener an den bereits erstellten HTML-Code anzuhängen, anstatt ihn neu zu erstellen.

Beim Erstellen der Anwendung werden jetzt statische HTML-Dateien als Nutzlasten für jede gecrawlte Route generiert. Sie können sich die HTML-Nutzlast ansehen, indem Sie auf die URL der HTML-Anfrage und dann in den Chrome-Entwicklertools auf den Tab Vorschauen klicken.

Ein Vorher-Nachher-Vergleich. In der Nachher-Aufnahme ist zu sehen, dass der Inhalt gerendert wurde.

Flash für Inhalte ohne Stile

Obwohl statisches HTML jetzt fast sofort gerendert wird, bleibt es standardmäßig ohne Formatierung, was zu dem Problem führen kann, dass ein FOUC (Flash of Unstyled Content) angezeigt wird. Dies kann besonders auffällig sein, wenn Sie zum Generieren von Selektoren eine CSS-in-JS-Bibliothek verwenden, da das JavaScript-Bundle beendet sein muss, bevor Stile angewendet werden können.

Um dies zu verhindern, kann das kritische CSS (oder die Mindestanzahl an CSS, die zum Rendern der ersten Seite erforderlich ist) direkt in die <head> des HTML-Dokuments eingefügt werden. react-snap verwendet eine andere Drittanbieterbibliothek, minimalcss, um wichtige CSS für verschiedene Routen zu extrahieren. Sie können dies aktivieren, indem Sie in der Datei package.json Folgendes angeben:

"reactSnap": {
  "inlineCss": true
}

In der Antwortvorschau in den Chrome-Entwicklertools wird jetzt die Seite mit benutzerdefinierten Stilen mit wichtigem CSS-Code angezeigt.

Ein Vorher-Nachher-Vergleich. In der Nachher-Aufnahme ist zu sehen, dass der Inhalt gerendert wurde und aufgrund von kritischem Inline-CSS-Code formatiert wird.

Fazit

Wenn Sie keine serverseitigen Rendering-Routen in Ihrer Anwendung verwenden, verwenden Sie react-snap, um statischen HTML-Code für die Nutzer vorab zu rendern.

  1. Installieren Sie es als Entwicklungsabhängigkeit und beginnen Sie nur mit den Standardeinstellungen.
  2. Verwenden Sie die experimentelle Option inlineCss, um wichtige CSS-Elemente inline einzubetten, wenn sie auf Ihrer Website funktionieren.
  3. Wenn Sie die Codeaufteilung auf Komponentenebene innerhalb von Routen verwenden, achten Sie darauf, für Ihre Nutzer keinen Ladestatus vorab zu rendern. In der Readme-Datei react-snap wird dies ausführlicher behandelt.