Webleistung leicht gemacht – Google I/O 2018

Bei der Google IO 2018 haben wir eine Reihe von Tools, Bibliotheken und Optimierungstechniken vorgestellt, mit denen sich die Leistung von Websites einfacher verbessern lässt. Hier erklären wir sie anhand der Oodles Theater App. Außerdem sprechen wir über unsere Experimente mit vorausschauenden Ladevorgängen und die neue Guess.js-Initiative.

Addy Osmani
Addy Osmani
Ewa Gasperowicz

Wir waren im letzten Jahr sehr beschäftigt, um herauszufinden, wie wir das Web schneller und leistungsfähiger machen können. Das hat zu neuen Tools, Ansätzen und Bibliotheken geführt, die wir Ihnen in diesem Artikel vorstellen möchten. Im ersten Teil stellen wir einige Optimierungstechniken vor, die wir bei der Entwicklung der App The Oodles Theater in der Praxis angewendet haben. Im zweiten Teil sprechen wir über unsere Experimente mit vorausschauendem Laden und die neue Initiative Guess.js.

Die Notwendigkeit von Leistung

Das Internet wird von Jahr zu Jahr immer härter und härter. Wenn wir den Status des Webs überprüfen, sehen wir, dass der Medianwert einer Seite auf Mobilgeräten bei etwa 1,5 MB liegt, wobei der Großteil aus JavaScript und Bildern besteht.

Die wachsende Größe der Websites trägt zusammen mit anderen Faktoren wie Netzwerklatenz, CPU-Einschränkungen, Blockierungsmustern für das Rendering oder überflüssigem Drittanbietercode zu diesem komplizierten Leistungspuzzle bei.

Die meisten Nutzenden stufen die Geschwindigkeit als oberste in der UX-Hierarchie ihrer Anforderungen ein. Das ist nicht allzu überraschend, da Sie erst wirklich viel tun können, wenn eine Seite fertig geladen ist. Sie können aus der Seite keinen Nutzen ziehen und nicht ihre Ästhetik bewundern.

UX-Hierarchie Piramid
Abb. 1: Wie wichtig ist Geschwindigkeit für Nutzende? (Speed Matters, Vol. 3)

Wir wissen, wie wichtig die Leistung für die Nutzer ist. Es kann sich aber auch wie ein Geheimnis anfühlen, wie man herausfinden muss, wo Optimierungsbedarf besteht. Zum Glück gibt es Tools, die Ihnen unterwegs helfen können.

Lighthouse – Basis für einen Performance-Workflow

Lighthouse ist Teil der Chrome-Entwicklertools, mit dem Sie Ihre Website prüfen und Verbesserungsvorschläge machen können.

Vor Kurzem haben wir eine Reihe neuer Leistungsprüfungen eingeführt, die im täglichen Entwicklungsworkflow sehr nützlich sind.

Neue Lighthouse-Prüfungen
Abb. 2: Neue Lighthouse-Prüfungen

Sehen wir uns an einem praktischen Beispiel an, wie Sie diese Tools nutzen können: Oodles Theater. Es ist eine kleine Demo-Web-App, in der Sie einige unserer bevorzugten interaktiven Google-Doodles ausprobieren und sogar ein oder zwei Spiele spielen können.

Bei der Entwicklung der App war uns wichtig, dass sie so leistungsstark wie möglich ist. Ausgangspunkt für die Optimierung war ein Lighthouse-Bericht.

Lighthouse-Bericht für die Oodles App
Abb. 3. Lighthouse-Bericht für die Oodles App

Die anfängliche Leistung unserer App im Lighthouse-Bericht war ziemlich schlecht. In einem 3G-Netzwerk musste der Nutzer 15 Sekunden warten, bis der erste aussagekräftige Paint erstellt wurde oder die App interaktiv wurde. Lighthouse hat uns eine Menge Probleme mit unserer Website aufgezeigt. Genau das spiegelt sich in der Leistungsbewertung von 23 wider.

Die Seite hatte eine Gewichtung von 3,4 MB – wir mussten also unbedingt etwas Fett reduzieren.

Damit begann unsere erste Herausforderung hinsichtlich der Leistung: Suche nach Elementen, die sich leicht entfernen lassen, ohne das Gesamterlebnis zu beeinträchtigen.

Möglichkeiten zur Leistungsoptimierung

Unnötige Ressourcen entfernen

Es gibt einige offensichtliche Dinge, die bedenkenlos entfernt werden können: Leerzeichen und Kommentare.

Vorteile durch Reduzierung
Abb. 4. JavaScript und CSS komprimieren und komprimieren

Lighthouse zeigt diese Optimierungsmöglichkeit in der Prüfung von nicht reduzierten CSS- und JavaScript-Dateien an. Für unseren Build-Prozess haben wir Webpack verwendet, also haben wir einfach das Uglify-JS-Plug-in verwendet, um eine Komprimierung zu erhalten.

