In diesem Codelab verbessern Sie die Leistung der folgenden Anwendung, indem Sie alle nicht verwendeten und nicht benötigten Abhängigkeiten entfernen.
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, drücken Sie App ansehen und dann Vollbild .
Klicke einfach auf dein 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 Anwendung synchronisiert. 🐈
- 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.
- Laden Sie die App neu.
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 EingabeFilter
aktiviert ist.
- Sehen Sie sich die angezeigte Warnung an.
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 vereinfacht. 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? Einer der Gründe dafür ist, dass jede Abhängigkeit wiederum eigene Abhängigkeiten haben kann. Wenn also jede Tiefe/jeder Zweig des Abhängigkeitsbaums berücksichtigt wird, gibt es viel mehr als nur zwei. Wenn viele Abhängigkeiten enthalten sind, kann eine Anwendung relativ schnell groß werden.
Analysieren Sie den Bündelungsdienst, 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 plugins
-Array hinzu:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
Wenn die Anwendung neu geladen wird, sollte anstelle der App eine Visualisierung des gesamten Bundles angezeigt werden.
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. |
Gzip-komprimierte Größe | Größe des Pakets nach der Komprimierung mit gzip-Codierung. Dieses Thema wird in einer separaten Anleitung 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 Dienste von Firebase. 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 Warnung in den DevTools nicht mehr angezeigt. Im Bereich Netzwerk der DevTools ist außerdem eine erfreuliche Verringerung der Bundle-Größe zu sehen:
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 wirklich benötigen. In dieser Anwendung wurde nur firebase/database
zum Speichern und Synchronisieren aller Daten verwendet. Der firebase/app
-Import, 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?
Der Geburtstag jedes süßen Kätzchens wird im Unix (Millisekunden) in der Firebase-Datenbank 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.
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 Methode eine Anwendung optimieren, sollten Sie wissen, dass dies bei größeren Anwendungen deutlich 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.
Bei allem gibt es Vor- und Nachteile. 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 Drittanbieterbibliothek zu verlassen.