Wie Gatsby Next.js umging

Der Autor des Artikels, dessen Übersetzung wir heute veröffentlichen, arbeitet als Programmierer bei Antler. Dieses Unternehmen ist ein globaler Startup-Generator. Bei Antler finden mehrmals im Jahr Demo-Tage statt, an denen viele Startup-Entwickler und Investoren aus der ganzen Welt zusammenkommen. Die Situation um COVID-19 zwang Antler, seine Ereignisse in ein Online-Format zu übersetzen.



Das Unternehmen wollte sicherstellen, dass Besucher ihrer virtuellen Veranstaltungen, ohne von irgendetwas abgelenkt zu werden und nirgendwo hängen zu bleiben, das Wichtigste sehen. Die Ideen von Startups, die der Öffentlichkeit präsentiert werden, werden als Inhalt von Webseiten ausgedrückt. Virtuelle Demonstrationstage können für ein ziemlich breites Publikum von Interesse sein. Einige Mitglieder dieses Publikums nehmen möglicherweise zum ersten Mal an so etwas teil. Daher musste das Unternehmen alles auf die bestmögliche Weise tun und das Hochladen von Seiten, die Startups darstellen, mit hoher Geschwindigkeit bereitstellen. Sie entschieden, dass dies nur dann der Fall ist, wenn eine leistungsstarke progressive Webanwendung (PWA, Progressive Web App) nützlich sein kann. Das Hauptproblem bestand darin, die richtige Technologie für die Entwicklung von PWA zu finden.


Server-Rendering oder statischer Site-Generator?


Zunächst möchte ich Ihnen den Kurs ein wenig vorstellen. Alle unsere Projekte basieren auf React und der Material-UI-Bibliothek. Aus diesem Grund haben wir uns zunächst entschieden, nicht von diesem Technologie-Stack abzuweichen, um eine hohe Entwicklungsgeschwindigkeit zu gewährleisten und das neue Projekt mit dem zu vereinbaren, was wir bereits haben. Der Hauptunterschied zwischen diesem neuen Projekt und unseren anderen React-Anwendungen bestand darin, dass die Datenbank für sie mit der Create-React-App erstellt wurde und dass sie vollständig auf dem Client gerendert wurden (CSR, Client-Side Rendering). Dies führte insbesondere dazu, dass Benutzer beim erstmaligen Laden der Anwendung gezwungen waren, einen leeren weißen Bildschirm zu beobachten, während der JavaScript-Code des Projekts geladen, verarbeitet und ausgeführt wurde.

Wir brauchten ein kompromissloses Leistungsniveau. Aus diesem Grund haben wir uns Gedanken darüber gemacht, entweder serverseitiges Rendering (SSR, serverseitiges Rendering) oder einen statischen Site-Generator (SSG, statischer Site-Generator) zu verwenden, damit das anfängliche Laden von Anwendungen so schnell wie möglich erfolgt.

Unsere Daten werden im Cloud Firestore gespeichert und wir greifen mit Algolia darauf zu. Auf diese Weise können wir auf Datenbankfeldebene den öffentlichen Zugriff auf Daten mit eingeschränkten API-Schlüsseln steuern. Dies verbessert auch die Abfrageleistung. Aus Erfahrung wissen wir, dass Algolia-Abfragen schneller als normal sind und dass das komprimierte Firestore-JavaScript-SDK 86 KB groß ist . Im Fall von Algolia sind dies 7,5 Kb .