Die Minimierung ist eine häufige Aufgabe. Daher sollten Sie für jeden Build-Prozess, den Sie verwenden, eine gebrauchsfertige Lösung finden können.

Eine weitere nützliche Prüfung in diesem Bereich ist die Textkomprimierung aktivieren. Es gibt keinen Grund, unkomprimierte Dateien zu senden, und die meisten CDNs unterstützen dies derzeit standardmäßig.

Wir haben Firebase Hosting verwendet, um unseren Code zu hosten, und in Firebase ist standardmäßig gzip aktiviert. Da wir unseren Code auf einem vernünftigen CDN hosten konnten, haben wir ihn kostenlos erhalten.

gzip ist zwar eine sehr beliebte Komprimierungsmethode, aber auch andere Mechanismen wie Zopfli und Brotli machen sich gut. Brotli wird von den meisten Browsern unterstützt und Sie können ein Binärprogramm verwenden, um Ihre Assets vorab zu komprimieren, bevor Sie sie an den Server senden.

Effiziente Cache-Richtlinien verwenden

Im nächsten Schritt haben wir dafür gesorgt, dass wir Ressourcen nicht zweimal senden, wenn sie unnötig sind.

Durch die Prüfung der Richtlinie für ineffiziente Cache-Richtlinien in Lighthouse konnten wir feststellen, dass wir unsere Caching-Strategien optimieren können, um genau das zu erreichen. Durch Festlegen eines „max-age“-Headers auf unserem Server haben wir dafür gesorgt, dass Nutzer bei wiederholten Besuchen die zuvor heruntergeladenen Ressourcen wiederverwenden können.

Idealerweise sollten Sie so viele Ressourcen wie möglich über einen möglichst langen Zeitraum sicher im Cache speichern und Validierungstokens für eine effiziente erneute Validierung der aktualisierten Ressourcen bereitstellen.

Nicht verwendeten Code entfernen

Bisher haben wir die offensichtlichen Teile des unnötigen Downloads entfernt. Aber was ist mit den weniger offensichtlichen Teilen? Zum Beispiel nicht verwendeter Code.

Codeabdeckung in den Entwicklertools
Abb. 5: Codeabdeckung prüfen

Manchmal fügen wir in unsere Apps Code ein, der nicht wirklich erforderlich ist. Dies passiert insbesondere, wenn Sie über einen längeren Zeitraum an Ihrer Anwendung arbeiten, sich Ihr Team oder Ihre Abhängigkeiten ändern und manchmal eine verwaiste Bibliothek zurückbleibt. Genau das ist uns passiert.

Anfangs haben wir die Material Components-Bibliothek verwendet, um schnell einen Prototyp für unsere App zu erstellen. Nach der Zeit sind wir zu einem benutzerdefinierten Design übergegangen und haben diese Bibliothek komplett vergessen. Glücklicherweise hat uns die Prüfung der Codeabdeckung geholfen, sie in unserem Bundle wiederzufinden.

Sie können Ihre Codeabdeckungsstatistiken in den Entwicklertools sowohl für die Laufzeit als auch für die Ladezeit Ihrer Anwendung überprüfen. Im Screenshot unten sind die beiden großen roten Streifen zu sehen – über 95 % unseres CSS-Codes wurden nicht verwendet und es gab auch eine Menge JavaScript.

Lighthouse hat dieses Problem auch in der Prüfung nicht verwendeter CSS-Regeln erkannt. Eine Einsparung von über 400 KB möglich. Also kehrten wir zu unserem Code zurück und haben den JavaScript- und CSS-Teil der Bibliothek entfernt.

Beim Entfernen des MVC-Adapters verringern sich die Stile auf 10 KB.
Abb. 6: Wenn wir den MVC-Adapter entfernen, sinken unsere Stile auf 10 KB!

Dadurch verkleinerte sich unser CSS-Bundle um das 20-Fache, was bei einem winzigen, zweizeiligen Commit ziemlich gut ist.

Natürlich hat sich dadurch unsere Leistungsbewertung erhöht und auch die Zeit bis Interaktivität ist viel besser geworden.

Bei solchen Änderungen reicht es jedoch nicht mehr aus, nur die Messwerte und Bewertungen zu überprüfen. Das Entfernen von Code ist nie risikolos. Achten Sie daher immer auf mögliche Regressionen.

Unser Code wurde in 95 % nicht verwendet – irgendwo gibt es immer noch diese 5 %. Offensichtlich wurden für eine unserer Komponenten noch immer die Stile aus der Bibliothek verwendet: die kleinen Pfeile im Doodle-Schieberegler. Da es aber so klein war, konnten wir diese Stile einfach manuell wieder in die Schaltflächen integrieren.

