Kategorie:
Services
Autor: Hellmann eCommerce
Magento Shop

Steigerung der Performance eines Magento-Shops Teil 2

In seinem Beitrag zur Performance-Optimierung von Websites spricht Gilad Peleg nicht ohne Grund von der Evolution der Website-Entwicklung. Gemeint ist damit vor allem der Trend, dem Benutzer mit Hilfe von JavaScript und Co. eine immer einfachere und komfortablere Bedienung von Websites und Webservices zu ermöglichen.

Was im ersten Moment plausibel und folgerichtig klingt, entpuppt sich jedoch bei genauerer Betrachtung als Trugschluss. Denn diese vermeintlichen Verbesserungen für den Nutzer haben einen nicht zu unterschätzenden Nachteil: die Größe und die damit verbundenen Ladezeiten. Auch die allerbeste Server-Konfiguration (s. Teil 1 unserer Blogreihe zur Performance-Optimierung) nützt schließlich wenig, wenn die zu übertragenden Daten so groß sind, dass sie merklich den Aufbau der Seite beim Aufruf im Browser verzögern. Dieser Beitrag widmet sich daher dem Thema der Performance-Steigerung im Frontend und soll Tipps und Hinweise in Bezug auf das Vorgehen, die verschiedenen Faktoren sowie mögliche Fallstricke bei der Optimierung geben. Dabei werden wir letzten Endes feststellen, dass es doch nicht auf die Größe ankommt – zumindest nicht ausschließlich…

Am Anfang eines Web-Projektes steht die Idee. Im E-Commerce sind dies in der Regel Produkte bzw. Dienstleistungen, die über einen Online-Shop vertrieben werden sollen. Die Rahmenbedingungen sind hierbei klar definiert: Das Produkt muss stets im Vordergrund stehen und der Nutzer soll möglichst einfach und eindeutig zum Kauf animiert werden.

Eine übersichtliche Darstellung und gezielte Nutzerführung sind genauso unerlässlich wie der zielgruppenorientierte Aufbau des Projekts. Hierfür sind auch einfache Prozesse erforderlich. Und natürlich soll der Shop auf möglichst vielen Endgeräten gut betrachtet und bedient werden können. Schnell fällt bei der Planung dann auch das Buzzword „mobile-first“. Bekommen wir alles hin. Mit JavaScript gar kein Problem, da gibt es ja Frameworks und Plugins. Und den unverwechselbaren Look (natürlich „responsive“) erhalten wir dank Stylesheets und Webfonts.

Steht dann der erste Prototyp, der die Anforderungen an die Bedienbarkeit und Übersichtlichkeit erfüllt, kommt schnell die Ernüchterung. Alles funktioniert eigentlich wie gewünscht und auch die sogenannte Time To First Byte (TTFB), also die Zeit nach der sich der Server nach einer Nutzereingabe zurückmeldet, ist ordentlich. Trotzdem benötigen die Seiten eine gefühlte Ewigkeit für ihre Darstellung im Browser. Warum ist das so und was können wir dagegen tun?

 

1. Die Analyse

Zunächst gilt es die offensichtlichsten Performance-Bremsen aufzufinden, womit wir wieder beim Thema Größe wären. Neben der eigentlichen HTML-Seite mit den darzustellenden Inhalten (Bilder und Co.) sowie Haupt-Stylesheet, sind es hier vor allem die eingesetzten Plugins, die den zu ladenden Content schnell auf mehrere hundert KB anwachsen lassen. Häufig sind diese Dateien in ihrer ursprünglichen Form zudem schlecht komprimiert.

Ein weiteres Problem beim Einsatz vieler verschiedener Frameworks und Plugins ist die Anzahl der HTTP-Requests, die durch das Laden der dazu gehörigen JS- und CSS-Dateien entsteht. Aktuelle Browser erlauben maximal 2-8 parallele (HTTP-)Requests je Domain. Das heißt bei einer Vielzahl von Dateien, die vom selben Server geladen werden müssen, kommt es zu Verzögerungen des Ladevorgangs und daraus resultierend zu einer verspäteten Anzeige.

Außerdem ist die Positionierung der zu ladenden Ressourcen innerhalb der HTML-Seite für die Ladezeiten entscheidend. Werden externe JavaScript-Dateien beispielsweise innerhalb des <head>-Tags geladen, blockiert dies das Rendern der Seite im Browser (das so genannte „render blocking“), denn der Browser versucht zunächst alle dort befindlichen Scripts zu laden und auszuführen, bevor er die übrigen Inhalte der Seite nachlädt und darstellt.

Ein weiterer Faktor, der zum „render blocking“ führen kann, sind CSS-Dateien, die einerseits zu umfangreich und andererseits zu unstrukturiert sind. Aber auch und insbesondere extern geladene Schriftarten (Webfonts) verzögern häufig die erste Anzeige des Webseiteninhalts im Browser. Lediglich der Internet Explorer rendert den darzustellenden Text direkt mit einer System-Schriftart und „übermalt“ die Seite dann, wenn die entsprechende Schriftart geladen ist. Die übrigen gängigen Browser (Firefox und Webkit) warten hingegen mit der Darstellung, bis alle genutzten Schriftarten heruntergeladen sind.

