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 Webleistung leichter verbessern lässt. Hier erklären wir sie anhand der App „Oodles Theater“. Außerdem sprechen wir über unsere Tests mit dem vorausschauenden Laden und die neue Initiative „Guess.js“.

Ewa Gasperowicz

Im letzten Jahr haben wir uns intensiv damit beschäftigt, das Web schneller und leistungsfähiger zu machen. Das hat zu neuen Tools, Ansätzen und Bibliotheken geführt, die wir Ihnen in diesem Artikel vorstellen möchten. Im ersten Teil zeigen wir Ihnen einige Optimierungstechniken, die wir bei der Entwicklung der Oodles Theater App eingesetzt haben. Im zweiten Teil sprechen wir über unsere Tests mit dem vorausschauenden Laden und die neue Initiative Guess.js.

Die Notwendigkeit von Leistung

Das Internet wird jedes Jahr schwerer. Wenn wir uns den Status des Webs ansehen, sehen wir, dass eine durchschnittliche Seite auf Mobilgeräten etwa 1,5 MB wiegt, 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, Renderblockierungsmustern oder überflüssigem Drittanbietercode zum komplexen Leistungspuzzle bei.

Die meisten Nutzer bewerten die Geschwindigkeit ganz oben in der UX-Hierarchie ihrer Anforderungen. Das ist nicht weiter verwunderlich, da Sie nicht viel tun können, bis eine Seite vollständig geladen ist. Sie können keine Informationen von der Seite ableiten und auch nicht ihre Ästhetik bewundern.

UX-Hierarchiepyramide
Abbildung 1. Wie wichtig ist die Geschwindigkeit für Nutzer? (Speed Matters, Vol. 3)

Wir wissen, dass die Leistung für Nutzer wichtig ist. Es kann aber auch ein Rätsel sein, wo Sie mit der Optimierung beginnen sollen. Zum Glück gibt es Tools, die Ihnen dabei helfen können.

Lighthouse – eine Grundlage für den Leistungs-Workflow

Lighthouse ist ein Teil der Chrome-Entwicklertools, mit dem Sie Ihre Website prüfen und Hinweise dazu erhalten, wie Sie sie verbessern können.

Vor Kurzem haben wir eine Reihe von neuen Leistungsanalysen eingeführt, die im täglichen Entwicklungsablauf sehr nützlich sind.

Neue Lighthouse-Prüfungen
Abbildung 2. Neue Lighthouse-Prüfungen

Sehen wir uns an, wie Sie sie anhand eines praktischen Beispiels nutzen können: Die Oodles Theater App. Das ist eine kleine Demo-Web-App, in der Sie einige unserer beliebtesten interaktiven Google-Doodles ausprobieren und sogar ein oder zwei Spiele spielen können.

Bei der Entwicklung der App wollten wir dafür sorgen, dass sie möglichst leistungsstark ist. Ausgangspunkt für die Optimierung war ein Lighthouse-Bericht.

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

Die anfängliche Leistung unserer App, wie im Lighthouse-Bericht zu sehen, war ziemlich schlecht. In einem 3G-Netzwerk musste der Nutzer 15 Sekunden warten, bis die App interaktiv wurde. Lighthouse hat eine Menge Probleme mit unserer Website aufgezeigt und die Gesamtbewertung der Leistung von 23 spiegelt genau das wider.

Die Seite hatte ein Gewicht von etwa 3,4 MB.Wir mussten dringend etwas sparen.

Das war der Beginn unserer ersten Leistungsherausforderung: Dinge finden, die wir einfach entfernen können, ohne die Gesamtnutzung zu beeinträchtigen.

Leistungsoptimierung

Unnötige Ressourcen entfernen

Es gibt einige offensichtliche Dinge, die Sie entfernen können: Leerzeichen und Kommentare.

Vorteile der Minimierung
Abbildung 4 JavaScript und CSS minimieren und komprimieren

Lighthouse hebt diese Möglichkeit in der Prüfung unminierter CSS- und JavaScript-Dateien hervor. Wir haben webpack für unseren Build-Prozess verwendet. Für die Minimierung haben wir einfach das Uglify JS-Plug-in verwendet.

Die Minimierung ist eine gängige Aufgabe. Daher sollten Sie für jeden Buildprozess, den Sie verwenden, eine vorgefertigte Lösung finden können.