Schaltflächen sind durch fehlende Bibliothek defekt
Abb. 7: Eine Komponente hat die entfernte Bibliothek noch verwendet.

Achten Sie also beim Entfernen von Code darauf, dass Sie einen geeigneten Testworkflow eingerichtet haben, um potenzielle visuelle Regressionen zu vermeiden.

Sehr große Netzwerknutzlasten vermeiden

Wir wissen, dass große Ressourcen das Laden von Webseiten verlangsamen können. Sie können unsere Nutzer Geld kosten und einen großen Einfluss auf ihre Datentarife haben, daher ist es wirklich wichtig, das im Hinterkopf zu behalten.

Lighthouse konnte mithilfe der Prüfung Enorme Netzwerknutzlasten feststellen, dass ein Problem mit einigen unserer Netzwerknutzlasten aufgetreten ist.

Riesige Netzwerknutzlasten erkennen
Abb. 8. Riesige Netzwerknutzlasten erkennen

Wir haben gesehen, dass über 3 MB an Code vermerkt wurde, was ziemlich viel ist, insbesondere auf Mobilgeräten.

Ganz oben auf dieser Liste hat Lighthouse gezeigt, dass wir ein JavaScript-Anbieter-Bundle mit 2 MB unkomprimierten Code hatten. Auch dieses Problem wird in Webpack hervorgehoben.

Es heißt also: Die schnellste Anfrage ist die, die nicht gestellt wird.

Idealerweise sollten Sie den Wert jedes einzelnen Assets messen, das Sie Ihren Nutzern zur Verfügung stellen, die Leistung dieser Assets messen und überlegen, ob es sich lohnt, die Lieferung zu optimieren. Manchmal werden diese Assets verzögert, verzögert geladen oder bei Inaktivität verarbeitet.

Da wir mit vielen JavaScript-Bundles zu tun haben, hatten wir Glück, weil die JavaScript-Community über zahlreiche Audit-Tools für JavaScript-Bundles verfügt.

Prüfung von JavaScript-Bundles
Abb. 9: Prüfung von JavaScript-Bundles

Wir begannen mit dem Webpack Bundle Analyzer, das uns ergab, dass wir eine Abhängigkeit namens Unicode einbauten.Diese bestand aus 1,6 MB geparstem JavaScript, also ziemlich viele.

Dann gingen wir zum Editor über und konnten mit dem Import Cost Plugin for Visual Code die Kosten jedes importierten Moduls visualisieren. So konnten wir feststellen, welche Komponente Code enthält, der auf dieses Modul verweist.

Dann wechselten wir zu einem anderen Tool, BundlePhobia. Mit diesem Tool können Sie den Namen eines NPM-Pakets eingeben und die geschätzte Größe des komprimierten und mit gzip komprimierten Pakets sehen. Wir haben eine schöne Alternative für das Slug-Modul gefunden, das nur 2,2 KB wog, und haben das vertauscht.

Das hatte großen Einfluss auf unsere Leistung. Zwischen dieser Änderung und der Suche nach weiteren Möglichkeiten zur Reduzierung der Größe des JavaScript-Bundles haben wir 2, 1 MB Code eingespart.

Insgesamt konnten wir 65% Verbesserungen erzielen, nachdem diese Bundles mit gzip- und komprimierter Größe berücksichtigt wurden. Und wir stellten fest, dass sich dies als Prozess wirklich lohnen würde.

Versuchen Sie daher im Allgemeinen, unnötige Downloads auf Ihren Websites und in Ihren Apps zu vermeiden. Eine Bestandsaufnahme Ihrer Assets und die Messung ihrer Auswirkungen auf die Leistung können einen großen Unterschied machen. Daher sollten Sie Ihre Assets regelmäßig prüfen.

Geringere JavaScript-Startzeit durch Codeaufteilung

Obwohl große Netzwerknutzlasten große Auswirkungen auf unsere Anwendung haben können, gibt es noch etwas, das einen sehr großen Einfluss haben kann, und zwar JavaScript.

JavaScript ist das teigste Asset. Wenn Sie auf Mobilgeräten große JavaScript-Pakete senden, kann dies dazu führen, dass die Nutzer mit den Komponenten der Benutzeroberfläche schneller interagieren können. Sie können also auf die Benutzeroberfläche tippen, ohne dass etwas Wichtiges passiert. Es ist also wichtig für uns zu verstehen, warum JavaScript so teuer ist.

So wird JavaScript von einem Browser verarbeitet.

JavaScript-Verarbeitung
Abb. 10. JavaScript-Verarbeitung

Wir müssen zuerst das Skript herunterladen. Wir haben eine JavaScript-Engine, die diesen Code dann parsen, kompilieren und ausführen muss.

