So beschleunigen Sie Ihre Next.js-App mit Code-Splitting und intelligenten Ladestrategien.
Veröffentlicht am 8. November 2019
Hier erfahren Sie mehr über die verschiedenen Arten von Code-Splitting und wie Sie dynamische Importe verwenden können, um Ihre Next.js-Apps zu beschleunigen.
Routen- und komponentenbasiertes Code-Splitting
Standardmäßig teilt Next.js Ihr JavaScript in separate Chunks für jede Route auf. Wenn Nutzer Ihre Anwendung laden, sendet Next.js nur den Code, der für die erste Route benötigt wird. Wenn Nutzer in der Anwendung navigieren, werden die Chunks abgerufen, die den anderen Routen zugeordnet sind. Durch die routenbasierte Codeaufteilung wird die Menge an Script, die gleichzeitig geparst und kompiliert werden muss, minimiert. Das führt zu schnelleren Seitenladezeiten.
Die routenbasierte Codeaufteilung ist zwar eine gute Standardeinstellung, Sie können den Ladevorgang aber durch Codeaufteilung auf Komponentenebene weiter optimieren. Wenn Ihre App große Komponenten enthält, ist es eine gute Idee, sie in separate Chunks aufzuteilen. So können alle großen Komponenten, die nicht kritisch sind oder nur bei bestimmten Nutzerinteraktionen (z. B. beim Klicken auf eine Schaltfläche) gerendert werden, verzögert geladen werden.
Next.js unterstützt dynamische import(), mit denen Sie JavaScript-Module (einschließlich React-Komponenten) dynamisch importieren und jeden Import als separaten Chunk laden können. Dadurch wird das Aufteilen von Code auf Komponentenebene ermöglicht. Außerdem können Sie das Laden von Ressourcen so steuern, dass Nutzer nur den Code herunterladen, den sie für den Teil der Website benötigen, den sie sich ansehen. In Next.js werden diese Komponenten standardmäßig serverseitig gerendert (Server-Side Rendering, SSR).
Dynamische Importe in Aktion
Dieser Beitrag enthält mehrere Versionen einer Beispiel-App, die aus einer einfachen Seite mit einer Schaltfläche besteht. Wenn Sie auf die Schaltfläche klicken, sehen Sie einen süßen Welpen. Im Laufe der einzelnen Versionen der App sehen Sie, wie sich dynamische Importe von statischen Importen unterscheiden und wie Sie damit arbeiten können.
In der ersten Version der App lebt der Welpe in components/Puppy.js. Damit das Welpenbild auf der Seite angezeigt wird, importiert die App die Komponente Puppy in index.js mit einer statischen Importanweisung:
import Puppy from "../components/Puppy";
So sehen Sie, wie Next.js die App bündelt:
Drücken Sie App ansehen, um sich eine Vorschau der Website anzusehen. Drücken Sie dann Vollbild
.
Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
Klicken Sie auf den Tab Netzwerk.
Klicken Sie das Kästchen Cache deaktivieren an.
Aktualisieren Sie die Seite.
Wenn Sie die Seite laden, wird der gesamte erforderliche Code, einschließlich der Puppy.js-Komponente, in index.js gebündelt:
Wenn Sie auf die Schaltfläche Click me (Klick mich) klicken, wird nur die Anfrage für das Welpen-JPEG auf dem Tab Network (Netzwerk) hinzugefügt:
Der Nachteil dieses Ansatzes ist, dass Nutzer die Puppy-Komponente laden müssen, auch wenn sie nicht auf die Schaltfläche klicken, um das Welpenbild zu sehen, da sie in index.js enthalten ist. In diesem kleinen Beispiel ist das nicht so wichtig, aber in realen Anwendungen ist es oft eine enorme Verbesserung, große Komponenten nur bei Bedarf zu laden.
Sehen wir uns nun eine zweite Version der App an, in der der statische Import durch einen dynamischen Import ersetzt wird. Next.js enthält next/dynamic, sodass dynamische Importe für alle Komponenten in Next möglich sind:
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
Folgen Sie der Anleitung aus dem ersten Beispiel, um den Netzwerk-Trace zu untersuchen.
Wenn Sie die App zum ersten Mal laden, wird nur index.js heruntergeladen. Dieses Mal ist sie 0,5 KB kleiner (sie ist von 37,9 KB auf 37,4 KB gesunken), da sie den Code für die Puppy-Komponente nicht enthält:
Die Komponente Puppy befindet sich jetzt in einem separaten Chunk, 1.js, der nur geladen wird, wenn Sie die Schaltfläche drücken:
In realen Anwendungen sind Komponenten oft viel größer. Durch das Lazy Loading von Komponenten kann die ursprüngliche JavaScript-Nutzlast um Hunderte von Kilobyte reduziert werden.
Dynamische Importe mit benutzerdefinierter Ladeanzeige
Wenn Sie Ressourcen verzögert laden, sollten Sie einen Ladeindikator einfügen, falls es zu Verzögerungen kommt. In Next.js können Sie dazu ein zusätzliches Argument für die Funktion dynamic() angeben:
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
So simulieren Sie eine langsame Netzwerkverbindung in den DevTools, um die Ladeanzeige in Aktion zu sehen:
Drücken Sie App ansehen, um sich eine Vorschau der Website anzusehen. Drücken Sie dann Vollbild
.
Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
Klicken Sie auf den Tab Netzwerk.
Klicken Sie das Kästchen Cache deaktivieren an.
Wählen Sie in der Drop-down-Liste Throttling (Drosselung) die Option Fast 3G (Schnelles 3G) aus.
Drücken Sie die Schaltfläche Click me (Klick mich).
Wenn Sie jetzt auf die Schaltfläche klicken, dauert es eine Weile, bis die Komponente geladen ist. In der Zwischenzeit wird in der App die Meldung „Wird geladen…“ angezeigt.
Dynamische Importe ohne SSR
Wenn Sie eine Komponente nur auf der Clientseite rendern müssen, z. B. ein Chat-Widget, können Sie die Option ssr auf false festlegen:
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
Fazit
Durch die Unterstützung dynamischer Importe bietet Next.js die Codeaufteilung auf Komponentenebene, wodurch sich die JavaScript-Nutzlasten minimieren und die Ladezeit der Anwendung verbessern lässt. Alle Komponenten werden standardmäßig serverseitig gerendert. Sie können diese Option bei Bedarf deaktivieren.