Performance-Verbesserung durch komprimieren und minimieren von JS/CSS

Performance-Verbesserung durch komprimieren und minimieren von JS/CSS

CSS und JavaScript haben sich durchgesetzt, um moderne und ansprechende Internetseiten oder gar Webanwendungen zu entwickeln. Auch deren Umfang ist dadurch gestiegen: Oft wird auf Frameworks wie jQuery oder Bootstrap aufgebaut. Dazu kommen dann noch ein paar zusätzliche Plugins und je nach Umfang und Anspruch hat man schnell 10 einzelne CSS-Dateien und eben so viele JavaScript-Dateien beisammen. Zusammen mit anderen Elementen wie Grafiken oder Inhalten die per Ajax nachgeladen werden, verursachen moderne Webseiten insgesamt ohne Mühe 50 Anfragen und mehr.

Warum das ein Problem ist

Jede Datei, egal ob CSS oder JavaScript, erzeugt eine Anfrage an den Server. Das kostetet Zeit und verzögert die Ladedauer der Seite. Insbesondere bei JavaScript-Dateien wird das Laden der Seite gar angehalten, wenn dies im Header geschieht. Bereits bei der Entwicklung von Webanwendungen kann dies berücksichtigt und bereits abgeschwächt werden. Nützliche Tipps liefert dazu beispielsweise Google in seinen PageSpeed Insights.

Insbesondere bei komplexeren Webanwendungen hat man aber trotzdem mehrere Dateien, da man etwa verschiedene Frameworks/Erweiterungen einsetzt und dazu seinen Code strukturell trennen möchte. Und dies verschlechtert die Ladezeit, auch wenn man alle sonstigen Best Practice Lösungen umsetzt.

Die Lösung: Kombinieren

Einfache und logische Konsequenz: Man fügt einfach alle CSS- und JavaScript-Dateien zu jeweils einer zusammen, und zwar in der Reihenfolge wie man sie auch regulär als Einzeldatei eingebunden hätte.
Aus

<script type="text/javascript" src="js/lib/jquery.js"></script>
<script type="text/javascript" src="js/lib/jquery-ui.js"></script>
<script type="text/javascript" src="js/lib/bootstrap.js"></script>
<script type="text/javascript" src="js/myapp-lang-de.js"></script>
<script type="text/javascript" src="js/myapp-core.js"></script>
<script type="text/javascript" src="js/myapp-module.js"></script>

wird also beispielsweise

<script type="text/javascript" src="js/scripts.js"></script>

Die Datei scripts.js enthält also jQuery, jQuery UI, Bootstrap und so weiter.

Minimieren und Optimieren für noch mehr Performance

Sowohl CSS als auch JS-Dateien enthalten Darstellungszeichen wie Leerzeichen, Umbrüche und Tabs. Zu Entwicklungs- und Wartungszwecken sind diese genau wie Kommentare unerlässlich, auf die korrekte Funktion des Codes selbst haben sie aber keinerlei Einfluss.

/*
 * Dies ist eine gut formatierte und kommentierte CSS-Klasse, die dadurch deutlich mehr Traffic verursacht als nötig wäre
*/
.my-class{
  position: absolute;
  background: #fff;
  top: 100px;
  left: 20px;
  padding: 4px;
  margin-top: 1px;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
}

Wird seinen Zweck genau so erfüllen wir