Diese Phasen benötigen auf einem High-End-Gerät wie einem Desktop-Computer, einem Laptop oder vielleicht sogar einem High-End-Smartphone nicht viel Zeit. Auf einem durchschnittlichen Mobiltelefon kann dieser Vorgang 5- bis 10-mal länger dauern. Das verzögert die Interaktivität, deshalb müssen wir versuchen, sie zu reduzieren.

Damit Sie diese Probleme mit Ihrer App besser erkennen können, haben wir eine neue Prüfung der JavaScript-Bootzeit in Lighthouse eingeführt.

JavaScript-Startzeit
Abb. 11. Prüfung der JavaScript-Bootzeit

Die Oodle-App teilte uns mit, dass wir 1,8 Sekunden Zeit für den JavaScript-Bootstart hatten. Alle unsere Routen und Komponenten wurden statisch in ein monolithisches JavaScript-Bundle importiert.

Eine Technik, um dieses Problem zu umgehen, ist die Codeaufteilung.

Code-Splitting ist wie Pizza

Bei der Code-Aufteilung handelt es sich um das Konzept, Ihren Nutzenden nicht die ganze Menge JavaScript zur Verfügung zu stellen. Was wäre, wenn Sie ihnen bei Bedarf nur ein Stück pro Stück geben würden?

Die Codeaufteilung kann auf Routen- oder Komponentenebene angewendet werden. Sie funktioniert hervorragend mit React, React Loadable, Vue.js, Angular, Polymer, Preact und mehreren anderen Bibliotheken.

Wir haben die Codeaufteilung in unsere Anwendung integriert und von statischen zu dynamischen Importen gewechselt, sodass wir Code nach Bedarf asynchron laden können.

Codeaufteilung mit dynamischen Importen
Abb. 13. Codeaufteilung mit dynamischen Importen

Dies hatte sowohl die Verkleinerung der Größe unserer Bundles als auch die Verringerung der JavaScript-Startzeit zur Folge. Er dauerte nur noch 0, 78 Sekunden und ist damit 56% schneller.

Wenn du eine Website mit vielen JavaScript-Funktionen erstellst, solltest du im Allgemeinen darauf achten, nur Code an die Nutzer zu senden, die sie benötigen.

Nutzen Sie Konzepte wie Codeaufteilung, erkunden Sie Ideen wie Baumschütteln und sehen Sie sich das webpack-libs-Optimizations-Repository an, um einige Ideen dazu zu erhalten, wie Sie die Größe Ihrer Bibliothek reduzieren können, wenn Sie Webpack verwenden.

Bilder optimieren

Witz zum Laden des Bildes beim Laden

In der Oodle-App verwenden wir viele Bilder. Leider war Lighthouse weniger begeistert als wir. Tatsächlich sind wir bei allen drei Audits zum Thema Bilder nicht bestanden.

Wir haben vergessen, die Bilder zu optimieren, sie passten nicht richtig an und wir konnten auch mit anderen Bildformaten einen gewissen Nutzen erzielen.

Image-Audits
Abb. 14. Lighthouse-Bildprüfungen

Wir begannen mit der Optimierung unserer Bilder.

Für einmalige Optimierungsrunden können Sie visuelle Tools wie ImageOptim oder XNConvert verwenden.

Ein eher automatisierter Ansatz besteht darin, dem Build-Prozess einen Schritt zur Bildoptimierung mit Bibliotheken wie imagemin hinzuzufügen.

So sorgen Sie dafür, dass die Bilder, die Sie zukünftig hinzufügen, automatisch optimiert werden. Einige CDNs wie Akamai oder Drittanbieterlösungen wie Cloudinary, Fastly oder Uploadcare bieten umfassende Lösungen zur Bildoptimierung, sodass Sie Ihre Bilder auch einfach über diese Dienste hosten können.

Wenn Sie dies aufgrund der Kosten- oder Latenzprobleme vermeiden möchten, bieten Projekte wie Thumbor oder Imageflow selbst gehostete Alternativen an.

Vor und nach der Optimierung
Abb. 15: Vor und nach der Optimierung

Unser PNG-Hintergrundbild wurde im Webpack zu Recht als groß gekennzeichnet. Nachdem wir die Größe an den Darstellungsbereich angepasst und über ImageOptim ausgeführt hatten, sind wir auf 100 KB gesunken, was akzeptabel ist.

Dadurch konnten wir die Gewichtung der gesamten Seite deutlich reduzieren.

Das richtige Format für animierte Inhalte verwenden

GIFs können richtig teuer werden. Überraschenderweise war das GIF-Format nie als Animationsplattform gedacht. Durch den Wechsel zu einem besser geeigneten Videoformat lassen sich daher große Einsparungen bei der Dateigröße erzielen.