Zu guter Letzt sollten auch das Markup der HTML-Seite an sich und die weiteren darzustellenden Inhalte wie Bilder/Grafiken in einem gesunden Maße optimiert sein. Für das Markup bedeutet dies einen semantisch korrekten und nicht zu komplexen/verschachtelten Aufbau. Auch hinsichtlich der Indexierbarkeit durch Suchmaschinen ist dies zu beachten. Bei Bildern ist in erster Linie die Wahl des idealen Formats entscheidend. Für Grafiken und Logos eignet sich etwa ein Format wie PNG bzw. GIF besser, wohingegen Fotos am besten als JPG-Datei mit ausreichender Kompressionsstufe angeboten werden sollten.

 

2. Ziele definieren

Nach der Analyse des Ist-Zustandes sollten Ziele definiert werden, die den groben Rahmen und Arbeitsumfang abstecken.

In einem Webshop steht natürlich der potentielle Kunde im Mittelpunkt des Interesses. Ihm soll durch kurze Ladezeiten, gepaart mit einer durchdachten Nutzerführung, ein positives Kauferlebnis bereitet werden. Denn bereits bei Reaktionszeiten des Shops von über einer Sekunde (nach Nutzereingabe) fühlt sich die Anwendung für den Besucher, in Bezug auf den angestoßenen Prozess, inkonsistent an. Die Gefahr eines Kaufabbruchs steigt dabei mit jeder weiteren Zehntelsekunde um ein Vielfaches. Ziel sollte es daher sein, die Reaktionszeit des Servers durch einen frühestmöglichen Start des Renderings der Seite zu reduzieren.

Zuerst sollte also festgelegt werden, welche Inhalte bzw. Elemente der Seite zuerst angezeigt werden sollen und daher höher priorisiert werden als andere. Ein wichtiger Bereich ist dabei sicherlich der „above-the-fold content“, also der Teil der Website, der auf den ersten Blick sichtbar ist, ohne dass  der Nutzer scrollen muss. Es ist also nicht zwingend erforderlich, dass sofort die gesamte Website perfekt dargestellt wird, sofern als Reaktion auf eine Nutzereingabe zumindest die wesentlichen Elemente schnell gerendert werden – möglichst unabhängig von der dem Nutzer zur Verfügung stehenden Bandbreite und Hardware.

Spätestens an diesem Punkt sind wir wieder beim mobile-first-Ansatz angelangt, der also wesentlich mehr verlangt, als ein für mobile Geräte optimiertes Design der Website. Im Fachjargon spricht man hier von der Optimierung des sogenannten „kritischen Rendering-Pfades“. Wie oben bereits angedeutet umfasst diese Optimierung im Wesentlichen folgende Punkte:

  • Minimierung der Anzahl an kritischen Ressourcen; also diejenigen, die das Rendern der Seite blockieren könnten
  • Minimierung der Anzahl an kritischen Bytes; also Umfang der Ressourcen minimieren, z.B. durch Komprimierung oder Weglassen unwichtiger Inhalte (im Markup o.ä.)
  • Minimierung der Länge des kritischen Pfads; also der Ressourcen, die voneinander abhängig sind (d.h. die erst heruntergeladen werden, nachdem eine vorherige Ressource vollständig verarbeitet wurde)

Mit dem Ziel die folgenden, von Google empfohlenen Richtwerte zu erreichen:

  • Das zum Start des Renderings erforderliche HTML-Markup sowie die zugehörigen CSS- und JavaScript-Anweisungen/Dateien sollten möglichst in die zuerst übertragenen ~14 KB passen (ausgenommen hiervon sind die darzustellenden Bilder)
  • Der SpeedIndex sollte <= 1000 sein. Das heißt die Zeit, in der der sichtbare Bereich, der „above-the-fold content“ gerendert ist, sollte möglichst 1 Sekunde (=1000ms) nicht überschreiten.

 

3. Schrittweise Optimierung

Um das Potenzial der Frontend-Optimierung zu veranschaulichen, haben wir als Beispiel eine Artikelübersichtsseite unseres Kunden Jeans Fritz als statische HTML-Seite extrahiert und werden diese im Verlauf dieses Kapitels Stück für Stück performance-technisch verbessern. Hierbei setzen wir sukzessive alle zur Verfügung stehenden Mittel ein, um die zuvor definierten Ziele (möglichst genau) zu erreichen.