Eine weitere nützliche Prüfung in diesem Bereich ist Textkomprimierung aktivieren. Es gibt keinen Grund, nicht komprimierte Dateien zu senden. Die meisten CDNs unterstützen dies heutzutage standardmäßig.

Wir haben unseren Code mit Firebase Hosting gehostet. Firebase aktiviert standardmäßig das GZIP-Verfahren. Da wir unseren Code also auf einem vernünftigen CDN gehostet haben, haben wir diese Funktion kostenlos erhalten.

Gzip ist eine sehr beliebte Komprimierungsmethode, aber auch andere Mechanismen wie Zopfli und Brotli gewinnen an Bedeutung. Brotli wird von den meisten Browsern unterstützt und Sie können Ihre Assets mit einem Binärprogramm vorab komprimieren, bevor Sie sie an den Server senden.

Effiziente Cache-Richtlinien verwenden

Im nächsten Schritt wollten wir dafür sorgen, dass wir Ressourcen nicht unnötig doppelt senden.

Die Analyse Ineffiziente Cache-Richtlinie in Lighthouse hat uns gezeigt, dass wir unsere Caching-Strategien optimieren können, um genau das zu erreichen. Durch das Festlegen einer Max-Age-Header-Gültigkeitsdauer auf unserem Server haben wir dafür gesorgt, dass Nutzer bei einem wiederholten Besuch die zuvor heruntergeladenen Ressourcen wiederverwenden können.

Im Idealfall sollten Sie so viele Ressourcen wie möglich für so lange wie möglich im Cache speichern und Validierungstokens für eine effiziente Neuvalidierung der aktualisierten Ressourcen bereitstellen.

Nicht verwendeten Code entfernen

Bisher haben wir die offensichtlichen Teile des unnötigen Downloads entfernt. Was ist aber mit den weniger offensichtlichen Teilen? Beispielsweise nicht verwendeter Code.

Codeabdeckung in den Entwicklertools
Abbildung 5 Codeabdeckung prüfen

Manchmal enthalten unsere Apps Code, der nicht wirklich notwendig ist. Das passiert vor allem, wenn Sie längere Zeit an Ihrer App arbeiten, sich Ihr Team oder Ihre Abhängigkeiten ändern und manchmal eine Bibliothek ohne Elternelement übrig bleibt. Genau das ist uns passiert.

Zuerst haben wir die Material Components-Bibliothek verwendet, um schnell einen Prototyp unserer App zu erstellen. Im Laufe der Zeit sind wir zu einem individuelleren Erscheinungsbild übergegangen und haben diese Bibliothek völlig vergessen. Glücklicherweise konnten wir es mithilfe der Codeabdeckung in unserem Bundle wiederfinden.

Sie können die Statistiken zur Codeabdeckung in DevTools sowohl für die Laufzeit als auch für die Ladezeit Ihrer Anwendung prüfen. Im unteren Screenshot sehen Sie die beiden großen roten Streifen: Über 95 % unseres CSS und auch ein großer Teil des JavaScripts waren nicht verwendet.

Lighthouse hat dieses Problem auch bei der Prüfung auf nicht verwendete CSS-Regeln erkannt. Es wurde eine potenzielle Einsparung von über 400 KB angezeigt. Also sind wir zu unserem Code zurückgekehrt und haben sowohl den JavaScript- als auch den CSS-Teil dieser Bibliothek entfernt.

Wenn wir den MVC-Adapter entfernen, sinken unsere Stile auf 10 KB.
Abbildung 6: Wenn wir den MVC-Adapter entfernen, sinken unsere Stile auf 10 KB.

Dadurch wurde unser CSS-Bundle um das 20-fache verkleinert, was für ein kleines, zweizeiliges Commit ziemlich gut ist.

Dadurch konnte unser Leistungswert natürlich gesteigert werden und auch die Time to Interactive wurde deutlich verbessert.

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

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

Schaltflächen funktionieren nicht, weil die Bibliothek fehlt
Abbildung 7 Eine Komponente verwendete weiterhin die entfernte Bibliothek.

Wenn Sie also Code entfernen, sollten Sie einen geeigneten Testablauf haben, um sich vor potenziellen visuellen Rückschritten zu schützen.

Sehr große Netzwerknutzlasten vermeiden

Uns ist bewusst, dass große Ressourcen das Laden von Webseiten verlangsamen können. Sie können unsere Nutzer Geld kosten und sich stark auf ihr Datenvolumen auswirken. Daher ist es wirklich wichtig, dies zu berücksichtigen.