In der Oodle-App haben wir ein GIF als Einleitungssequenz auf der Startseite verwendet. Laut Lighthouse könnten wir durch den Wechsel zu einem effizienteren Videoformat mehr als 7 MB einsparen. Unser Clip wiete etwa 7, 3 MB, viel zu viel für eine vernünftige Website.Also haben wir ihn in ein Videoelement mit zwei Quelldateien verwandelt: eine MP4-Datei und WebM für eine umfassendere Browserunterstützung.

Animierte GIFs durch Videos ersetzen
Abb. 16. Animierte GIFs durch Videos ersetzen

Wir haben das FFmpeg verwendet, um unser animiertes GIF in eine MP4-Datei zu konvertieren. Mit dem WebM-Format können Sie noch größere Einsparungen erzielen, denn die ImageOptim API kann solche Konvertierungen für Sie vornehmen.

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

Durch diese Umwandlung konnten wir über 80% unserer Gesamtgewichtung einsparen. Damit waren wir auf etwa 1 MB reduziert.

Dennoch ist 1 MB eine große Ressource, um den Draht nach unten zu verschieben, insbesondere für einen Nutzer mit eingeschränkter Bandbreite. Glücklicherweise können wir mit der Effective Type API feststellen, dass sie eine langsame Bandbreite haben, und ihnen stattdessen eine viel kleinere JPEG-Datei zur Verfügung stellen.

Diese Schnittstelle verwendet die effektive Umlaufzeit und die Abwärtswerte, um den vom Nutzer verwendeten Netzwerktyp zu schätzen. Sie gibt einfach einen String zurück: langsames 2G, 2G, 3G oder 4G. Abhängig von diesem Wert könnten wir also das Videoelement durch das Bild ersetzen, wenn der Nutzer sich unter 4G befindet.

if (navigator.connection.effectiveType) { ... }

Dabei wird die Website ein wenig beeinträchtigt, aber zumindest lässt sich die Website bei einer langsamen Verbindung nutzen.

Lazy Loading von Bildern außerhalb des Bildschirms

Auf Karussells, Schiebereglern oder sehr langen Seiten werden oft Bilder geladen, auch wenn der Nutzer sie nicht sofort auf der Seite sehen kann.

Lighthouse meldet dieses Verhalten bei der Prüfung von nicht sichtbaren Bildern. Sie können es sich auch im Netzwerkbereich der Entwicklertools selbst ansehen. Wenn viele Bilder eingehen, aber nur ein paar davon auf der Seite zu sehen sind, empfiehlt es sich möglicherweise, sie stattdessen mit Lazy Loading zu laden.

Lazy Loading wird nativ im Browser noch nicht unterstützt. Daher müssen wir JavaScript verwenden, um diese Funktion hinzuzufügen. Wir haben die Lazysizes-Bibliothek verwendet, um unseren Oodle-Covern das Lazy Loading-Verhalten hinzuzufügen.

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

Lazysizes ist eine smarte Funktion, da nicht nur Änderungen der Sichtbarkeit eines Elements erfasst werden, sondern auch Elemente, die sich in der Nähe der Ansicht befinden, proaktiv vorab abgerufen werden, um eine optimale Nutzererfahrung zu ermöglichen. Außerdem ist eine optionale Integration von IntersectionObserver verfügbar, die eine sehr effiziente Sichtbarkeitssuche ermöglicht.

Nach dieser Änderung werden unsere Bilder bei Bedarf abgerufen. Weitere Informationen zu diesem Thema finden Sie unter images.guide. Es ist eine sehr praktische und umfassende Ressource.

Helfen Sie dem Browser, wichtige Ressourcen frühzeitig bereitzustellen

Nicht jedes Byte, das an den Browser gesendet wird, hat dieselbe Bedeutung, und der Browser weiß dies. Viele Browser verwenden eine Heuristik, um zu entscheiden, was sie zuerst abrufen sollten. Manchmal wird CSS vor Bildern oder Skripts abgerufen.

Es kann hilfreich sein, dass wir als Autoren der Seite dem Browser mitteilen, was uns wirklich wichtig ist. Glücklicherweise haben Browseranbieter in den letzten Jahren eine Reihe von Funktionen hinzugefügt, die uns dabei helfen, z.B. Ressourcenhinweise wie link rel=preconnect, preload oder prefetch.

Diese Funktionen, die der Webplattform zur Verfügung gestellt wurden, helfen dem Browser, das richtige Element zur richtigen Zeit abzurufen. Sie sind möglicherweise etwas effizienter als einige der benutzerdefinierten, logikbasierten Ansätze, die stattdessen mithilfe von Skripts ausgeführt werden.

Sehen wir uns an, wie uns Lighthouse bei der effektiven Nutzung einiger dieser Funktionen hilft.

Lighthouse sagt uns als Erstes, mehrfache Hin- und Rückflug zu einem beliebigen Startort zu vermeiden.

Mehrfache, kostspielige Hin- und Rückflug zu einem beliebigen Startort vermeiden
Abb. 17. Mehrfache, kostspielige Hin- und Rückflüge zu einem beliebigen Startort vermeiden

