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, kann die Seitenleistung verbessert werden, indem das JavaScript in mehrere Chunks aufgeteilt wird.

In diesem Codelab wird gezeigt, wie Sie Code-Splitting verwenden, um die Leistung einer einfachen Anwendung zu verbessern, die drei Zahlen sortiert.

In einem Browserfenster wird eine Anwendung mit dem Titel „Magic Sorter“ mit drei Feldern zur Eingabe von Zahlen und einer Schaltfläche zum Sortieren angezeigt.

Messen

Wie immer ist es wichtig, zuerst die Leistung einer Website zu messen, 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. Aktualisieren Sie die App.

Im Netzwerkbereich wird ein JavaScript-Bundle mit 71,2 KB angezeigt.

71,2 KB JavaScript-Code nur zum Sortieren einiger Zahlen in einer einfachen Anwendung. What gives?

Im Quellcode (src/index.js) wird die lodash-Bibliothek importiert und in dieser Anwendung verwendet. Lodash bietet viele nützliche Hilfsfunktionen, aber hier wird nur eine Methode aus dem Paket verwendet. Ein häufiger Fehler ist das Installieren und Importieren von vollständigen Drittanbieterabhängigkeiten, von denen nur ein kleiner Teil verwendet wird.

Optimieren

Es gibt mehrere Möglichkeiten, die Bundle-Größe zu verringern:

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

Option 1 und Option 2 sind absolut geeignete Methoden, um die Bundle-Größe zu reduzieren (und wären wahrscheinlich für eine echte Anwendung am sinnvollsten). Sie werden jedoch in dieser Anleitung nicht verwendet, um die Konzepte zu veranschaulichen 😈.

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 behandelt. Wie bei jedem Coding-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",

mit diesem:

"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 so 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>
  `
});

Aktualisieren Sie die Anwendung, öffnen Sie die Entwicklertools und sehen Sie sich das Netzwerk-Steuerfeld noch einmal an.

Im Netzwerkbereich wird ein JavaScript-Bundle mit einer Größe von 15,2 KB angezeigt.

Bei dieser Anwendung konnte die Bundle-Größe mit sehr wenig Aufwand um mehr als das Vierfache reduziert werden. Es gibt aber noch weiteres Verbesserungspotenzial.

Code-Splitting

webpack ist einer der beliebtesten Open-Source-Modul-Bundler, die heute verwendet werden. Kurz gesagt: Es bündelt alle JavaScript-Module (sowie andere Assets), aus denen eine Webanwendung besteht, in statische 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, aus dem unsere erste Route besteht
  • Ein sekundärer Chunk, der unseren Sortiercode enthält

Mithilfe von dynamischen Importen kann ein sekundärer Chunk verzögert geladen oder bei Bedarf 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 sie im Event-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 Vorschlags (derzeit in Phase 3 des TC39-Prozesses), die Möglichkeit zum dynamischen Importieren eines Moduls einzuführen. webpack unterstützt dies bereits und folgt der im Vorschlag festgelegten Syntax.

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

Als Letztes muss noch die sortInput-Methode am Ende der Datei geschrieben werden. Dies muss eine Funktion sein, die eine Funktion zurückgibt, die die importierte Methode aus lodash.sortBy verwendet. 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 ein letztes Mal neu und behalten Sie das Network-Panel (Netzwerk) im Blick. Sobald die App geladen wird, wird nur ein kleines anfängliches Bundle heruntergeladen.

Im Netzwerkbereich wird ein JavaScript-Bundle mit 2,7 KB angezeigt.

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

Im Bereich „Netzwerk“ werden zwei JavaScript-Bundles angezeigt: eines mit 2,7 KB und eines mit 13,9 KB.

Die Zahlen werden weiterhin sortiert.

Fazit

Code-Splitting und Lazy Loading können sehr nützliche Techniken sein, um die anfängliche Bundle-Größe Ihrer Anwendung zu verringern. Dies kann direkt zu viel schnelleren Seitenladezeiten führen. Es gibt jedoch einige wichtige Punkte, die berücksichtigt werden müssen, bevor Sie diese Optimierung in Ihre Anwendung einbauen.

Lazy Loading der Benutzeroberfläche

Wenn Sie bestimmte Module von Code verzögert laden, sollten Sie berücksichtigen, wie die Nutzererfahrung für Nutzer mit schwächeren Netzwerkverbindungen aussehen würde. Wenn ein sehr großer Codeabschnitt aufgeteilt und geladen wird, wenn ein Nutzer eine Aktion ausführt, kann es so aussehen, als ob die Anwendung nicht mehr funktioniert. Zeigen Sie daher eine Art Ladeanzeige an.

Lazy Loading von Node-Modulen von Drittanbietern

Es ist nicht immer die beste Vorgehensweise, Drittanbieterabhängigkeiten in Ihrer Anwendung verzögert zu laden. Das hängt davon ab, wo Sie sie verwenden. Normalerweise werden Drittanbieterabhängigkeiten in ein separates vendor-Bundle aufgeteilt, das im Cache gespeichert werden kann, da es nicht so oft aktualisiert wird. SplitChunksPlugin

Lazy Loading mit einem JavaScript-Framework

Viele beliebte Frameworks und Bibliotheken, die Webpack verwenden, bieten Abstraktionen, um Lazy Loading zu vereinfachen, anstatt dynamische Importe in der Mitte Ihrer Anwendung zu verwenden.

Es ist zwar nützlich zu verstehen, wie dynamische Importe funktionieren, aber Sie sollten immer die von Ihrem Framework/Ihrer Bibliothek empfohlene Methode zum Lazy Loading bestimmter Module verwenden.

Vorabladen und Prefetching

Nutzen Sie nach Möglichkeit Browser-Hinweise wie <link rel="preload"> oder <link rel="prefetch">, um kritische Module noch früher zu laden. webpack unterstützt beide Hinweise durch die Verwendung von Magic Comments in Importanweisungen. Weitere Informationen dazu finden Sie im Leitfaden Wichtige Chunks vorab laden.

Lazy Loading von mehr als nur Code

Bilder können einen erheblichen Teil einer Anwendung ausmachen. Wenn Sie Elemente, die sich unter dem Falz oder außerhalb des Darstellungsbereichs des Geräts befinden, erst dann laden, wenn sie benötigt werden, kann das die Geschwindigkeit einer Website erhöhen. Weitere Informationen dazu finden Sie im Lazysizes-Leitfaden.