Darüber hinaus wollten wir die Daten, die wir unseren Kunden geben, so aktuell wie möglich gestalten. Dies würde uns helfen, fehlerhafte Daten, die versehentlich veröffentlicht werden könnten, sehr schnell zu korrigieren. Während die Standardpraxis von SSG die Implementierung relevanter Datenanforderungen während der Montage des Projekts vorsieht, haben wir erwartet, dass die Daten in unserer Datenbank ziemlich häufig geschrieben werden. Insbesondere handelt es sich um Datenaufzeichnungen, die von Administratoren über die Firetable- Schnittstelle initiiert wurdenund auf Initiative der Gründer der Projekte, die das Webportal nutzen. Dies führt zu einer wettbewerbsfähigen Montage des Projekts. Aufgrund der strukturellen Merkmale unserer Datenbank können geringfügige Änderungen zu neuen Projektmontagevorgängen führen. Dies macht unsere CI / CD-Pipeline äußerst ineffizient. Daher mussten die Anforderungen zum Empfangen von Daten aus dem Repository jedes Mal ausgeführt werden, wenn ein Benutzer das Laden einer Seite anfordert. Leider bedeutete dies, dass unsere Lösung kein Beispiel für ein „sauberes“ SSG-Projekt sein würde.

Ursprünglich wurde unsere Anwendung auf der Basis von Gatsby erstellt, da wir bereits auf Gatsby erstellte Zielseiten verwendet haben und auf einer davon bereits die Material-UI-Bibliothek verwendet wurde. Die erste Version des Projekts bildete eine Seite, auf der während des Ladens der Daten ein "Skelett" angezeigt wurde. Gleichzeitig lag die erste inhaltliche Farbe (FCP) im Bereich von 1 Sekunde.


Herunterladen des "Skeletts" der Seite mit anschließendem Laden der Daten

Die Lösung erwies sich als interessant, hatte jedoch ihre Nachteile, da die Daten für die Ausgabe der Seite auf Initiative des Kunden heruntergeladen wurden:

  • Um den Inhalt der Seite zu sehen, müssten Benutzer auf den Download dieser Seite selbst und der darin angezeigten Daten warten, die durch 4 Anfragen an Algolia erhalten wurden.
  • JS- . , React «» . DOM.
  • . , , .

Aus diesem Grund habe ich mich am langen Wochenende entschlossen, mit der SSR-Version des mit Next.js erstellten Projekts zu experimentieren. Zum Glück hatte die Dokumentation für Material-UI ein Beispielprojekt für Next.js. Daher musste ich dieses Framework nicht von Grund auf neu lernen. Ich musste nur einige Teile des Tutorials und der Dokumentation durchsehen. Ich habe die Anwendung in ein Projekt konvertiert, das auf dem Server gerendert wurde. Wenn ein Benutzer das Laden einer Seite angefordert hat, hat der Server Datenanforderungen ausgeführt, die zum Ausfüllen der Seite erforderlich sind. Dieser Schritt ermöglichte es uns, alle drei oben genannten Probleme zu lösen. Hier sind die Testergebnisse für zwei Anwendungsoptionen.


Ergebnisse der Recherche nach Anwendungen mit Google PageSpeed ​​Insights . Links ist Gatsby (SSG), rechts ist Next.js (SSR) ( Originalbild ).

Der FCP für die Next.js-Version des Projekts war etwa dreimal höher als für die auf Gatsby basierende Version. Die Gatsby-Version des Projekts hatte einen Geschwindigkeitsindex von 3,3 Sekunden, während die Next.js-Version 6,2 Sekunden hatte. Die Zeit bis zum ersten Byte (TTFB, Time To First Byte) betrug 2,56 Sekunden bei Verwendung von Next.js und 10 bis 20 ms bei Verwendung von Gatsby.

Es ist zu beachten, dass die Next.js-Version der Site für einen anderen Dienst bereitgestellt wurde (hier haben wir die Dienste ZEIT Now und Firebase Hosting verwendet - dies könnte sich auch auf die Erhöhung des TTFB auswirken). Trotzdem war klar, dass die Übertragung von Daten-Upload-Vorgängen auf den Server die Site langsamer erscheinen ließ, obwohl alle Seitenmaterialien ungefähr zur gleichen Zeit geladen wurden. Tatsache ist, dass der Benutzer in der Next.js-Version des Projekts für einige Zeit nur eine leere weiße Seite sieht.


Screenshot zeigt das Laden von zwei Versionen einer Anwendung. Der Download wurde nicht gleichzeitig abgeschlossen. Die Datensätze werden synchronisiert, sobald Sie die Eingabetaste drücken.