Im Fall der Oodle-App nutzen wir tatsächlich sehr häufig Google Fonts. Jedes Mal, wenn Sie ein Google Font-Stylesheet auf Ihrer Seite einfügen, wird es mit bis zu zwei Subdomains verbunden. Lighthouse sagt uns, dass wir, wenn wir diese Verbindung aufwärmen könnten, bei der anfänglichen Verbindungszeit bis zu 300 Millisekunden einsparen könnten.

Durch die Nutzung der Vorverbindung "link rel" können wir diese Verbindungslatenz effektiv maskieren.

Besonders bei Google Fonts, bei der unser CSS-Code für Schriftart auf googleapis.com gehostet wird und unsere Schriftartenressourcen auf Gstatic gehostet werden, kann dies eine enorme Wirkung haben. Also haben wir diese Optimierung angewendet und einige Hundert Millisekunden reduziert.

Der nächste Vorschlag von Lighthouse ist, dass wir Schlüsselanfragen vorab laden.

Schlüsselanfragen vorab laden
Abb. 18. Schlüsselanfragen vorab laden

<link rel=preload> ist sehr leistungsstark. Es informiert den Browser darüber, dass eine Ressource im Rahmen der aktuellen Navigation benötigt wird, und versucht, dass der Browser sie so schnell wie möglich abruft.

Lighthouse teilt uns jetzt mit, dass wir unsere wichtigsten Ressourcen für Webschriftarten vorab laden sollten, da wir in zwei Webschriftarten laden.

So sieht das Vorabladen einer Webschriftart aus: Sie geben rel=preload an, übergeben as mit dem Schrifttyp und geben dann den Schrifttyp an, in dem geladen werden soll, z. B. WOFF2.

Das kann erhebliche Auswirkungen auf Ihre Seite haben.

Auswirkungen des Vorabladens von Ressourcen
Abb. 19. Auswirkungen des Vorabladens von Ressourcen

Wenn Webschriftarten für deine Seite eigentlich wichtig sind, muss der Browser normalerweise, ohne das Link-rel-Vorabladevorgang zu verwenden, zuerst den HTML-Code abrufen, den CSS-Code parsen und erst viel später die Webschriftarten abrufen.

Sobald der Browser den HTML-Code geparst hat, kann er diese Webschriftarten viel früher mithilfe von Link-rel-Vorabladevorgängen abrufen. So konnten wir bei unserer App die Zeit für das Rendern von Text mit unseren Webschriftarten um eine Sekunde verkürzen.

Es ist nicht ganz so einfach, Schriftarten mit Google Fonts vorab zu laden.

Die Google-Schriftart-URLs, die wir für die Schriftarten in unseren Stylesheets angeben, wurden vom Fonts-Team regelmäßig aktualisiert. Diese URLs können ablaufen oder regelmäßig aktualisiert werden. Wenn Sie also die volle Kontrolle über das Laden von Schriftarten haben möchten, empfehlen wir Ihnen, Ihre Webschriftarten selbst zu hosten. So könnt ihr z. B. Vorabladevorgänge von Links nutzen.

Das Tool Google Web Fonts Helper hat uns dabei geholfen, einige dieser Webschriftarten offline und lokal einzurichten. Probieren Sie es also am besten gleich aus.

Unabhängig davon, ob Sie Webschriftarten als Teil Ihrer kritischen Ressourcen oder JavaScript verwenden, versuchen Sie, den Browser dabei zu unterstützen, Ihre kritischen Ressourcen so schnell wie möglich bereitzustellen.

Experimentell: Prioritätshinweise

Heute haben wir etwas Besonderes für Sie. Neben Funktionen wie Ressourcenhinweisen und Vorabladevorgängen haben wir an einer brandneuen experimentellen Browserfunktion gearbeitet, die wir Prioritätshinweise nennen.

Priorität für die anfänglich sichtbaren Inhalte festlegen
Abb. 20. Prioritätshinweise

Dies ist eine neue Funktion, mit der Sie dem Browser einen Hinweis darauf geben können, wie wichtig eine Ressource ist. Sie stellt ein neues Attribut namens "Wichtigkeit" mit den Werten "niedrig", "hoch" oder "auto" zur Verfügung.

Auf diese Weise können wir die Verringerung der Priorität weniger wichtiger Ressourcen wie nicht kritischen Stile, Bilder oder Abrufe von API-Aufrufen vermitteln, um Konflikte zu reduzieren. Wir können auch wichtigere Dinge wie Hero-Images priorisieren.

Im Fall unserer Oodle-App führte dies zu einer praktischen Optimierungsmöglichkeit.

Priorität für die anfänglich sichtbaren Inhalte festlegen
Abb. 21. Priorität für die anfänglich sichtbaren Inhalte festlegen