Mit der Prüfung Enorme Netzwerknutzlast konnte Lighthouse ein Problem mit einigen unserer Netzwerknutzlasten erkennen.

Erkennen von sehr großen Netzwerknutzlasten
Abbildung 8 Erkennen von sehr großen Netzwerknutzlasten

Hier haben wir festgestellt, dass über 3 MB Code gesendet wurden, was vor allem auf Mobilgeräten sehr viel ist.

Ganz oben in dieser Liste wies Lighthouse darauf hin, dass wir ein JavaScript-Anbieter-Bundle mit 2 MB unkomprimierten Code hatten. Auch Webpack weist darauf hin.

Wie das Sprichwort sagt: Die schnellste Anfrage ist die, die nicht gestellt wird.

Idealerweise sollten Sie den Wert jedes einzelnen Assets messen, das Sie Ihren Nutzern bereitstellen, die Leistung dieser Assets messen und entscheiden, ob es sich lohnt, sie mit der ursprünglichen Version zu veröffentlichen. Denn manchmal werden diese Assets verzögert oder verzögert geladen oder während der Inaktivität verarbeitet.

Da wir es mit vielen JavaScript-Bundles zu tun hatten, hatten wir Glück, denn die JavaScript-Community bietet eine Vielzahl von Tools zur Analyse von JavaScript-Bundles.

JavaScript-Bundle-Audit
Abbildung 9. JavaScript-Bundle-Audit

Wir haben mit dem Webpack-Bundle-Analyzer begonnen, der uns mitteilte, dass wir eine Abhängigkeit namens „unicode“ mit 1,6 MB geparsten JavaScripts einschließen, was ziemlich viel ist.

Anschließend haben wir den Editor geöffnet und mit dem Import Cost Plugin for Visual Code die Kosten jedes importierten Moduls visualisiert. So konnten wir herausfinden, welche Komponente Code enthielt, der auf dieses Modul verweist.

Wir sind dann zu einem anderen Tool gewechselt, BundlePhobia. Mit diesem Tool können Sie den Namen eines beliebigen NPM-Pakets eingeben und die geschätzte Größe der minimierten und komprimierten Datei sehen. Wir haben eine gute Alternative für das von uns verwendete Slug-Modul gefunden, das nur 2,2 KB groß war.

Das hatte große Auswirkungen auf unsere Leistung. Durch diese Änderung und die Entdeckung anderer Möglichkeiten, die Größe unseres JavaScript-Bundles zu reduzieren, konnten wir 2,1 MB Code einsparen.

Insgesamt konnten wir eine Verbesserung von 65% erzielen, wenn man die Größe der gezippten und minimierten Bundles berücksichtigt. Und wir haben festgestellt, dass sich dieser Prozess wirklich lohnt.

Vermeiden Sie daher im Allgemeinen unnötige Downloads auf Ihren Websites und in Ihren Apps. Wenn Sie ein Inventar Ihrer Assets erstellen und ihre Auswirkungen auf die Leistung messen, kann das einen großen Unterschied machen. Prüfen Sie Ihre Assets daher regelmäßig.

JavaScript-Startzeit mit Code-Splitting verkürzen

Große Netzwerknutzlasten können zwar einen großen Einfluss auf unsere App haben, aber es gibt noch etwas anderes, das einen wirklich großen Einfluss haben kann: JavaScript.

JavaScript ist Ihr teuerstes Asset. Wenn Sie auf Mobilgeräten große JavaScript-Bundles senden, kann es zu Verzögerungen bei der Interaktion der Nutzer mit den Komponenten Ihrer Benutzeroberfläche kommen. Das bedeutet, dass sie auf die Benutzeroberfläche tippen können, ohne dass etwas Sinnvolles passiert. Daher ist es wichtig, dass wir verstehen, warum JavaScript so viel kostet.

So verarbeitet ein Browser JavaScript.

JavaScript-Verarbeitung
Abbildung 10 JavaScript-Verarbeitung

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

Auf einem High-End-Gerät wie einem Desktop-Computer oder Laptop, vielleicht sogar einem High-End-Smartphone, dauern diese Phasen nicht sehr lange. Auf einem durchschnittlichen Smartphone kann dieser Vorgang jedoch fünf- bis zehnmal länger dauern. Das verzögert die Interaktivität. Wir sollten versuchen, das zu reduzieren.