All dies gibt uns eine wichtige Lehre aus dem Bereich der Webentwicklung: Sie müssen den Benutzern visuelles Feedback geben. Eine Studie ergab, dass Anwendungen, die Skelettbildschirme verwenden, schneller geladen werden.

Darüber hinaus entspricht dieses Ergebnis nicht der Stimmung, die Sie möglicherweise beim Lesen von Artikeln über die Webentwicklung in den letzten Jahren hatten. Wir sprechen nämlich von der Tatsache, dass die Verwendung der Ressourcen des Clients nichts auszusetzen hat und dass die SSR keine umfassende Lösung für Leistungsprobleme darstellt.

Leistung bei der statischen Site-Generierung: Vergleich von Gatsby und Next.js.


Während die beiden betrachteten Frameworks Gatsby und Next.js für ihre Fähigkeit bekannt sind, statische Sites und Server-Rendering zu generieren, wurde die Unterstützung für SSG in Next.js 9.3 verbessert, was es zu einem Konkurrenten von Gatsby macht.

Zum Zeitpunkt dieses Schreibens war die Fähigkeit von Next.js, statische Sites zu generieren, noch sehr neu. Sie war etwas mehr als einen Monat alt. Sie wird immer noch auf der ersten Seite des Projekts gemeldet. Jetzt gibt es nicht mehr viele Vergleiche der SSG-Funktionen von Gatsby und Next.js (oder vielleicht gibt es überhaupt keine derartigen Vergleiche). Aus diesem Grund habe ich beschlossen, mein eigenes Experiment durchzuführen.

Ich habe die Gatsby-Version des Projekts auf den Status zurückgesetzt, als die Daten auf den Client heruntergeladen wurden, und sie so erstellt, dass beide Versionen der Anwendung genau die gleichen Funktionen haben. Ich musste nämlich entfernen, wofür Gatsby-Plugins verantwortlich sind: SEO-Funktionen, Generieren von Favoriten, PWA-Manifest. Um ausschließlich von Frameworks erstellte JavaScript-Bundles zu vergleichen, habe ich keine Bilder und andere Inhalte, die von externen Quellen heruntergeladen wurden, in die Projekte aufgenommen. Beide Versionen der Anwendung wurden auf der Firebase Hosting-Plattform bereitgestellt. Als Referenz wurden zwei Versionen der Anwendung basierend auf Gatsby 2.20.9 und Next.js 9.3.4 erstellt.

Ich habe Lighthouse 6 Mal für jede Version auf meinem Computer ausgeführt. Die Ergebnisse zeigten einen leichten Vorteil für Gatsby.


Durchschnittswerte nach 6 Lighthouse-Starts für jedes Framework ( Originalbild )

In Bezug auf die Gesamtleistungsbewertung lag die Next.js-Version nur geringfügig hinter der Gatsby-Version zurück. Gleiches gilt für FCP und Speed ​​Index. Die nächste mögliche Verzögerung der ersten Eingabe für die Next.js-Version der Anwendung ist geringfügig höher als für die Gatsby-Version.

Um besser zu verstehen, was passiert, habe ich die Registerkarte "Netzwerk" der Chrome-Entwicklertools aufgerufen. Wie sich herausstellte, ist in der Next.js-Version des Projekts die Anzahl der Fragmente, in die der JavaScript-Code aufgeteilt wird, 3 höher als in der Gatsby-Version (ohne Manifestdateien), aber der komprimierte Code ist 20 KB kleiner. Können die zusätzlichen Anforderungen, die zum Herunterladen dieser Dateien erforderlich sind, die Vorteile eines kleineren Bundles so stark überwiegen, dass die Leistung beeinträchtigt wird?


In der Gatsby-Version des Projekts werden 7 Anforderungen ausgeführt, um 379 KB Daten herunterzuladen. In der Next.js-Version des Projekts - 12 Anforderungen zum Herunterladen von 359 KB Daten ( Originalbild )