Bevor wir unseren Bildern Lazy Loading hinzugefügt haben, hatten wir dieses Bilderkarussell mit all unseren Zeichnungen. Der Browser forderte bereits am Anfang des Karussells alle Bilder mit hoher Priorität an. Leider waren es die Bilder in der Mitte des Karussells, die den Nutzenden am wichtigsten waren. Wir haben die Wichtigkeit dieser Hintergrundbilder auf sehr gering und die Vordergrundbilder auf sehr hoch eingestellt. Dies hatte eine zweisekündige Auswirkung auf langsamen 3G-Verbindungen und darauf, wie schnell wir diese Bilder abrufen und rendern konnten. Es hat uns also ein schönes und positives Erlebnis gebracht.

Wir hoffen, diese Funktion in einigen Wochen auf Canary verfügbar zu machen.

Eine Strategie für das Laden von Schriftarten haben

Typografie ist eine Grundvoraussetzung für ein gutes Design. Wenn Sie Webschriftarten verwenden, sollten Sie idealerweise nicht das Rendern Ihres Textes blockieren und auf keinen Fall unsichtbaren Text anzeigen.

Wir heben dieses Problem jetzt in Lighthouse hervor und nutzen die Prüfung, um unsichtbaren Text beim Laden von Webschriftarten zu vermeiden.

Unsichtbaren Text beim Laden von Web-Schriftarten vermeiden
Abb. 22. Unsichtbaren Text beim Laden von Web-Schriftarten vermeiden

Wenn Sie Ihre Webschriftarten mithilfe eines Schriftartblocks laden, überlassen Sie dem Browser die Entscheidung, was zu tun ist, wenn das Abrufen der Webschriftart lange dauert. Einige Browser warten bis zu drei Sekunden darauf, bevor sie zu einer Systemschrift wechseln. Nach dem Download wird diese dann wieder in die Schriftart geändert.

Wir versuchen, diesen unsichtbaren Text zu vermeiden. In diesem Fall hätten wir die klassischen Doodles der Woche nicht sehen können, wenn die Webschriftart zu lange gedauert hätte. Glücklicherweise haben Sie mit der neuen Funktion font-display viel mehr Kontrolle über diesen Prozess.

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

Über die Schriftanzeige können Sie entscheiden, wie Webschriftarten gerendert oder als Fallback verwendet werden, je nachdem, wie lange es dauert, bis sie ausgetauscht werden.

In diesem Fall verwenden wir "font display swap". Mit „Swap“ erhält die Schriftart einen Blockperiode von null Sekunden und einen unendlichen Auslagerungszeitraum. Wenn das Laden der Schriftart etwas länger dauert, zeichnet der Browser den Text ziemlich sofort mit einer Fallback-Schriftart. Sobald die Schriftart verfügbar ist, wird sie ausgetauscht.

Der Vorteil unserer App ist, dass wir damit schon sehr früh einen aussagekräftigen Text einblenden und dann zur Webschriftart wechseln konnten.

Ergebnis der Schriftanzeige
Abb. 23. Ergebnis der Schriftanzeige

Wenn Sie Webschriftarten verwenden – ein großer Prozentsatz aller Nutzer im Web –, sollten Sie eine gute Strategie für das Laden von Schriftarten haben.

Es gibt viele Funktionen der Webplattform, mit denen Sie das Laden von Schriftarten optimieren können. Sehen Sie sich aber auch das Repository von Zach Leatherman an, denn es ist wirklich großartig.

Anzahl der Scripts reduzieren, die das Rendering blockieren

Es gibt andere Teile unserer Anwendung, die wir früher in der Download-Kette platzieren könnten, um zumindest etwas grundlegendes Nutzererlebnis etwas früher zu ermöglichen.

Auf der Lighthouse-Zeitachse ist zu sehen, dass der Nutzer in den ersten Sekunden, in denen alle Ressourcen geladen sind, keine Inhalte sehen kann.

Möglichkeiten reduzieren, die das Rendering von Stylesheets blockieren
Abb. 24. Reduzierung von Stylesheets, die das Rendering blockieren

Das Herunterladen und Verarbeiten externer Stylesheets verhindert, dass der Renderingprozess voranschreitet.

Wir können versuchen, unseren kritischen Rendering-Pfad zu optimieren, indem wir einige der Stile etwas früher bereitstellen.

Wenn wir die Stile, die für dieses erste Rendering verantwortlich sind, extrahieren und in unseren HTML-Code einbetten, kann der Browser sie sofort rendern, ohne auf das Eintreffen der externen Stylesheets warten zu müssen.

In unserem Fall haben wir ein NPM-Modul namens Critical verwendet, um unseren kritischen Inhalt während eines Build-Schritts in die Datei index.html einzubetten.

