JavaScript-Nutzlasten durch Codeaufteilung reduzieren

Die meisten Webseiten und Anwendungen bestehen aus vielen verschiedenen Teilen. Anstatt das gesamte JavaScript, aus dem die Anwendung besteht, zu senden, sobald die erste Seite geladen wird, wird die Seitenleistung verbessert, wenn das JavaScript in mehrere Teile aufgeteilt wird.

In diesem Codelab wird gezeigt, wie Sie mithilfe der Code-Spaltung die Leistung einer einfachen Anwendung verbessern, die drei Zahlen sortiert.

In einem Browserfenster wird eine Anwendung mit dem Namen „Magischer Sortierer“ mit drei Feldern zum Eingeben von Zahlen und einer Sortierschaltfläche angezeigt.

Messen

Wie immer ist es wichtig, zuerst zu messen, wie gut eine Website abschneidet, bevor Sie Optimierungen vornehmen.

  1. Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.
  2. Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  3. Klicken Sie auf den Tab Netzwerk.
  4. Klicken Sie das Kästchen Cache deaktivieren an.
  5. Laden Sie die App neu.

Netzwerkbereich mit 71,2 KB JavaScript-Bundle

71,2 KB JavaScript, nur um ein paar Zahlen in einer einfachen Anwendung zu sortieren. What gives?

Im Quellcode (src/index.js) wird die lodash-Bibliothek importiert und in dieser Anwendung verwendet. Lodash bietet viele nützliche Dienstfunktionen, aber hier wird nur eine einzige Methode aus dem Paket verwendet. Es ist ein häufiger Fehler, vollständige Abhängigkeiten von Drittanbietern zu installieren und zu importieren, von denen nur ein kleiner Teil verwendet wird.

Optimieren

Es gibt mehrere Möglichkeiten, die Größe des Bundles zu reduzieren:

  1. Benutzerdefinierte Sortiermethode schreiben, anstatt eine Drittanbieterbibliothek zu importieren
  2. Verwenden Sie die integrierte Array.prototype.sort()-Methode, um numerisch zu sortieren.
  3. Nur die sortBy-Methode aus lodash importieren, nicht die gesamte Bibliothek
  4. Code für die Sortierung nur herunterladen, wenn der Nutzer auf die Schaltfläche klickt

Option 1 und 2 sind völlig geeignete Methoden, um die Größe des Bundles zu reduzieren. Sie sind für eine reale Anwendung wahrscheinlich am sinnvollsten. Diese werden in dieser Anleitung jedoch nicht verwendet, um den Lerneffekt zu steigern 😈.

Sowohl Option 3 als auch Option 4 tragen dazu bei, die Leistung dieser Anwendung zu verbessern. In den nächsten Abschnitten dieses Codelabs werden diese Schritte beschrieben. Wie bei jedem Codierungs-Tutorial sollten Sie immer versuchen, den Code selbst zu schreiben, anstatt ihn zu kopieren und einzufügen.

Nur das importieren, was Sie benötigen

Einige Dateien müssen geändert werden, damit nur die einzelne Methode aus lodash importiert wird. Ersetzen Sie zuerst diese Abhängigkeit in package.json:

"lodash": "^4.7.0",

durch diesen Codeblock:

"lodash.sortby": "^4.7.0",

Importieren Sie nun in src/index.js dieses Modul:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

Und aktualisieren Sie die Sortierung der Werte:

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Laden Sie die Anwendung neu, öffnen Sie die Entwicklertools und sehen Sie sich noch einmal den Bereich Netzwerk an.

Netzwerkbereich mit 15,2 KB JavaScript-Bundle

Bei dieser Anwendung konnte die Bundle-Größe mit sehr wenig Aufwand um mehr als das Vierfache reduziert werden. Es gibt jedoch noch Raum für Verbesserungen.

Code-Splitting

Webpack ist eines der beliebtesten Open-Source-Modul-Bundler, die derzeit verwendet werden. Kurz gesagt: Es bündelt alle JavaScript-Module (sowie andere Assets), aus denen eine Webanwendung besteht, in statischen Dateien, die vom Browser gelesen werden können.

Das in dieser Anwendung verwendete einzelne Bundle kann in zwei separate Chunks aufgeteilt werden:

  • Eine für den Code verantwortliche Person, aus dem unsere ursprüngliche Route besteht
  • Ein sekundärer Code-Chunk, der den Sortiercode enthält

Mit dynamischen Importen kann ein sekundärer Chunk lazy loaded (lazy-geladen) oder auf Anfrage geladen werden. In dieser Anwendung kann der Code, aus dem der Chunk besteht, nur geladen werden, wenn der Nutzer auf die Schaltfläche drückt.

Entfernen Sie zuerst den Import der obersten Ebene für die Sortiermethode in src/index.js:

import sortBy from "lodash.sortby";