Wenn Sie die JavaScript-Leistung analysieren, geben die Entwicklertools an, dass die Next.js-Version des Projekts zusätzliche 300 ms für das erste Rendern benötigt dass diese Version mehr Zeit für die Aufgabe "Skript auswerten" benötigt. In den Tools des Entwicklers wurde diese Aufgabe sogar als "lange Aufgabe" markiert.


Analyse der Leistung verschiedener Projektoptionen mithilfe der Registerkarte Leistung der Chrome-Entwicklertools ( Originalbild )

Ich habe den Projektcode verglichen, um festzustellen, ob es Unterschiede in der Implementierung gibt, die die Leistung beeinträchtigen könnten. Mit Ausnahme des Entfernens von unnötigem Code und Korrekturen, die mit fehlenden TypeScript-Typen verbunden sind, bestand der einzige Unterschied in der Implementierung eines reibungslosen Bildlaufs der Seite beim Verschieben zu ihren einzelnen Teilen. Diese Funktion wurde zuvor von einer Datei eingeführtgatsby-browser.jsund in eine dynamisch importierte Komponente verschoben. Infolgedessen würde dieser Code nur in einem Browser ausgeführt. (Wir haben das Smooth-Scroll- Paket npm verwendet, und beim Importieren benötigt er ein Objektwindow.) Dieses Problem mag der Schuldige sein, aber ich weiß nicht, wie es in Next.js behandelt wird.

Gatsby ist aus Sicht des Entwicklers bequemer


Am Ende habe ich mich für die Gatsby-Version des Projekts entschieden. Außerdem habe ich hier den sehr kleinen Leistungsvorteil, den Gatsby im Vergleich zum SSG-Mechanismus von Next.js gezeigt hat, nicht berücksichtigt (ich werde mich nicht ernsthaft an den Vorteil von 0,6 Sekunden halten?). Tatsache ist, dass in der Gatsby-Version des Projekts bereits viele PWA-Funktionen implementiert sind, und ich habe nicht den Sinn gesehen, sie in der Next.js-Version der Anwendung erneut zu implementieren.

Als ich gerade die erste Gatsby-Version des Projekts erstellte, konnte ich dem Projekt schnell einige nützliche PWA-Funktionen hinzufügen. Um beispielsweise jeder Seite meine eigenen Meta-Tags hinzuzufügen, die für SEO benötigt werden, musste ich nur das Handbuch lesen . Um das Projekt mit einem PWA-Manifest auszustatten, musste ich nur das entsprechende Plugin verwenden. Um das Projekt mit Favicons auszustatten, die alle verfügbaren Plattformen unterstützen (und in diesem Fall gibt es immer noch ein schreckliches Durcheinander ), musste ich nicht einmal etwas tun, da die Favicon-Unterstützung Teil des Plugins ist, das für das Manifest verantwortlich ist. Es ist sehr bequem!

Das Implementieren derselben Funktionen in der Next.js-Version der Anwendung würde mehr Arbeit erfordern. Ich müsste nach Schulungshandbüchern suchen, nach allen möglichen „Best Practices“. Und die Tatsache, dass ich sowieso Erfolg haben würde, würde mir keine Vorteile bringen. Immerhin unterscheidet sich die Next.js-Version des Projekts nicht in der höheren Leistung als die Gatsby-Version. Dies war außerdem der Grund, warum ich beschlossen habe, die entsprechenden Funktionen der Gatsby-Version des Projekts einfach zu deaktivieren und mit der Next.js-Version zu vergleichen. Die Next.js-Dokumentation ist prägnanter als die Gatsby-Dokumentation (möglicherweise ist Next.js kleiner als Gatsby) Ich mag das gamifizierte Next.js.-Tutorial sehr Die umfangreichere Gatsby-Dokumentation ist jedoch bei der tatsächlichen Entwicklung von PWA wertvoller, obwohl sie auf den ersten Blick riesig aussieht.


