Routen vorab rendern – mit Reaktions-Snap

Sie verwenden kein serverseitiges Rendering, möchten aber trotzdem die Leistung Ihrer React-Website verbessern? Probieren Sie Pre-Rendering aus.

react-snap ist eine Drittanbieterbibliothek, mit der Seiten auf Ihrer Website in statische HTML-Dateien vorgerendert werden. Dadurch können die First Paint-Zeiten in Ihrer Anwendung verbessert werden.

Hier sehen Sie einen Vergleich derselben Anwendung mit und ohne Vorrendering, die auf einem simulierten Mobilgerät mit 3G-Verbindung geladen wird:

Ein direkter Vergleich des Ladens. Die Version mit Vorrendering wird 4,2 Sekunden schneller geladen.

Welchen Nutzen bieten sie?

Das Hauptleistungsproblem bei großen Single-Page-Anwendungen besteht darin, dass der Nutzer warten muss, bis die JavaScript-Bundles, aus denen die Website besteht, vollständig heruntergeladen wurden, bevor er tatsächliche Inhalte sehen kann. Je größer die Pakete sind, desto länger müssen die Nutzer warten.

Viele Entwickler beheben dieses Problem, indem sie die Anwendung auf dem Server rendern, anstatt sie nur im Browser zu starten. Bei jeder Seiten-/Routenübergang wird das gesamte HTML auf dem Server generiert und an den Browser gesendet. Dadurch wird die Zeit bis zum ersten Rendern verkürzt, aber die Zeit bis zum ersten Byte verlängert.

Vorrendern ist eine separate Technik, die weniger komplex als das Serverrendering ist, aber auch eine Möglichkeit bietet, die Zeit bis zum ersten Rendern in Ihrer Anwendung zu verkürzen. Ein Headless-Browser oder ein Browser ohne Benutzeroberfläche wird verwendet, um während der Build-Zeit statische HTML-Dateien für jede Route zu generieren. Diese Dateien können dann zusammen mit den JavaScript-Bundles ausgeliefert werden, die für die Anwendung erforderlich sind.

react-snap

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

npm install --save-dev react-snap

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

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

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

Als Letztes müssen Sie ändern, wie die Anwendung gestartet wird. Ä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 Stamm-React-Element direkt im DOM zu rendern, wird hier geprüft, ob bereits untergeordnete Knoten vorhanden sind. So wird ermittelt, ob HTML-Inhalte vorab gerendert (oder auf dem Server gerendert) wurden. In diesem Fall wird ReactDOM.hydrate verwendet, um Event-Listener an das bereits erstellte HTML anzuhängen, anstatt es neu zu erstellen.

Beim Erstellen der Anwendung werden nun statische HTML-Dateien als Nutzlasten für jede gecrawlte Route generiert. Wenn Sie sich ansehen möchten, wie die HTML-Nutzlast aussieht, klicken Sie in den Chrome-Entwicklertools auf die URL der HTML-Anfrage und dann auf den Tab Vorschau.

Ein Vorher-Nachher-Vergleich. Auf dem Nachher-Bild sind gerenderte Inhalte zu sehen.

Flash of Unstyled Content

Statisches HTML wird zwar jetzt fast sofort gerendert, ist aber standardmäßig weiterhin nicht formatiert. Das kann dazu führen, dass ein FOUC-Problem (Flash of Unstyled Content) auftritt. Das kann besonders auffällig sein, wenn Sie eine CSS-in-JS-Bibliothek zum Generieren von Selektoren verwenden, da das JavaScript-Bundle vollständig ausgeführt werden muss, bevor Stile angewendet werden können.

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

"reactSnap": {
  "inlineCss": true
}

Wenn Sie sich die Antwortvorschau in den Chrome-Entwicklertools ansehen, wird die formatierte Seite mit dem inline eingefügten kritischen CSS angezeigt.

Ein Vorher-Nachher-Vergleich. Auf dem Bild danach ist zu sehen, dass der Inhalt gerendert und aufgrund des inline eingefügten kritischen CSS formatiert wurde.

Fazit

Wenn Sie in Ihrer Anwendung keine Routen für das serverseitige Rendern verwenden, können Sie mit react-snap statischen HTML-Code für Ihre Nutzer vorab rendern.

  1. Installieren Sie es als Entwicklungsabhängigkeit und beginnen Sie mit den Standardeinstellungen.
  2. Verwenden Sie die experimentelle Option inlineCss, um wichtige CSS-Elemente inline einzubetten, sofern dies für Ihre Website funktioniert.
  3. Wenn Sie Code-Splitting auf Komponentenebene in Routen verwenden, achten Sie darauf, dass Sie Ihren Nutzern keinen Ladestatus vorrendern. Weitere Informationen finden Sie in der README-Datei zu react-snap.