Damit Sie diese Probleme mit Ihrer App leichter erkennen können, haben wir in Lighthouse eine neue Analyse der JavaScript-Startzeit eingeführt.

JavaScript-Startzeit
Abbildung 11. Prüfung der JavaScript-Startzeit

Im Fall der Oodle App wurde uns mitgeteilt, dass der JavaScript-Start 1,8 Sekunden gedauert hat. Wir importierten alle unsere Routen und Komponenten statisch in ein monolithisches JavaScript-Bundle.

Eine Möglichkeit, dies zu umgehen, ist das Code-Splitting.

Code-Splitting ist wie Pizza

Beim Code-Splitting wird der JavaScript-Code nicht auf einmal, sondern nach Bedarf in mehreren Teilen an die Nutzer gesendet.

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

Wir haben Code Splitting in unsere Anwendung eingebunden und von statischen zu dynamischen Importen gewechselt, sodass wir Code nach Bedarf asynchron lazy laden konnten.

Code-Splitting mit dynamischen Importen
Abbildung 13. Codesplitting mit dynamischen Importen

Dadurch konnten wir nicht nur die Größe unserer Bundles, sondern auch die JavaScript-Startzeit verkürzen. Die Ladezeit sank auf 0,78 Sekunden, was einer Beschleunigung um 56% entspricht.

Wenn Sie eine JavaScript-lastige Website erstellen, sollten Sie den Nutzern nur den Code senden, den sie benötigen.

Nutzen Sie Konzepte wie Code Splitting und sehen Sie sich Ideen wie Tree Shaking an. Im Repository webpack-libs-optimizations finden Sie einige Ideen dazu, wie Sie die Größe Ihrer Bibliothek reduzieren können, wenn Sie webpack verwenden.

Bilder optimieren

Witz zur Bildladeleistung

In der Oodle App verwenden wir viele Bilder. Leider war Lighthouse viel weniger begeistert als wir. Tatsächlich haben wir bei allen drei bildbezogenen Prüfungen nicht bestanden.

Wir hatten vergessen, unsere Bilder zu optimieren, sie hatten nicht die richtige Größe und wir hätten auch von anderen Bildformaten profitieren können.

Bildüberprüfungen
Abbildung 14. Lighthouse-Bildprüfungen

Wir haben damit begonnen, unsere Bilder zu optimieren.

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

Ein automatisierterer Ansatz besteht darin, Ihrem Build-Prozess mithilfe von Bibliotheken wie imagemin einen Schritt zur Bildoptimierung hinzuzufügen.

So sorgen Sie dafür, dass die in Zukunft hinzugefügten Bilder automatisch optimiert werden. Einige CDNs, z. B. Akamai, oder Lösungen von Drittanbietern wie Cloudinary, Fastly oder Uploadcare bieten umfassende Lösungen zur Bildoptimierung. Sie können Ihre Bilder also auch einfach bei diesen Diensten hosten.

Wenn Sie das aufgrund von Kosten oder Latenzproblemen nicht möchten, bieten Projekte wie Thumbor oder Imageflow selbst gehostete Alternativen.

Vorher und nachher
Abbildung 15. Vorher und nachher

Unser Hintergrund-PNG wurde in Webpack als zu groß gekennzeichnet und das zu Recht. Nachdem wir die Größe auf den Darstellungsbereich angepasst und es durch ImageOptim laufen lassen hatten, konnten wir es auf 100 KB reduzieren, was akzeptabel ist.

Durch die Wiederholung dieses Vorgangs für mehrere Bilder auf unserer Website konnten wir das Gesamtgewicht der Seite deutlich senken.

Das richtige Format für animierte Inhalte verwenden

GIFs können sehr teuer werden. Überraschenderweise war das GIF-Format ursprünglich gar nicht als Animationsplattform gedacht. Daher können Sie mit einem Wechsel zu einem geeigneteren Videoformat große Einsparungen bei der Dateigröße erzielen.

In der Oodle App haben wir ein GIF als Einführungssequenz auf der Startseite verwendet. Laut Lighthouse könnten wir über 7 MB sparen, wenn wir zu einem effizienteren Videoformat wechseln. Unser Clip wog etwa 7, 3 MB, was für eine vernünftige Website viel zu viel ist.Deshalb haben wir ihn in ein Videoelement mit zwei Quelldateien umgewandelt – eine MP4- und eine WebM-Datei für eine breitere Browserunterstützung.