Gatsby-Dokumentation

Richtig, ich kann nicht über die Stärken von Next.j schweigen:

  • Dank des Tutorials und der übersichtlichen Dokumentation von Next.js scheint dieses Framework schneller zu erlernen als Gatsby.
  • Das in Next.js verwendete Datenladesystem basiert auf asynchronen Funktionen und der Fetch-API. Infolgedessen hat der Entwickler bei der Entwicklung von Next.js nicht das Gefühl, dass er GraphQL lernen muss, um die Funktionen des Frameworks voll nutzen zu können.
  • Next.js TypeScript, Gatsby , ( ). Next.js , , , .

Dank der Tatsache, dass Next.js die SSG-Unterstützung verbessert hat, ist dieses Framework zu einem leistungsstarken Tool geworden, mit dem auf der Ebene jeder einzelnen Seite die Arbeitsweise ausgewählt werden kann. Dies kann SSR, SSG oder CSR sein.

Wenn ich diese Anwendung in einer vollständig statischen Form generieren könnte, würde Next.js besser zu mir passen, da ich die Standard-JS-API von Algolia verwenden und den Code zum Laden von Daten in derselben Datei wie halten könnte und Komponentencode. Da Algolia keine integrierte GraphQL-API hat und es kein Gatsby-Plugin für Algolia gibt, müsste für die Implementierung eines solchen Mechanismus in Gatsby dieser Code einer neuen Datei hinzugefügt werden . Und dies widerspricht der intuitiven deklarativen Beschreibung von Seiten.

Informationen zu zusätzlichen Möglichkeiten zur Verbesserung der Projektleistung


Nachdem wir das Problem der Auswahl eines Frameworks gelöst haben, kann festgestellt werden, dass es zusätzliche Möglichkeiten zur Verbesserung der Projektleistung gibt, die nicht mit dem Framework zusammenhängen. Diese Verbesserungen können die Lighthouse-Projektbewertung auf 100 bringen.

  • In der Mailingliste von March Algolia wurde empfohlen, einen Hinweis hinzuzufügen preconnect, um die Geschwindigkeit der Abfrageausführung weiter zu erhöhen. (Richtig, leider wird im Newsletter das falsche Codefragment angegeben. Hier ist der richtige Code.)
  • . JS- CSS-, webpack- Gatsby. Gatsby . , , Netlify Amazon S3. , Firebase Hosting, , .
  • Wir verwenden JPEG- und PNG-Bilder, die von Startup-Erstellern in der Anwendung hochgeladen wurden. Wir komprimieren und optimieren sie nicht. Die Verbesserung dieses Aspekts unserer Anwendung ist eine ziemliche Herausforderung und geht über den Rahmen dieses Projekts hinaus. Darüber hinaus wäre es einfach großartig, wenn alle diese Bilder in das WebP-Format konvertiert würden. Infolgedessen müssten wir Bilder nur in einem hocheffizienten Grafikformat speichern. Leider macht das Safari WebKit-Entwicklungsteam wie bei vielen anderen PWA-Funktionen süchtig nach WebP-Unterstützung. Jetzt ist es der einzige große Browser, der dieses Format nicht unterstützt .

Zusammenfassung


Wenn wir kurz zusammenfassen, worüber wir hier gesprochen haben, können wir Folgendes sagen:

  • Die Ausgabe der "Skelett" -Version der Seite während des Ladens von Daten durch den Client erzeugt dem Benutzer das Gefühl eines schnelleren Website-Betriebs als wenn der Benutzer eine leere Seite betrachtet, während der Server Daten lädt.
  • Die Gatsby-Version der Site war nur geringfügig schneller als die Next.js-Version. Das Gatsby-Plug-In-System und die hochwertige Projektdokumentation erhöhen jedoch die Benutzerfreundlichkeit dieses Frameworks für den Entwickler.

Liebe Leser! Verwenden Sie statische Site-Generatoren oder serverseitige Rendering-Systeme, um Ihre Projekte zu beschleunigen?


All Articles