
Wie man die Website-Performance mit dem Drupal BigPipe-Modul verbessert? Ein umfassender Leitfaden
Geschwindigkeit der Website ist entscheidend, insbesondere heutzutage, wenn moderne Content-Management-Lösungen dynamischer und interaktiver sind. Der traditionelle Ansatz der Seitenbereitstellung ist in diesem Kontext deutlich ineffizient. Es gibt zahlreiche Techniken, um eine optimale Leistung zu erreichen, und eine solche Methode ist die BigPipe-Technik, die ursprünglich bei Facebook entwickelt wurde. Die gute Nachricht ist, dass das BigPipe-Modul, das die gleiche Funktionalität beinhaltet, seit Version 8.1 in Drupal 8 Core integriert ist.
Wie funktioniert Drupal BigPipe?
Die allgemeine Idee der BigPipe-Technik besteht darin, Webseiten in kleine Stücke namens Pagelets zu zerlegen und sie durch mehrere Ausführungsstufen in Webservern und Browsern zu leiten.
Auf hoher Ebene sendet BigPipe eine HTML-Antwort in Teilen:
1. Ein Teil: alles bis kurz vor </body>
- dies enthält BigPipe-Platzhalter für die personalisierten Teile der Seite. Daher sendet dies die nicht personalisierten Teile der Seite. Nennen wir es Das Skelett.
2. N Teile: ein <script>
-Tag pro BigPipe-Platzhalter im Skelett.
3. Ein Teil: </body>
und alles danach.
Dies ist konzeptionell identisch mit Facebooks BigPipe (daher der Name).
Wie unterscheidet sich DruPal BigPipe von Facebooks Technik?
Das Drupal-Modul unterscheidet sich erheblich von der Facebook-Implementierung (und anderen) in der Fähigkeit, automatisch herauszufinden, welche Teile der Webseite von einer BigPipe-ähnlichen Bereitstellung profitieren können.
Das Rendersystem von Drupal hat das Konzept des „Auto-Platzhaltersetzens.“ Was bedeutet das? Der Inhalt, der zu dynamisch ist, wird durch einen Platzhalter ersetzt, der später gerendert werden kann.
Darüber hinaus gibt es auch das Konzept der „Platzhalter-Strategien“. Standardmäßig werden Platzhalter auf der Serverseite ersetzt, und die Antwort wird blockiert, bis alle ersetzt wurden. Es ist jedoch möglich, zusätzliche Platzhalter-Strategien hinzuzufügen. BigPipe ist nur eine davon. Andere könnten ESI, AJAX usw. sein.
Das von Facebook implementierte BigPipe kann nur funktionieren, wenn JavaScript aktiviert ist. Stattdessen ermöglicht das Drupal BigPipe-Modul das Ersetzen von Platzhaltern ohne JavaScript, „kein-JS BigPipe“. Dies ist technisch gesehen überhaupt nicht BigPipe, sondern nur die Verwendung von mehreren Spülungen.
Dadurch können wir sowohl kein-JS BigPipe als auch das „klassische“ BigPipe in derselben Antwort verwenden, um die Menge an Inhalten zu maximieren, die wir so früh wie möglich senden können.
Also, im Wesentlichen passiert das während des Seiten-Render-Prozesses:
- Die personalisierten Teile werden in Platzhalter umgewandelt.
<span data-big-pipe-placeholder-id="callback=d_profiles.builder%3Abuild&args%5B0%5D=profile_widget_mini
&token=6NHeAQvXLYdzXuoWp2TRCvedTO2WAoVKnpW-5_pV9gk"></span>.
Der Platzhalter enthält Informationen darüber, welcher Rückruf aufgerufen werden muss und welche Argumente an ihn übergeben werden. Das Rendersystem traversiert dann weiterhin das Array und wandelt es in HTML um. Das resultierende HTML, einschließlich der Platzhalter, wird zwischengespeichert. Abhängig von der verwendeten Renderstrategie werden die Platzhalter dann jeweils durch ihren dynamischen Inhalt ersetzt. - Das Ersetzen der Platzhalter erfolgt durch JavaScript. Der Rückruf beginnt mit dem Suchen nach Ersatzelementen, sobald ein spezielles
<script type="application/vnd.drupal-ajax" data-big-pipe-event="stop">
-Element gedruckt und gefunden wurde. - Im allerletzten Moment wird es durch den tatsächlichen Inhalt ersetzt. Diese neue Strategie ermöglicht es uns, die anfängliche Webseite zuerst auszugeben und dann die Ersatzteile für die Platzhalter zu streamen.
Wann sollte ein Lazy Builder verwendet werden?
Als Faustregel gilt, dass Sie einen Lazy Builder in Betracht ziehen sollten, wann immer der Inhalt, den Sie zu einem Render-Array hinzufügen, eine der folgenden Typen ist.
- Inhalt, der eine hohe Kardinalität hätte, wenn er zwischengespeichert würde. Zum Beispiel ein Block, der den Namen des Benutzers anzeigt. Er kann zwischengespeichert werden, aber da er sich je nach Benutzer unterscheidet, führt es wahrscheinlich dazu, dass zwischengespeicherte Objekte mit einer geringen Trefferquote resultieren.
- Inhalt, der nicht zwischengespeichert werden kann oder eine sehr hohe Ungültigkeitsrate hat. Zum Beispiel die Anzeige des aktuellen Datums/Uhrzeit oder Statistiken, die immer so aktuell wie möglich sein müssen.
- Inhalt, der einen langwierigen und potenziell langsamen Zusammenstellungsprozess erfordert. Zum Beispiel ein Block, der Inhalte von einer Drittanbieter-API anzeigt, bei der das Anfordern von Inhalten von der API einen Overhead verursacht.
Lazy Builder in der Praxis
Um ein umfassendes Beispiel für die Implementierung von Lazy Buildern zu geben, betrachten wir ein Szenario mit einem benutzerdefinierten Profil-Widget-Block, der auf einer Webseite platziert ist. Der Block enthält das Bild des Benutzers, den vollständigen Namen und das Profilmenü.