Animierte GIFs durch Videos ersetzen
Abbildung 16. Animierte GIFs durch Video ersetzen

Wir haben das Tool FFmpeg verwendet, um unser animiertes GIF in eine MP4-Datei zu konvertieren. Das WebM-Format bietet noch größere Einsparungen. Die ImageOptim API kann diese Konvertierung für Sie durchführen.

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

Durch diese Umstellung konnten wir über 80% des Gesamtgewichts einsparen. So konnten wir die Größe auf etwa 1 MB reduzieren.

1 MB ist jedoch eine große Ressource, die über das Netzwerk gesendet werden muss, insbesondere für Nutzer mit eingeschränkter Bandbreite. Glücklicherweise konnten wir mithilfe der Effective Type API feststellen, dass die Bandbreite des Nutzers niedrig ist, und ihm stattdessen ein viel kleineres JPEG senden.

Bei dieser Schnittstelle werden die effektive Laufzeit und die Ausfallwerte verwendet, um den vom Nutzer verwendeten Netzwerktyp zu schätzen. Es gibt einfach einen String zurück: „slow 2G“, „2G“, „3G“ oder „4G“. Je nach diesem Wert können wir das Videoelement durch ein Bild ersetzen, wenn der Nutzer eine Verbindung unter 4G hat.

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

Das beeinträchtigt die Nutzerfreundlichkeit zwar ein wenig, aber zumindest ist die Website auch bei einer langsamen Verbindung nutzbar.

Nicht sichtbare Bilder per Lazy Loading laden

Bei Karussells, Slidern oder sehr langen Seiten werden oft Bilder geladen, die der Nutzer nicht sofort auf der Seite sehen kann.

Lighthouse meldet dieses Verhalten bei der Prüfung von Bildern außerhalb des Bildschirms. Sie können es sich auch im Netzwerkbereich der DevTools ansehen. Wenn viele Bilder ankommen, aber nur wenige auf der Seite zu sehen sind, sollten Sie stattdessen Lazy Loading in Betracht ziehen.

Lazy Loading wird im Browser noch nicht nativ unterstützt. Daher müssen wir JavaScript verwenden, um diese Funktion hinzuzufügen. Wir haben die Lazysizes-Bibliothek verwendet, um unseren Oodle-Covern ein 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 intelligent, weil es nicht nur die Sichtbarkeitsänderungen des Elements erfasst, sondern auch proaktiv Elemente im Voraus lädt, die sich in der Nähe des Darstellungsbereichs befinden, um die Nutzerfreundlichkeit zu optimieren. Außerdem bietet er eine optionale Einbindung der IntersectionObserver, mit der Sie sehr effiziente Sichtbarkeitsabfragen durchführen können.

Nach dieser Änderung werden unsere Bilder auf Anfrage abgerufen. Weitere Informationen zu diesem Thema finden Sie unter images.guide.

Browser dabei unterstützen, wichtige Ressourcen frühzeitig bereitzustellen

Nicht jedes Byte, das über die Leitung an den Browser gesendet wird, ist gleich wichtig. Der Browser weiß das. Viele Browser verwenden Heuristiken, um zu entscheiden, was zuerst abgerufen werden soll. Manchmal wird also CSS vor Bildern oder Scripts abgerufen.

Es wäre hilfreich, wenn wir als Autoren der Seite dem Browser mitteilen könnten, was für 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 auf der Webplattform eingeführt wurden, helfen dem Browser, die richtigen Daten zur richtigen Zeit abzurufen. Sie können etwas effizienter sein als einige der benutzerdefinierten, logikbasierten Lademethoden, die stattdessen mit Script ausgeführt werden.

Sehen wir uns an, wie Lighthouse uns dabei hilft, einige dieser Funktionen effektiv zu nutzen.

Als Erstes wird in Lighthouse empfohlen, mehrere kostenintensive Rücksprünge zu einem Ursprung zu vermeiden.

Vermeiden Sie mehrere teure Rundfahrten zu einem beliebigen Startpunkt.
Abbildung 17: Vermeiden Sie mehrere, kostenintensive Hin- und Rückfahrten zu einem beliebigen Startpunkt.

