Nicht verwendeten Code entfernen

In diesem Codelab verbessern Sie die Leistung der folgenden Anwendung, indem Sie alle nicht verwendeten und nicht benötigten Abhängigkeiten entfernen.

App – Screenshot

Messen

Es empfiehlt sich immer, zuerst zu messen, wie gut eine Website abschneidet, bevor Sie Optimierungen vornehmen.

  • Wenn Sie sich eine Vorschau der Website ansehen möchten, klicken Sie auf App ansehen und dann auf Vollbild Vollbild.

Klicken Sie auf Ihr Lieblingskätzchen! In dieser Anwendung wird die Realtime Database von Firebase verwendet. Daher wird der Punktestand in Echtzeit aktualisiert und mit allen anderen Nutzern der App synchronisiert. 🐈

  1. Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Option + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  2. Klicken Sie auf den Tab Netzwerk.
  3. Klicken Sie das Kästchen Cache deaktivieren an.
  4. Aktualisieren Sie die App.

Ursprüngliche Bundle-Größe von 992 KB

Fast 1 MB JavaScript werden zum Laden dieser einfachen Anwendung gesendet.

Sehen Sie sich die Projektwarnungen in den DevTools an.

  • Klicken Sie auf den Tab Console.
  • Achten Sie darauf, dass Warnings im Drop-down-Menü „Ebenen“ neben der Eingabe Filter aktiviert ist.

Warnungsfilter

  • Sehen Sie sich die angezeigte Warnung an.

Konsolenwarnung

Firebase, eine der in dieser Anwendung verwendeten Bibliotheken, warnt Entwickler, das gesamte Paket nicht zu importieren, sondern nur die verwendeten Komponenten. Mit anderen Worten: Es gibt nicht verwendete Bibliotheken, die in dieser Anwendung entfernt werden können, um das Laden zu beschleunigen.

Es gibt auch Fälle, in denen eine bestimmte Bibliothek verwendet wird, es aber eine einfachere Alternative gibt. Das Entfernen nicht benötigter Bibliotheken wird später in dieser Anleitung behandelt.

Bundle analysieren

Die Anwendung hat zwei Hauptabhängigkeiten:

  • Firebase: Eine Plattform, die eine Reihe nützlicher Dienste für iOS-, Android- oder Webanwendungen bietet. Hier werden die Informationen für jedes Kätzchen in Echtzeit in der Realtime Database gespeichert und synchronisiert.
  • Moment.js: Eine Dienstprogrammbibliothek, die die Verarbeitung von Datumsangaben in JavaScript erleichtert. Das Geburtsdatum jedes Kätzchens wird in der Firebase-Datenbank gespeichert. Anhand von moment wird das Alter in Wochen berechnet.

Wie können nur zwei Abhängigkeiten zu einer Bundle-Größe von fast 1 MB beitragen? Nun, einer der Gründe ist, dass jede Abhängigkeit wiederum eigene Abhängigkeiten haben kann, sodass es weit mehr als nur zwei gibt, wenn jede Tiefe/Zweig des Abhängigkeitsbaums berücksichtigt wird. Wenn viele Abhängigkeiten enthalten sind, kann eine Anwendung relativ schnell groß werden.

Analysieren Sie den Bündelungstool, um sich ein besseres Bild von der Situation zu machen. Es gibt eine Reihe von von der Community entwickelten Tools, die Ihnen dabei helfen können, z. B. webpack-bundle-analyzer.

Das Paket für dieses Tool ist bereits als devDependency in der App enthalten.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Das bedeutet, dass es direkt in der webpack-Konfigurationsdatei verwendet werden kann. Importieren Sie es ganz am Anfang von webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Fügen Sie es jetzt als Plug-in ganz am Ende der Datei im Array plugins hinzu:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

Wenn die Anwendung neu geladen wird, sollte anstelle der App eine Visualisierung des gesamten Bundles angezeigt werden.

Webpack Bundle Analyzer

Nicht so süß wie Kätzchen 🐱, aber trotzdem unglaublich hilfreich. Wenn Sie den Mauszeiger auf eines der Pakete bewegen, wird die Größe auf drei verschiedene Arten dargestellt:

Statistische Größe Größe vor Minimierung oder Komprimierung.
Geparste Größe Größe des tatsächlichen Pakets im Bundle nach der Kompilierung. Version 4 von webpack (die in dieser Anwendung verwendet wird) minimiert die kompilierten Dateien automatisch. Deshalb ist sie kleiner als die statistische Größe.
Mit gzip komprimierte Größe Größe des Pakets, nachdem es mit GZIP-Codierung komprimiert wurde. Dieses Thema wird in einem separaten Leitfaden behandelt.

Mit dem Webpack-Bundle-Analyzer-Tool können Sie nicht verwendete oder nicht benötigte Pakete leichter identifizieren, die einen großen Prozentsatz des Bundles ausmachen.

Nicht verwendete Pakete entfernen

Die Visualisierung zeigt, dass das firebase-Paket viel mehr als nur eine Datenbank enthält. Es enthält zusätzliche Pakete wie:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Das sind alles tolle Firebase-Dienste (weitere Informationen finden Sie in der Dokumentation). Da sie aber in der Anwendung nicht verwendet werden, gibt es keinen Grund, sie alle zu importieren.

Machen Sie die Änderungen in webpack.config.js rückgängig, um die Anwendung wieder zu sehen:

  • Entfernen Sie BundleAnalyzerPlugin aus der Liste der Plug-ins:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • Entfernen Sie nun den nicht verwendeten Import oben in der Datei:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