Um sicherzustellen, dass jeder Benutzer seine personalisierten Informationen sieht, können wir spezifische Strategien umsetzen, wie das Setzen des „max-age“ auf 0 oder die Nutzung von Benutzerkontexten und Tags. Es ist jedoch wichtig zu beachten, dass das Setzen von „max-age“ auf 0 dazu führt, dass der Rest der Webseite nicht zwischengespeichert wird.
Dank des Konzepts des „Auto-Platzhaltersetzens“ betrachtet Drupal diesen Block als personalisierten Teil und verwandelt ihn in einen Platzhalter.
Das einzige Problem hierbei ist, dass wir den gesamten Block nachträglich durch einen Platzhalter ersetzen lassen:
<span data-big-pipe-placeholder-id="callback=Drupal%5Cblock%5CBlockViewBuilder%3A%3AlazyBuilder&args%5B0%5D
=profilewidget&args%5B1%5D=full&args%5B2%5D&token=QzMTPnxwihEGO
itjJB_tahJj8V-L-KopAVnEjVEMSsk"></span>
Es ist jedoch zu beachten, dass bestimmte Daten innerhalb des Blocks statisch oder für alle Benutzer konsistent bleiben können, wie hier:

Um unseren Block granulärer zu gestalten, können wir dynamische Teile in Platzhalter umwandeln, während der andere Blockinhalt zwischenspeicherbar bleibt und während des initialen Seitenladevorgangs geladen wird.
Schritt 1. Erstellung von Lazy Buildern
Lazy Builder werden unter Verwendung des Render-Arrays des Typs #lazy_builder implementiert, genau wie andere Elemente. Das Render-Array muss einen Rückruf als erstes Element und ein Array von Argumenten für diesen Rückruf als zweites Element enthalten.
Lazy Builder-Render-Elemente sollten nur die Eigenschaften #cache, #weight und #create_placeholder enthalten.
public function build() {
$build['user_data'] = [
'#lazy_builder' => [
'd_profiles.builder:build',
[],
],
'#create_placeholder' => TRUE,
];
$build['user_menu'] = $this->buildMenu()
$build['user_img'] = [
'#lazy_builder' => [
'd_profiles.builder:build',
['profile_widget_mini'],
],
'#create_placeholder' => TRUE,
];
return $build;
}
Schritt 2. Implementieren des TrustedCallbackInterface
Bevor wir weitergehen, müssen wir sicherstellen, dass unsere Lazy Builder-Implementierung die lazyBuilder()-Methode aufrufen kann. Dazu müssen wir das TrustedCallbackInterface implementieren, um Drupal mitzuteilen, dass unser Callback zulässig ist.
Beim Implementieren dieses Interface müssen wir eine Methode namens trustedCallbacks() hinzufügen, die automatisch von Drupal über die Erkennung des Interfaces aufgerufen wird. Der Rückgabewert dieser Methode muss alle Methoden in dieser Klasse enthalten, die als Callbacks verwendet werden können.
Hier ist die grundlegende Implementierung für unseren Block:
/**
* Stellt einen Lazy Builder für den Profilblock bereit.
*/
class ProfileBuilder implements TrustedCallbackInterface {
/**
* {@inheritdoc}
*/
public static function trustedCallbacks() {
return ['build'];
}
/**
* Profildetails aufbauen.
*/
public function build($view_mode = 'navbar_widget') {
return $this->entityBuilder->build($this->loadProfile(), $view_mode);
}
}
Infolgedessen wird der zwischengespeicherte Block so aussehen:
<div id="profile-widget" class="profile-widget dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdown-menu-button" data-toggle="dropdown" aria-expanded="false">
<div id="block-profilewidget" class="img img--round">
<span data-big-pipe-placeholder-id="callback=em_profiles.builder%3Abuild&args%5B0%5D=profile_widget_mini&token=ArkAzE-rR2gaSeRCkyb61vLT6nWbvDcIx0HQ8gjUMUs"></span>
</div>
</button>
<div class="dropdown-menu" aria-labelledby="dropdown-menu-button">
<section class="profile-widget__data p-5">
<h3 class="profile-widget__name title-h4 mb-2">Profil</h3>
<span data-big-pipe-placeholder-id="callback=em_profiles.builder%3Abuild&&token=ODDkF_Laqrq9ERh-djJN_UI_C1J2L6FtmRMh8luWPqk"></span>
</section>
<nav class="profile-widget__menu p-5" aria-labelledby="profile-widget">
<ul class="nav navbar-nav">
<li class="nav-item">
<a href="/user/settings" class="nav-link--icon-settings nav-link--icon nav-link" data-drupal-link-system-path="user/settings">Einstellungen</a>
</li>
<li class="nav-item">
<a href="/user/logout" class="nav-link--icon nav-link--icon-logout nav-link" data-drupal-link-system-path="user/logout">Abmelden</a>
</li>
</ul>
</nav>
</div>
</div>
Normalerweise wird der Callback des Lazy Builders bei jedem Seitenladevorgang ausgeführt, was das beabsichtigte Verhalten ist. In bestimmten Fällen kann es jedoch auch erforderlich sein, Platzhalter zu zwischenspeichern. Dazu müssen wir Cache-Schlüssel zusammen mit dem Cache-Kontext einfügen, wie im folgenden Beispiel:
$build['user_data'] = [
'#lazy_builder' => [
'em_profiles.builder:build',
[],
],
'#create_placeholder' => TRUE,
'#cache' => [
'contexts' => ['user'],
'keys' => [
'entity_view',
'user',
'profile',
'navbar_widget',
],
],
];
Schritt 3. Sicherstellen eines reibungslosen visuellen Seitenladeerlebnisses
Da Drupal BigPipe bestimmte Teile der Seite nur verzögert lädt, könnte dies zu einem stockenden Seitenladeerlebnis führen. Es hängt von unserem Thema und der Position der verzögert geladenen Inhalte ab.
Die einfachste Lösung besteht darin, dass die verzögert geladenen Inhalte in einem Bereich erscheinen, der für sie reserviert ist und ein Neufließen der Inhalte vermeidet. Alternativ können wir eine „Lade“-Animation auf alle BigPipe-Platzhalter in unserem Thema mit etwas CSS anwenden.
Die letzte mögliche Option besteht darin, ein Interface-Vorschau zu definieren, das mit Twig-Template von BigPipe gefüllt wird.
Vergleichen wir das endgültige Ergebnis der benutzerdefinierten Lazy-Builder-Strategie (1) mit der „Auto-Platzhalterungs-Strategie“ (2).
Benutzerdefinierte Lazy-Builder-Strategie (1)