Bei der Oodle-App verwenden wir tatsächlich häufig Google Fonts. Wenn Sie ein Google Fonts-Stylesheet auf Ihre Seite einfügen, wird eine Verbindung zu bis zu zwei Subdomains hergestellt. Lighthouse zeigt uns, dass wir bei einer Aufwärmung der Verbindung bis zu 300 Millisekunden bei der Erstverbindungszeit einsparen könnten.

Mithilfe von „link rel preconnect“ können wir diese Verbindungslatenz effektiv verbergen.

Das kann besonders bei Google Fonts eine große Auswirkung haben, da unsere Schriftschnitt-CSS-Dateien auf googleapis.com und unsere Schriftressourcen auf Gstatic gehostet werden. Wir haben diese Optimierung angewendet und konnten so einige hundert Millisekunden einsparen.

Als Nächstes schlägt Lighthouse vor, wichtige Anfragen vorab zu laden.

Wichtige Anfragen vorab laden
Abbildung 18. Wichtige Anfragen vorab laden

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

Lighthouse teilt uns hier mit, dass wir unsere wichtigsten Webschriftarten-Ressourcen vorab laden sollten, da wir zwei Webschriften laden.

Das Vorladen einer Webschriftart sieht so aus: Sie geben rel=preload an, übergeben as mit der Schriftart und geben dann die Schriftart an, die Sie laden möchten, z. B. woff2.

Das kann sich stark auf Ihre Seite auswirken.

Auswirkungen des Vorabladens von Ressourcen
Abbildung 19. Auswirkungen des Vorabladens von Ressourcen

Wenn Webschriften für Ihre Seite wichtig sind und Sie link rel preload nicht verwenden, muss der Browser zuerst Ihre HTML-Datei abrufen, Ihr CSS parsen und erst viel später Ihre Webschriften abrufen.

Mit „link rel preload“ kann der Browser diese Webfonts viel früher abrufen, sobald er Ihren HTML-Code geparst hat. Bei unserer App konnten wir so die Zeit für das Rendern von Text mit unseren Web-Schriftarten um eine Sekunde verkürzen.

Das Vorladen von Schriftarten mit Google Fonts ist nicht ganz so einfach, da es eine kleine Einschränkung gibt.

Die Google Fonts-URLs, die wir in unseren Stylesheets für unsere Schriftschnitte angeben, werden vom Fonts-Team ziemlich regelmäßig aktualisiert. Diese URLs können ablaufen oder regelmäßig aktualisiert werden. Wenn Sie das Laden von Schriftarten vollständig steuern möchten, sollten Sie Ihre Webschriften selbst hosten. Das kann sehr nützlich sein, da Sie so beispielsweise auf „link rel preload“ zugreifen können.

In unserem Fall hat uns das Tool Google Web Fonts Helper dabei geholfen, einige dieser Webfonts offline zu stellen und lokal einzurichten. Probieren Sie es aus.

Unabhängig davon, ob Sie Webschriften als Teil Ihrer kritischen Ressourcen verwenden oder es sich um JavaScript handelt, sollten Sie dem Browser helfen, Ihre kritischen Ressourcen so schnell wie möglich bereitzustellen.

Experimentell: Hinweise zur Priorität

Wir haben heute etwas Besonderes für dich. Neben Funktionen wie Ressourcenhinweisen und Preloading arbeiten wir an einer brandneuen experimentellen Browserfunktion, die wir Prioritätshinweise nennen.

Priorität für die anfangs sichtbaren Inhalte festlegen
Abbildung 20 Hinweise zur Priorität

Mit dieser neuen Funktion können Sie dem Browser mitteilen, wie wichtig eine Ressource ist. Dazu wird das neue Attribut „importance“ (Wichtigkeit) mit den Werten „low“ (niedrig), „high“ (hoch) oder „auto“ (automatisch) verwendet.

So können wir die Priorität weniger wichtiger Ressourcen wie nicht kritischer Stile, Bilder oder Abruf-API-Aufrufe senken, um Konflikte zu reduzieren. Wir können auch die Priorität wichtigerer Elemente wie unserer Hero-Bilder erhöhen.

Im Fall unserer Oodle-App führte dies zu einer praktischen Stelle, an der wir Optimierungen vornehmen konnten.

Priorität für die anfangs sichtbaren Inhalte festlegen
Abbildung 21. Priorität für die anfangs sichtbaren Inhalte festlegen