Dieses Modul erledigte den Großteil der Arbeit für uns, aber es war immer noch etwas schwierig, alles reibungslos über verschiedene Routen hinweg zu ermöglichen.

Wenn Sie nicht vorsichtig sind oder Ihre Websitestruktur sehr komplex ist, kann es sehr schwierig sein, ein solches Muster einzuführen, wenn Sie die Anwendungsshell-Architektur nicht von Anfang an geplant haben.

Deshalb ist es so wichtig, die Leistung frühzeitig zu berücksichtigen. Wenn Sie Ihr Design nicht von Anfang an auf Leistung konzipieren, ist die Wahrscheinlichkeit hoch, dass später Probleme auftreten.

Am Ende hat sich unser Risiko ausgezahlt. Wir haben es geschafft und die App liefert viel früher Inhalte, wodurch unsere erste bedeutungsvolle Farbzeit erheblich verkürzt werden konnte.

Das Ergebnis

Das war eine lange Liste von Leistungsoptimierungen, die wir an unserer Website vorgenommen haben. Sehen wir uns das Ergebnis an. So wurde unsere App vor und nach der Optimierung auf einem mittelgroßen Mobilgerät in einem 3G-Netzwerk geladen.

Die Lighthouse-Leistungsbewertung stieg von 23 auf 91. Das ist ein ziemlicher Fortschritt in Bezug auf die Geschwindigkeit. Für alle Änderungen haben wir den Lighthouse-Bericht kontinuierlich überprüft und berücksichtigt. Wenn du wissen möchtest, wie wir alle Verbesserungen technisch umgesetzt haben, kannst du dir unser Repository ansehen, insbesondere die PRs, die dort gelandet sind.

Prognoseleistung – datengesteuerte User Experiences

Wir sind davon überzeugt, dass maschinelles Lernen in vielen Bereichen eine spannende Zukunftsmöglichkeit bietet. Wir hoffen, dass dies in Zukunft zu mehr Experimenten anregen wird: Echte Daten können die Nutzererfahrung beeinflussen.

Heutzutage treffen wir viele willkürliche Entscheidungen darüber, was der Nutzer wollen oder braucht und was es daher wert ist, vorab abgerufen, vorab geladen oder im Cache gespeichert zu werden. Wenn wir richtig raten, können wir eine kleine Menge an Ressourcen priorisieren, aber es ist wirklich schwierig, sie auf die gesamte Website zu skalieren.

Tatsächlich liegen uns Daten vor, die uns heute bei unseren Optimierungen helfen. Mit der Google Analytics Reporting API können wir uns für jede URL auf unserer Website die nächsten oberen Seiten- und Ausstiegsprozentsätze ansehen und so Schlussfolgerungen dafür ziehen, welche Ressourcen priorisiert werden sollten.

Wenn wir dies mit einem guten Wahrscheinlichkeitsmodell kombinieren, vermeiden wir die Verschwendung der Daten unserer Nutzer durch einen aggressiven Vorabruf von Inhalten. Wir können diese Google Analytics-Daten nutzen sowie maschinelles Lernen und Modelle wie Markov-Ketten oder neuronale Netzwerke verwenden, um diese Modelle zu implementieren.

Datengesteuerte Bündelung für Webanwendungen
Abb. 25. Datengestützte Bündelung für Webanwendungen

Daher freuen wir uns, Ihnen eine neue Initiative mit dem Namen Guess.js vorstellen zu können.

Guess.js
Abb. 26. Guess.js

Guess.js ist ein Projekt, das sich auf datengesteuerte Nutzererfahrungen im Web konzentriert. Wir hoffen, dass dies dazu anregt, die Nutzung von Daten zur Verbesserung der Webleistung zu untersuchen und darüber hinaus zu gehen. Alles ist als Open Source verfügbar und jetzt auf GitHub verfügbar. Es wurde in Zusammenarbeit mit der Open-Source-Community von Minko Gechev, Kyle Matthews von Gatsby, Katie Hempenius und einer Reihe anderer Personen erstellt.

Probieren Sie Guess.js aus und teilen Sie uns Ihre Meinung mit.

Zusammenfassung

Werte und Messwerte sind hilfreich bei der Verbesserung der Geschwindigkeit des Internets, sie sind jedoch nur Mittel und nicht die Ziele selbst.

Wir alle haben schon mal erfahren, dass Seiten unterwegs langsam geladen werden. Jetzt haben wir die Möglichkeit, unseren Nutzern ein angenehmeres Erlebnis zu bieten, das sehr schnell geladen wird.

Die Leistung zu verbessern ist ein Weg. Viele kleine Änderungen können zu großen Gewinnen führen. Wenn Sie die richtigen Optimierungstools verwenden und die Lighthouse-Berichte im Auge behalten, können Sie Nutzern eine bessere und inklusivere Nutzererfahrung bieten.

Mit besonderem Dank gilt: Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse und Google Doodles.