Drupal „Auto-Platzhalterungs“-Strategie (2)
Beide Strategien funktionieren gut, aber man kann die Nachteile der Auto-Platzhalterung wie ein stockendes Seitenladeerlebnis (drastische Layout-Verschiebung) sehen.
Weitere Beispiele:
1. Statistikblock mit sofort geladenen statischen Teilen und später geladenen dynamischen Inhalten:


2. Ansichten mit Skelett:

Fehlersuche bei Lazy Buildern
Wenn Sie einen Lazy Builder implementiert haben und er das Laden Ihrer Drupal-Seite nicht beschleunigt oder einfach nicht wie erwartet funktioniert, können Sie Folgendes versuchen:
- Stellen Sie sicher, dass das Drupal BigPipe-Modul aktiviert ist.
- Überprüfen Sie die Cache-Einstellungen Ihrer Lazy Builder-Callback-Methode. Standardmäßig trifft Drupal einige Annahmen darüber, wie es zwischengespeichert werden soll, was nicht immer für Ihren Anwendungsfall richtig ist. Stattdessen können Sie die Cache-Einstellungen explizit festlegen.
- Eine vorgelagerte CDN- oder Varnish-Schicht könnte Ihre gesamte Webseite zwischenspeichern, sodass die gesamte Ausgabe des BigPipe-Renderprozesses gleichzeitig bereitgestellt wird. Sie müssen einen anderen Mechanismus finden, um dies zu umgehen.
Drupal BigPipe - Zusammenfassung
In diesem Artikel haben wir eine alternative Rendering-Strategie untersucht, die es uns ermöglicht, das Rendering von hochdynamischen Inhalten nur zu verzögern, nachdem die statischen Teile der Webseite bereits aus dem Cache geladen wurden.
BigPipe, das Drupal-Modul, kann dank einer verbesserten Renderpipeline und Render-API, insbesondere der Cache-Metadaten und Auto-Platzhalterung, die Leistung unserer Website automatisch verbessern.
Es ist jedoch wichtig zu beachten, dass die Verwendung von Drupal BigPipe nicht die Behebung grundlegender Leistungsprobleme ersetzt. Die Implementierung von Lazy Buildern zur Minderung der Auswirkungen von langsamem Code auf Ihrer Webseite wird das Problem nur verschleiern, anstatt es vollständig zu lösen. Durch die effektive Implementierung dieser Techniken können Sie die Leistung optimieren und das gesamte Benutzererlebnis auf Ihren Drupal-basierten Websites bereichern.