JavaScript-Nutzlasten durch Codeaufteilung reduzieren

Die meisten Webseiten und Anwendungen bestehen aus vielen verschiedenen Teilen. Anstatt das gesamte JavaScript, das die Anwendung ausmacht, 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 + Option + 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. Aktualisieren Sie die App.

Netzwerkbereich mit 71,2 KB JavaScript-Bundle

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

Im Quellcode (src/index.js) wird die Bibliothek lodash importiert und in dieser Anwendung verwendet. Lodash bietet viele nützliche Dienstprogrammfunktionen, hier wird jedoch 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 genutzt 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, um nur eine Methode aus lodash zu importieren. Ersetzen Sie zuerst diese Abhängigkeit in package.json:

"lodash": "^4.7.0",

durch diesen Codeblock:

"lodash.sortby": "^4.7.0",

Importieren Sie jetzt 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 einem 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.

Codeaufteilung

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 Bundle kann in zwei separate Blöcke 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 loaded) 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 Funktion import() ist Teil eines Angebots (derzeit in Phase 3 des TC39-Prozesses), um die Möglichkeit zum dynamischen Importieren eines Moduls zu bieten. Webpack unterstützt dies bereits und verwendet dieselbe Syntax wie im Vorschlag festgelegt.

import() gibt ein Promise zurück. Wenn es aufgelöst wird, wird das ausgewählte Modul bereitgestellt, das in einen separaten Teil aufgeteilt ist. 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 Versprechens-Kettecatch() wird für Fälle verwendet, in denen das Promise aufgrund eines Fehlers abgelehnt wird.

Als Letztes müssen Sie die Methode sortInput an das 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 einem 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 viel 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

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 Modulen für Drittanbieterknoten

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. SplitChunksPlugin kann dabei helfen.

Lazy Loading mit einem JavaScript-Framework

Viele gängige Frameworks und Bibliotheken, die Webpack verwenden, bieten Abstraktionen, um Lazy Loading zu vereinfachen als dynamische Importe in der Anwendung.

Auch wenn es hilfreich ist, zu verstehen, wie dynamische Importe funktionieren, sollten Sie immer die von Ihrem Framework/Ihrer Bibliothek empfohlene Methode verwenden, um bestimmte Module per Lazy Loading 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 dazu finden Sie im Leitfaden Kritische Chunks im Voraus laden.

Lazy Loading für mehr als nur Code

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