Bevor wir unseren Bildern Lazy Loading hinzugefügt haben, hat der Browser ein Bildkarussell mit all unseren Doodels abgerufen. Dabei wurden alle Bilder am Anfang des Karussells mit hoher Priorität abgerufen. Leider waren die Bilder in der Mitte des Karussells für die Nutzer am wichtigsten. Wir haben die Wichtigkeit dieser Hintergrundbilder auf „sehr niedrig“ und die der Vordergrundbilder auf „sehr hoch“ gesetzt. Das hatte eine Auswirkung von zwei Sekunden bei langsamem 3G und darauf, wie schnell wir diese Bilder abrufen und rendern konnten. Alles in allem also eine positive Erfahrung.

Wir hoffen, diese Funktion in wenigen Wochen in Canary einführen zu können.

Ladestrategie für Webschriftarten

Die Typografie ist für ein gutes Design unerlässlich. Wenn Sie Web-Schriftarten verwenden, sollten Sie das Rendering Ihres Texts nicht blockieren und auf keinen Fall unsichtbaren Text anzeigen.

In Lighthouse wird dies jetzt mit der Prüfung Unsichtbaren Text vermeiden, während Webfonts geladen werden hervorgehoben.

Unsichtbaren Text vermeiden, während Webfonts geladen werden
Abbildung 22. Vermeiden Sie unsichtbaren Text beim Laden von Webfonts

Wenn Sie Ihre Webschriften mit einem Schriftschnittblock laden, entscheidet der Browser, was zu tun ist, wenn das Abrufen der Webschrift sehr lange dauert. Einige Browser warten bis zu drei Sekunden, bevor sie auf eine Systemschriftart umstellen. Sobald die Schriftart heruntergeladen wurde, wird sie wieder verwendet.

Wir versuchen, diesen unsichtbaren Text zu vermeiden. In diesem Fall hätten wir die klassischen Doodles dieser Woche nicht sehen können, wenn der Webfont zu lange gedauert hätte. Mit der neuen Funktion font-display haben Sie jedoch 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');
    }

Mit der Schriftanzeige können Sie festlegen, wie Webschriften gerendert oder als Fallback verwendet werden, je nachdem, wie lange das Austauschen dauert.

In diesem Fall verwenden wir die Schriftanzeige. Mit „Swap“ wird der Schriftschnitt eine Blockzeit von null Sekunden und eine unbegrenzte Swap-Zeit zugewiesen. Das bedeutet, dass der Browser Ihren Text ziemlich sofort mit einer Fallback-Schriftart anzeigt, wenn das Laden der Schriftart etwas dauert. Sobald die Schriftart verfügbar ist, wird sie ersetzt.

Im Fall unserer App war das großartig, da wir so schon früh aussagekräftigen Text anzeigen und zur Webschriftart wechseln konnten, sobald sie fertig war.

Ergebnis der Schriftart-Anzeige
Abbildung 23. Ergebnis der Schriftanzeige

Wenn Sie wie ein großer Teil des Webs Webschriften verwenden, sollten Sie im Allgemeinen eine gute Strategie zum Laden von Webschriften haben.

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

Scripts reduzieren, die das Rendern blockieren

Es gibt andere Teile unserer Anwendung, die wir früher in der Downloadkette einschleusen könnten, um Nutzern schon etwas früher zumindest eine grundlegende Nutzererfahrung zu bieten.

Auf dem Zeitleistenstreifen von Lighthouse sehen Sie, dass der Nutzer in den ersten Sekunden, in denen alle Ressourcen geladen werden, keine Inhalte sehen kann.

Vermeiden Sie Stylesheets, die das Rendering blockieren
Abbildung 24. Anzahl der stylesheets, die das Rendering blockieren, reduzieren

Das Herunterladen und Verarbeiten externer Stylesheets verhindert, dass der Rendering-Prozess fortgesetzt werden kann.

Wir können versuchen, unseren kritischen Renderingpfad zu optimieren, indem wir einige der Stile etwas früher senden.

Wenn wir die Stile, die für dieses erste Rendern verantwortlich sind, extrahieren und in unsere HTML-Datei einfügen, kann der Browser sie sofort rendern, ohne auf die externen Stylesheets zu warten.

In unserem Fall haben wir ein NPM-Modul namens Critical verwendet, um unsere kritischen Inhalte während eines Build-Schritts in index.html einzufügen.