.my-class{position:absolute;background:#fff;top:100px;left:20px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}

Es spricht daher nichts dagegen, diese Inhalte auf dem Produktivsystem zu entfernen. Im Gegenteil: Dadurch wird die zu übertragene Datenmenge kleiner, sodass Ladezeit und Serverlast verringert werden. Besonders mobile Nutzer dürften sich außerdem darüber freuen, weniger limitierten Traffic zu verbrauchen.

Im Falle von JavaScript kann der Code auch noch optimiert werden.
Aus

/**
 * jQuery-Plugins initialisieren, wenn der DOM geladen ist
 */
$(function() {
    // Datentabelle mit jQuery-Plugin initialisieren
    var statisticsDataTable = $('#statisticsDataTable').dataTable({
        // Der Nutzer soll nicht in der Lage sein, die Anzahl der Ergebnisse selbst zu bestimmen
        "bLengthChange": false,
        // Blendet ein Suchfeld ein, über das sämtliche Spalten durchsucht werden können
        "bFilter": true,
        // Ermöglicht es dem Nutzer, die Spalten anhand ihrer Titel auf- oder absteigend zu sortieren
        "bSort": true,
        // Seitenzahlen werden mit numerischen Zahlen (1,2,3, ...) angegeben
        'sPagingType': 'full_numbers'
    });
    // Datensätze der Tabelle absteigend nach der 2. Spalte (Index 1) sortieren
    statisticsDataTable.fnSort([[1, 'desc']]);
});

wird beispielsweise mit dem Google Closure Compiler folgendes:

$(function(){$("#statisticsDataTable").dataTable({bLengthChange:!1,bFilter:!0,bSort:!0,sPagingType:"full_numbers"}).fnSort([[1,"desc"]])});

Wie man sieht, werden nicht nur Formatierungszeichen und Kommentare entfernt, sondern es findet auch eine Verkürzung des Codes statt. Boolische Werte werden gekürzt und meine Variable statisticsDataTable fällt sogar ganz weg. Insgesamt wurde die zu übertragende Datenmenge des obigem Codes um über 70% reduziert. Wie effektiv die Komprimierung ist hängt natürlich immer vom jeweiligen Einzelfall ab, beispielsweise wie viel und ausführlich kommentiert wird.

Allerdings sollte man es nicht übertreiben: Bei komplexem Code kann es durch diese Methode in wenigen Fällen zu Problemen kommen. Besonders wenn zu viel optimiert wird, wie etwa beim Google Clonsure Compiler mit der Optimierungseinstellung Advanced. In diesem Tool reicht Simple völlig aus. Die paar KB welche durch Advanced zusätzlich gespart werden stehen meist in keinem Verhältnis zu dem möglicherweise kaputtoptimierten Code. Man kann es ausprobieren, aber ich würde davon eher abraten.

Die Umsetzung

Es gibt Online-Dienste, bei denen man CSS- und JS-Dateien hochladen oder den Code zur Optimierung direkt in ein Textfeld einfügen kann.

Gute Beispiele sind:
Google Closure Compiler (für JavaScript)
CSS Minifier

Für kleinere Seiten mit wenig Änderungen mag das eine praktikable Lösung sein. Aber wenn man wirklich jeweils 5 oder mehr CSS/JS Dateien hat wird es sehr nervig und zeitraubend, besonders wenn diese noch in einer Datei kombiniert werden sollen. Glücklicherweise gibt es Mittel und Wege, dies via Script zu automatisieren und mit einem Klick erledigen zu können. Dadurch ist es sogar möglich, diesen Schritt im Build-Prozess zu integrieren.

Alternative Lösungen

Wie so oft führen viele Wege zum Ziel. Im folgenden sollen die wichtigsten von Ihnen mit ihren Vor- und Nachteilen beschrieben werden.

#1: PHP-Scripte zum ausgeben verwenden
Beispielsweise gibt es PHP-Scripte, die mehrere CSS/JS Dateien optimieren und ausgeben, etwa

<script type="text/javascript" src="js.php?files=jquery,jqueryui,client"></script>

Besonders wenn man mehrere CSS/JS Dateien hat die nur unter bestimmten Bedingungen eingefügt werden sollen kann diese Lösung sogar etwas besser sein. Beispielsweise ein Editor der nur für angemeldete Nutzer gebraucht wird.

Grundsätzlich halte ich diese Variante nur dann für sinnvoll, wenn die Ausgabe vollständig gecached werden kann. Der Grund ist die Performance auf der Seite des Servers: Das Dateisystem wird belastet, je nach Dateianzahl sogar stark. Dazu kommt die PHP-Seitige Last, welche durch das Minimieren und Optimieren entsteht. Und dies geschieht ohne Caching bei jedem Seitenaufruf! Zumal dynamisch generierte Seiten immer langsamer sind als statische Dateien, sodass hier hinsichtlich der Ladezeit etwas Performance verschenkt wird, wenn wohl auch verschmerzbar.

#2: Statische Dateien mit Platzhaltern erstellen

Vor allem mit Template-Systemen bietet sich die Möglichkeit, einen Platzhalter für CSS- und JS-Dateien einzufügen. Hier könnte man sich eine Erweiterung basteln, die eine statische Datei mit dem optimierten Code beim ersten Aufruf erstellt. Beispielsweise durch einen Hash aller originalen Dateinamen die eingebunden werden sollen aneinandergereiht zur Prüfung. Der Vorteil ist, dass man das Änderungsdatum der Datei abfragen und somit anhand dessen einen Parameter einfügen kann, um Caching zu verhindern (etwa css.php?files=jquery,jqueryui,client&created=1424965674). Neben der Bindung des Template-Systems ist aber auch diese Variante nicht übermäßig performant. Es finden zwar weniger Zugriff aufs Dateisystem statt wie bei Verwendung eines PHP-Scriptes, aber dennoch unnötig viele.

#3: Automatische Erstellung beim bearbeiten

Die Nachteile der ersten beiden Lösungen, nämlich dass bei jedem Seitenaufruf relativ viel Last erzeugt wird, lassen sich kompensieren: Dafür müssen CSS- und JS-Dateien in einer Art Admin-Bereich via Editor im Browser bearbeitet werden. Man kann also seine Einzeldateien per Web-Editor bearbeiten, und nach dem Speichern werden diese automatisch optimiert und verkleinert. Die daraus resultierende Datei wird statisch im Dateisystem gespeichert. So erfolgt dieser Vorgang lediglich 1x, nämlich dann wenn es nötig ist. Für fertige CMS gibt es teilweise bereits vergleichbare Lösungen.

Gerade bei Eigenentwicklungen bereitet einem diese Variante jedoch einen deutlichen Mehraufwand. Zumal man die Dateien nicht mehr über das Dateisystem bearbeiten kann, was besonders im Zusammenhang mit Versionierungssystemen wie Git nervig wird. Zu beachten ist außerdem, dass diese Lösung mit steigender Anzahl an Daten, die nur unter bestimmten Bedingungen ausgeliefert werden sollen, recht kompliziert und damit spätestens in Summe eher unpraktikabel wird.

Fazit

Es gibt auch andere Möglichkeiten, allerdings mit entsprechenden Nachteilen und Einschränkungen. Zumindest hinsichtlich größerer Besucherzahlen überwiegen diese jedoch. In den meisten Fällen dürfte die beste Lösung darin bestehen, bei Änderungen die statisch erstellten optimierten Dateien neu zu erstellen. Oder noch besser diesen Vorgang direkt in den Buildprozess zu verlagern, sofern vorhanden.

3 thoughts on “Performance-Verbesserung durch komprimieren und minimieren von JS/CSS

  1. Devon

    Wie sieht es mit Googles PageSpeed aus? Ist das auch eine gute Möglichkeit? Oder eher weniger? 🙂

    1. DMW007

      Auf Pagespeed wird im 2. Absatz verwiesen 😉 Hat mit dem eigentlichen Kernthema hier aber nichts zutun, daher auch im Artikel nur zum Verständnis am Rande erwähnt. Denn PageSpeed führt keine Optimierungen durch sondern analysiert lediglich die verschiedenen Faktoren der Seiten-Performance.

      Das hier beschriebene komprimieren, kombinieren und minimieren ist nur eine Methode für einen flotteren Seitenaufbau. Außerdem wird nebenbei Traffic gespart, was insbesondere (mobile) Nutzer, aber auch Betreiber größerer Seiten wo das ins Gewicht fällt freut.

Leave a Reply