Als Erstes bedienen wir uns einer vergleichsweise einfachen Methode: der GZIP-Komprimierung für textbasierte Ressourcen. Dazu muss auf Seiten des Servers lediglich ein entsprechendes Modul aktiviert werden. Dieses sorgt dann dafür, dass Textinhalte wie das Markup oder CSS- bzw. JavaScript-Dateien (Bytestreams) komprimiert an den Client übertragen und hier mit geringem Rechenaufwand dekomprimiert werden. Allein durch diese Maßnahme lassen sich bei den Bytestreams bis zu 70%-90% der Größe einsparen. Einzige Voraussetzung ist die Unterstützung durch den Browser, wobei diese jedoch bei allen modernen Browsern (jünger als 2001) gegeben ist.

Zudem wollen wir versuchen, die Größe der geladenen Ressourcen an sich zu minimieren und anschließend die Anzahl der HTTP-Requests zu reduzieren. Für Stylesheets hat sich hier seit geraumer Zeit der Einsatz von sogenannten „CSS Preprocessors“ bewährt. Diese Präprozessoren ermöglichen die Definition von Stylesheets in einer erweiterten CSS-Sprache (z.B. Less, Sass oder Stylus), d.h. sie erlauben etwa die Definition von Variablen, Mixins und Funktionen, die dann vor der Benutzung in reines CSS kompiliert werden - meist über ein Kommandozeilentool. Dadurch lässt sich der CSS-Code wesentlich besser strukturieren und zusammenfassen. Darüber hinaus erlauben die Compiler die Ausgabe des CSS-Codes in komprimierter Form oder als ausführlich kommentierten Code (mit sog. source map), der eine vereinfachte Entwicklung erlaubt.

Auf ähnliche Weise lassen sich auch mehrere separate JavaScript-Dateien zusammenfassen und komprimieren. Der Arbeitsaufwand erstreckt sich hier jedoch über mehrere Aufgabenschritte (Tasks): Zuerst müssen die Inhalte der Dateien aneinander gehängt werden (concat). Anschließend bietet es sich an, die zusammengefassten Dateien zu validieren (validate), um mögliche Syntaxfehler auszumerzen. Erst im letzten Schritt wird der erzeugte Code dann schließlich minimiert (minify).

Da für die einzelnen Schritte stets verschiedene Tools zum Einsatz kommen und sich diese Tasks während der Entwicklung ständig wiederholen, bietet sich der Einsatz eines „Task Runners“ an. Ein Task Runner erlaubt die Definition von Einzelaufgaben (Tasks) innerhalb des Entwicklungsprozesses, die dann beliebig miteinander kombiniert und sozusagen als Paket nacheinander ausgeführt werden können. Wie zuvor kurz angesprochen wären dies bei JavaScript-Dateien dann etwa die Tasks:

concat → validate → minify

Diese Task Runner lassen sich dann so konfigurieren, dass sie bei jeder Änderung einer JS-Datei innerhalb eines bestimmten Projektordners automatisch die definierten Tasks ausführen. Beliebte Task Runner sind aktuell Grunt und Gulp.js. Beide sind in JavaScript geschrieben und arbeiten Kommandozeilen-basiert. Ähnlich funktioniert dies auch bei Less/Sass/Stylus, wobei die Änderung einer zum Projekt gehörigen Datei hier lediglich das Kompilieren via Präprozessor anstößt.

Ein weiterer Weg um die Anzahl der HTTP-Requests zu senken ist die Verwendung von CSS-Sprites für Grafiken wie Symbole oder Icons, die als Gestaltungselemente auf der Website verwendet werden. Mittlerweile gibt es für die Generierung der Sprites Tools und Onlinedienste wie z.B. Sprite Cow, die zusätzlich zur Grafikdatei auch den nötigen CSS-Code liefern. Alternativ hierzu können die Grafiken, sofern sie einfarbig sind, auch mit Hilfe von Icon-Fonts dargestellt werden. Diese Technik erfreut sich seit einiger Zeit, vor allem im responsive Webdesign (wegen der einfachen Skalierbarkeit), einer immer größer werdenden Beliebtheit. Das Problem des render blockings aufgrund der nachzuladenden Icon-Schriftart (s.u.) sollte dabei jedoch nicht vernachlässigt werden.

Abbildung 1: Größe der zu ladenden Inhalte vor (blau) und nach (rot) den ersten Optimierungen. Wie deutlich zu erkennen ist, konnten so bereits mehr als 40% der Gesamtgröße aller zu ladenden Daten eingespart werden. Quelle: webpagetest.org

Abbildung 2: Auch die Anzahl der Requests ließ sich durch die ersten Maßnahmen verringern. Aufgrund der vielen Produktbilder, die ausschließlich separat geladen werden können, beträgt die Ersparnis hier jedoch lediglich gut 12%. Quelle: webpagetest.org

Die nächsten Optimierungsschritte gehen dann bereits ein gutes Stück weiter und widmen sich direkt dem kritischen Rendering-Pfad. Hierauf werden wir dann im dritten und letzten Teil unserer Artikelreihe „Steigerung der Performance eines Magento-Shops" eingehen.