Dieses Modul hat zwar den Großteil der Arbeit für uns erledigt, es war aber trotzdem etwas schwierig, die Funktion für verschiedene Routen reibungslos zu implementieren.

Wenn Sie nicht vorsichtig sind oder Ihre Website-Struktur sehr komplex ist, kann es sehr schwierig sein, dieses Muster einzuführen, wenn Sie die App-Shell-Architektur nicht von Anfang an geplant haben.

Deshalb ist es so wichtig, frühzeitig auf die Leistung zu achten. Wenn Sie nicht von Anfang an auf Leistung achten, besteht eine hohe Wahrscheinlichkeit, dass Sie später Probleme bekommen.

Letztendlich hat sich das Risiko gelohnt. Wir haben es geschafft, die App so zu optimieren, dass Inhalte viel früher ausgeliefert wurden. Dadurch konnte die Zeit bis zur ersten vollständigen Darstellung deutlich verkürzt werden.

Das Ergebnis

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

Die Lighthouse-Leistungsbewertung stieg von 23 auf 91. Das ist ein ziemlich guter Fortschritt in Bezug auf die Geschwindigkeit. Alle Änderungen wurden durch die kontinuierliche Prüfung und Umsetzung des Lighthouse-Berichts vorangetrieben. Wenn du wissen möchtest, wie wir alle Verbesserungen technisch implementiert haben, sieh dir unser Repository an, insbesondere die PRs, die dort gelandet sind.

Prognoseleistung – datengetriebene Nutzererfahrung

Wir sind der Ansicht, dass maschinelles Lernen in vielen Bereichen eine spannende Zukunftstechnologie darstellt. Wir hoffen, dass wir in Zukunft mehr Experimente anregen können, weil wir mithilfe echter Daten die Nutzerfreundlichkeit unserer Produkte verbessern können.

Heute treffen wir viele willkürliche Entscheidungen darüber, was Nutzer möglicherweise wünschen oder benötigen und was daher im Voraus abgerufen, vorab geladen oder vorab im Cache gespeichert werden sollte. Wenn wir richtig raten, können wir eine kleine Anzahl von Ressourcen priorisieren, aber es ist sehr schwierig, dies auf die gesamte Website auszuweiten.

Wir haben jetzt Daten, die unsere Optimierungen noch besser unterstützen. Mit der Google Analytics Reporting API können wir uns die nächste Top-Seite und die Abbruchprozentsätze für jede URL auf unserer Website ansehen und so Rückschlüsse darauf ziehen, welche Ressourcen wir priorisieren sollten.

Wenn wir dies mit einem guten Wahrscheinlichkeitsmodell kombinieren, vermeiden wir, dass die Daten unserer Nutzer durch aggressives Vorabladen von Inhalten verschwendet werden. Wir können diese Google Analytics-Daten nutzen und maschinelles Lernen und Modelle wie Markov-Ketten oder neuronale Netze verwenden, um solche Modelle zu implementieren.

Datengestütztes Bündeln für Web-Apps
Abbildung 25. Datengestütztes Bündeln für Webanwendungen

Um diese Tests zu erleichtern, haben wir eine neue Initiative namens Guess.js ins Leben gerufen.

Guess.js
Abbildung 26. Guess.js

Guess.js ist ein Projekt, das sich auf datengetriebene Nutzererfahrungen im Web konzentriert. Wir hoffen, dass Sie die Daten nutzen, um die Webleistung zu verbessern und darüber hinauszugehen. Das gesamte System ist Open Source und bereits auf GitHub verfügbar. Er wurde in Zusammenarbeit mit der Open-Source-Community von Minko Gechev, Kyle Matthews von Gatsby, Katie Hempenius und vielen anderen erstellt.

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

Zusammenfassung

Bewertungen und Messwerte sind hilfreich, um die Geschwindigkeit des Webs zu verbessern, aber sie sind nur Mittel, nicht die Ziele selbst.

Wir alle kennen das Problem langsamer Seitenladezeiten unterwegs. Jetzt haben wir die Möglichkeit, unseren Nutzern eine noch bessere Nutzererfahrung zu bieten, die wirklich schnell geladen wird.

Die Leistungssteigerung ist ein Prozess. Viele kleine Änderungen können zu großen Erfolgen führen. Wenn Sie die richtigen Optimierungstools verwenden und die Lighthouse-Berichte im Blick behalten, können Sie Ihren Nutzern eine bessere und inklusivere Nutzung bieten.

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