Die Anwendung sollte jetzt normal geladen werden. Ändern Sie src/index.js, um die Firebase-Importe zu aktualisieren.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Wenn die App jetzt neu geladen wird, wird die Entwicklertools-Warnung nicht mehr angezeigt. Im Bereich Netzwerk der DevTools ist außerdem eine erfreuliche Verringerung der Bundle-Größe zu sehen:

Bundle-Größe auf 480 KB reduziert

Mehr als die Hälfte der Größe des Pakets wurde entfernt. Firebase bietet viele verschiedene Dienste und Entwickler haben die Möglichkeit, nur die zu verwenden, die sie tatsächlich benötigen. In dieser Anwendung wurde nur firebase/database zum Speichern und Synchronisieren aller Daten verwendet. Der Import firebase/app, mit dem die API-Oberfläche für jeden der verschiedenen Dienste eingerichtet wird, ist immer erforderlich.

Viele andere beliebte Bibliotheken, z. B. lodash, ermöglichen es Entwicklern auch, verschiedene Teile ihrer Pakete selektiv zu importieren. Wenn Sie die Bibliotheksimporte in einer Anwendung so aktualisieren, dass nur die tatsächlich verwendeten Elemente enthalten sind, können Sie ohne großen Aufwand erhebliche Leistungsverbesserungen erzielen.

Die Größe des Bundles wurde zwar deutlich reduziert, aber es gibt noch viel zu tun. 😈

Nicht benötigte Pakete entfernen

Im Gegensatz zu Firebase kann der Import von Teilen der moment-Bibliothek nicht so einfach erfolgen. Vielleicht kann sie aber vollständig entfernt werden?

Das Geburtsdatum jedes niedlichen Kätzchens wird in der Firebase-Datenbank im Unix (Millisekunden) gespeichert.

Geburtsdaten im Unix-Format gespeichert

Dies ist ein Zeitstempel für ein bestimmtes Datum und eine bestimmte Uhrzeit, der durch die Anzahl der Millisekunden dargestellt wird, die seit dem 1. Januar 1970, 00:00 Uhr UTC, vergangen sind. Wenn das aktuelle Datum und die aktuelle Uhrzeit im selben Format berechnet werden können, kann wahrscheinlich eine kleine Funktion zum Ermitteln des Alters jedes Kätzchens in Wochen erstellt werden.

Wie immer sollten Sie beim Lesen nicht einfach kopieren und einfügen. Entfernen Sie zuerst moment aus den Importen in src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

Es gibt einen Firebase-Ereignis-Listener, der Wertänderungen in unserer Datenbank verarbeitet:

favoritesRef.on("value", (snapshot) => { ... })

Fügen Sie darüber eine kleine Funktion hinzu, um die Anzahl der Wochen ab einem bestimmten Datum zu berechnen:

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

In dieser Funktion wird die Differenz in Millisekunden zwischen dem aktuellen Datum und der Uhrzeit (new Date).getTime() und dem Geburtsdatum (das Argument birthDate, bereits in Millisekunden) berechnet und durch die Anzahl der Millisekunden in einer Woche geteilt.

Schließlich können alle Instanzen von moment im Ereignis-Listener entfernt werden, indem stattdessen diese Funktion verwendet wird:

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

Aktualisieren Sie jetzt die Anwendung und sehen Sie sich noch einmal den Bereich Netzwerk an.

Bundle-Größe auf 225 KB reduziert

Die Größe unseres Bundles wurde um mehr als die Hälfte reduziert.

Fazit

Nach diesem Codelab sollten Sie ein gutes Verständnis dafür haben, wie Sie ein bestimmtes Bundle analysieren und warum es so nützlich sein kann, nicht verwendete oder nicht benötigte Pakete zu entfernen. Bevor Sie mit dieser Technik beginnen, eine Anwendung zu optimieren, sollten Sie wissen, dass dies bei größeren Anwendungen erheblich komplexer sein kann.

Wenn Sie ungenutzte Bibliotheken entfernen möchten, sollten Sie herausfinden, welche Teile eines Bundles verwendet werden und welche nicht. Wenn Sie ein mysteriöses Paket sehen, das anscheinend nirgends verwendet wird, gehen Sie einen Schritt zurück und prüfen Sie, welche Abhängigkeiten der obersten Ebene es möglicherweise benötigen. Versuchen Sie, sie voneinander zu entkoppeln.

Das Entfernen nicht benötigter Bibliotheken kann etwas komplizierter sein. Es ist wichtig, eng mit Ihrem Team zusammenzuarbeiten und zu prüfen, ob Teile der Codebasis vereinfacht werden können. Das Entfernen von moment in dieser Anwendung mag zwar immer die richtige Entscheidung sein, aber was ist, wenn Zeitzonen und unterschiedliche Sprachen berücksichtigt werden müssen? Was ist, wenn es noch kompliziertere Datumsmanipulationen gibt? Das Bearbeiten und Parsen von Datumsangaben kann sehr schwierig sein. Bibliotheken wie moment und date-fns vereinfachen dies erheblich.

Alles ist ein Kompromiss und es ist wichtig zu beurteilen, ob sich die Komplexität und der Aufwand für die Einführung einer benutzerdefinierten Lösung überhaupt lohnen, anstatt sich auf eine Bibliothek eines Drittanbieters zu verlassen.