Importieren Sie es in den Ereignis-Listener, der ausgelöst wird, wenn die Schaltfläche gedrückt wird:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

Die import()-Funktion ist Teil eines Vorschlags (der sich derzeit in Phase 3 des TC39-Prozesses befindet), um die Möglichkeit zum dynamischen Importieren eines Moduls hinzuzufügen. Webpack unterstützt dies bereits und folgt der im Vorschlag beschriebenen Syntax.

import() gibt ein Promise zurück. Wenn es aufgelöst wird, wird das ausgewählte Modul bereitgestellt, das in einen separaten Chunk aufgeteilt wird. Nachdem das Modul zurückgegeben wurde, wird mit module.default auf den Standardexport von lodash verwiesen. Das Versprechen ist mit einem anderen .then verknüpft, das eine sortInput-Methode aufruft, um die drei Eingabewerte zu sortieren. Am Ende der Versprechenskettecatch() wird verwendet, um Fälle zu behandeln, in denen das Versprechen aufgrund eines Fehlers abgelehnt wird.

Als Letztes müssen Sie die sortInput-Methode am Ende der Datei schreiben. Dies muss eine Funktion sein, die eine Funktion zurückgibt, die die importierte Methode aus lodash.sortBy annimmt. Die verschachtelte Funktion kann dann die drei Eingabewerte sortieren und das DOM aktualisieren.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Überwachen

Laden Sie die Anwendung noch einmal neu und beobachten Sie das Netzwerk-Steuerfeld. Sobald die App geladen wird, wird nur ein kleines anfängliches Bundle heruntergeladen.

Netzwerkbereich mit 2,7 KB JavaScript-Bundle

Nachdem die Schaltfläche zum Sortieren der Eingabezahlen gedrückt wurde, wird der Code-Chunk mit dem Sortiercode abgerufen und ausgeführt.

Netzwerkbereich mit einem JavaScript-Bundle von 2,7 KB, gefolgt von einem JavaScript-Bundle von 13,9 KB

Die Zahlen werden trotzdem sortiert.

Fazit

Codesplitting und Lazy Loading können äußerst nützliche Techniken sein, um die anfängliche Bundle-Größe Ihrer Anwendung zu reduzieren. Dies kann direkt zu wesentlich kürzeren Seitenladezeiten führen. Es gibt jedoch einige wichtige Dinge, die Sie beachten sollten, bevor Sie diese Optimierung in Ihre Anwendung einbinden.

Lazy-Loading-UI

Wenn Sie bestimmte Codemodule mit Lazy Loading laden, sollten Sie berücksichtigen, wie die Nutzung für Nutzer mit schwächeren Netzwerkverbindungen aussehen würde. Wenn ein sehr großer Codeblock aufgeteilt und geladen wird, wenn ein Nutzer eine Aktion ausführt, kann es so aussehen, als würde die Anwendung nicht mehr funktionieren. Daher sollten Sie eine Art Ladeanzeige anzeigen.

Lazy Loading von Drittanbieter-Node-Modulen

Es ist nicht immer die beste Lösung, Abhängigkeiten von Drittanbietern in Ihrer Anwendung zu lazily laden. Das hängt davon ab, wo Sie sie verwenden. In der Regel werden Abhängigkeiten von Drittanbietern in ein separates vendor-Bundle aufgeteilt, das im Cache gespeichert werden kann, da sie nicht so oft aktualisiert werden. Weitere Informationen dazu, wie Sie das SplitChunksPlugin verwenden können, finden Sie hier.

Lazy Loading mit einem JavaScript-Framework

Viele beliebte Frameworks und Bibliotheken, die webpack verwenden, bieten Abstraktionsschichten, die das Lazy Loading einfacher machen als die Verwendung dynamischer Importe in der Mitte Ihrer Anwendung.

Es ist zwar hilfreich, zu verstehen, wie dynamische Importe funktionieren, aber Sie sollten immer die vom Framework oder der Bibliothek empfohlene Methode verwenden, um bestimmte Module verzögert zu laden.

Vorabladen und Prefetching

Nutzen Sie nach Möglichkeit Browserhinweise wie <link rel="preload"> oder <link rel="prefetch">, um kritische Module noch schneller zu laden. webpack unterstützt beide Hinweise durch die Verwendung von magischen Kommentaren in Importanweisungen. Weitere Informationen finden Sie im Leitfaden Kritische Chunks im Voraus laden.

Lazy Loading für mehr als nur Code

Bilder können einen wichtigen Teil einer Anwendung ausmachen. Wenn Sie Inhalte, die sich außerhalb des Darstellungsbereichs des Geräts befinden, per Lazy Loading laden, kann dies die Geschwindigkeit einer Website erhöhen. Weitere Informationen dazu finden Sie im Lazysizes-Leitfaden.