{"id":1066,"date":"2015-09-28T18:01:54","date_gmt":"2015-09-28T17:01:54","guid":{"rendered":"https:\/\/u-labs.de\/blog\/?p=1066"},"modified":"2015-09-28T18:30:26","modified_gmt":"2015-09-28T17:30:26","slug":"performance-verbesserung-durch-komprimieren-und-minimieren-von-jscss","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/performance-verbesserung-durch-komprimieren-und-minimieren-von-jscss\/","title":{"rendered":"Performance-Verbesserung durch komprimieren und minimieren von JS\/CSS"},"content":{"rendered":"<p>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\u00e4tzliche 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\u00fche 50 Anfragen und mehr.<\/p>\n<h4 style=\"font-weight: bold;\">Warum das ein Problem ist<\/h4>\n<p>Jede Datei, egal ob CSS oder JavaScript, erzeugt eine Anfrage an den Server. Das kostetet Zeit und verz\u00f6gert 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\u00fccksichtigt und bereits abgeschw\u00e4cht werden. N\u00fctzliche Tipps liefert dazu beispielsweise Google in seinen <a href=\"https:\/\/developers.google.com\/speed\/docs\/insights\/BlockingJS?hl=de\" target=\"_blank\" rel=\"nofollow\">PageSpeed Insights<\/a>.<\/p>\n<p>Insbesondere bei komplexeren Webanwendungen hat man aber trotzdem mehrere Dateien, da man etwa verschiedene Frameworks\/Erweiterungen einsetzt und dazu seinen Code strukturell trennen m\u00f6chte. Und dies verschlechtert die Ladezeit, auch wenn man alle sonstigen <i>Best Practice<\/i> L\u00f6sungen umsetzt.<\/p>\n<h4 style=\"font-weight: bold;\">Die L\u00f6sung: Kombinieren<\/h4>\n<p>Einfache und logische Konsequenz: Man f\u00fcgt einfach alle CSS- und JavaScript-Dateien zu jeweils einer zusammen, und zwar in der Reihenfolge wie man sie auch regul\u00e4r als Einzeldatei eingebunden h\u00e4tte.\nAus<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/lib\/jquery.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/lib\/jquery-ui.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/lib\/bootstrap.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/myapp-lang-de.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/myapp-core.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/myapp-module.js&quot;&gt;&lt;\/script&gt;\r\n<\/pre>\n<p>wird also beispielsweise<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js\/scripts.js&quot;&gt;&lt;\/script&gt;\r\n<\/pre>\n<p>Die Datei <b>scripts.js<\/b> enth\u00e4lt also jQuery, jQuery UI, Bootstrap und so weiter.<\/p>\n<h4 style=\"font-weight: bold;\">Minimieren und Optimieren f\u00fcr noch mehr Performance<\/h4>\n<p>Sowohl CSS als auch JS-Dateien enthalten Darstellungszeichen wie Leerzeichen, Umbr\u00fcche und Tabs. Zu Entwicklungs- und Wartungszwecken sind diese genau wie Kommentare unerl\u00e4sslich, auf die korrekte Funktion des Codes selbst haben sie aber keinerlei Einfluss.<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n\/*\r\n * Dies ist eine gut formatierte und kommentierte CSS-Klasse, die dadurch deutlich mehr Traffic verursacht als n\u00f6tig w\u00e4re\r\n*\/\r\n.my-class{\r\n  position: absolute;\r\n  background: #fff;\r\n  top: 100px;\r\n  left: 20px;\r\n  padding: 4px;\r\n  margin-top: 1px;\r\n  -webkit-border-radius: 4px;\r\n  -moz-border-radius: 4px;\r\n  border-radius: 4px;\r\n}\r\n<\/pre>\n<p>Wird seinen Zweck genau so erf\u00fcllen wir<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n.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}\r\n<\/pre>\n<p>Es spricht daher nichts dagegen, diese Inhalte auf dem Produktivsystem zu entfernen. Im Gegenteil: Dadurch wird die zu \u00fcbertragene Datenmenge kleiner, sodass Ladezeit und Serverlast verringert werden. Besonders mobile Nutzer d\u00fcrften sich au\u00dferdem dar\u00fcber freuen, weniger limitierten Traffic zu verbrauchen.<\/p>\n<p>Im Falle von JavaScript kann der Code auch noch optimiert werden.\nAus<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\/**\r\n * jQuery-Plugins initialisieren, wenn der DOM geladen ist\r\n *\/\r\n$(function() {\r\n    \/\/ Datentabelle mit jQuery-Plugin initialisieren\r\n    var statisticsDataTable = $('#statisticsDataTable').dataTable({\r\n        \/\/ Der Nutzer soll nicht in der Lage sein, die Anzahl der Ergebnisse selbst zu bestimmen\r\n        &quot;bLengthChange&quot;: false,\r\n        \/\/ Blendet ein Suchfeld ein, \u00fcber das s\u00e4mtliche Spalten durchsucht werden k\u00f6nnen\r\n        &quot;bFilter&quot;: true,\r\n        \/\/ Erm\u00f6glicht es dem Nutzer, die Spalten anhand ihrer Titel auf- oder absteigend zu sortieren\r\n        &quot;bSort&quot;: true,\r\n        \/\/ Seitenzahlen werden mit numerischen Zahlen (1,2,3, ...) angegeben\r\n        'sPagingType': 'full_numbers'\r\n    });\r\n    \/\/ Datens\u00e4tze der Tabelle absteigend nach der 2. Spalte (Index 1) sortieren\r\n    statisticsDataTable.fnSort(&#x5B;&#x5B;1, 'desc']]);\r\n});\r\n<\/pre>\n<p>wird beispielsweise mit dem <a href=\"http:\/\/closure-compiler.appspot.com\/home\" target=\"_blank\" rel=\"nofollow\">Google Closure Compiler<\/a> folgendes:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n$(function(){$(&quot;#statisticsDataTable&quot;).dataTable({bLengthChange:!1,bFilter:!0,bSort:!0,sPagingType:&quot;full_numbers&quot;}).fnSort(&#x5B;&#x5B;1,&quot;desc&quot;]])});\r\n<\/pre>\n<p>Wie man sieht, werden nicht nur Formatierungszeichen und Kommentare entfernt, sondern es findet auch eine Verk\u00fcrzung des Codes statt. Boolische Werte werden gek\u00fcrzt und meine Variable <i>statisticsDataTable<\/i> f\u00e4llt sogar ganz weg. Insgesamt wurde die zu \u00fcbertragende Datenmenge des obigem Codes um \u00fcber <b>70%<\/b> reduziert. Wie effektiv die Komprimierung ist h\u00e4ngt nat\u00fcrlich immer vom jeweiligen Einzelfall ab, beispielsweise wie viel und ausf\u00fchrlich kommentiert wird.<\/p>\n<p>Allerdings sollte man es nicht \u00fcbertreiben: Bei komplexem Code <b>kann<\/b> es durch diese Methode in wenigen F\u00e4llen zu Problemen kommen. Besonders wenn zu viel optimiert wird, wie etwa beim Google Clonsure Compiler mit der Optimierungseinstellung <i>Advanced<\/i>. In diesem Tool reicht <i>Simple<\/i> v\u00f6llig aus. Die paar KB welche durch Advanced zus\u00e4tzlich gespart werden stehen meist in keinem Verh\u00e4ltnis zu dem m\u00f6glicherweise <i>kaputtoptimierten<\/i> Code. Man kann es ausprobieren, aber ich w\u00fcrde davon eher abraten.<\/p>\n<h4 style=\"font-weight: bold;\">Die Umsetzung<\/h4>\n<p>Es gibt Online-Dienste, bei denen man CSS- und JS-Dateien hochladen oder den Code zur Optimierung direkt in ein Textfeld einf\u00fcgen kann.<\/p>\n<p>Gute Beispiele sind:\n<a href=\"http:\/\/closure-compiler.appspot.com\/home\" target=\"_blank\" rel=\"nofollow\">Google Closure Compiler (f\u00fcr JavaScript)<\/a>\n<a href=\"http:\/\/cssminifier.com\/\" target=\"_blank\" rel=\"nofollow\">CSS Minifier<\/a><\/p>\n<p>F\u00fcr kleinere Seiten mit wenig \u00c4nderungen mag das eine praktikable L\u00f6sung 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\u00fccklicherweise gibt es Mittel und Wege, dies via Script zu automatisieren und mit einem Klick erledigen zu k\u00f6nnen. Dadurch ist es sogar m\u00f6glich, diesen Schritt im Build-Prozess zu integrieren.<\/p>\n<h4 style=\"font-weight: bold;\">Alternative L\u00f6sungen<\/h4>\n<p>Wie so oft f\u00fchren viele Wege zum Ziel. Im folgenden sollen die wichtigsten von Ihnen mit ihren Vor- und Nachteilen beschrieben werden.<\/p>\n<p><b>#1: PHP-Scripte zum ausgeben verwenden<\/b>\nBeispielsweise gibt es PHP-Scripte, die mehrere CSS\/JS Dateien optimieren und ausgeben, etwa<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;script type=&quot;text\/javascript&quot; src=&quot;js.php?files=jquery,jqueryui,client&quot;&gt;&lt;\/script&gt;\r\n<\/pre>\n<p>Besonders wenn man mehrere CSS\/JS Dateien hat die nur unter bestimmten Bedingungen eingef\u00fcgt werden sollen kann diese L\u00f6sung sogar etwas besser sein. Beispielsweise ein Editor der nur f\u00fcr angemeldete Nutzer gebraucht wird.<\/p>\n<p>Grunds\u00e4tzlich halte ich diese Variante nur dann f\u00fcr sinnvoll, wenn die Ausgabe vollst\u00e4ndig 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 <b>jedem<\/b> Seitenaufruf! Zumal dynamisch generierte Seiten immer langsamer sind als statische Dateien, sodass hier hinsichtlich der Ladezeit etwas Performance verschenkt wird, wenn wohl auch verschmerzbar.<\/p>\n<p><b>#2: Statische Dateien mit Platzhaltern erstellen<\/b><\/p>\n<p>Vor allem mit Template-Systemen bietet sich die M\u00f6glichkeit, einen Platzhalter f\u00fcr CSS- und JS-Dateien einzuf\u00fcgen. Hier k\u00f6nnte 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\u00fcfung. Der Vorteil ist, dass man das \u00c4nderungsdatum der Datei abfragen und somit anhand dessen einen Parameter einf\u00fcgen kann, um Caching zu verhindern (etwa <b>css.php?files=jquery,jqueryui,client&amp;created=1424965674<\/b>). Neben der Bindung des Template-Systems ist aber auch diese Variante nicht \u00fcberm\u00e4\u00dfig performant. Es finden zwar weniger Zugriff aufs Dateisystem statt wie bei Verwendung eines PHP-Scriptes, aber dennoch unn\u00f6tig viele.<\/p>\n<p><b>#3: Automatische Erstellung beim bearbeiten<\/b><\/p>\n<p>Die Nachteile der ersten beiden L\u00f6sungen, n\u00e4mlich dass bei jedem Seitenaufruf relativ viel Last erzeugt wird, lassen sich kompensieren: Daf\u00fcr m\u00fcssen 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\u00e4mlich dann wenn es n\u00f6tig ist. F\u00fcr fertige CMS gibt es teilweise bereits vergleichbare L\u00f6sungen.<\/p>\n<p>Gerade bei Eigenentwicklungen bereitet einem diese Variante jedoch einen deutlichen Mehraufwand. Zumal man die Dateien nicht mehr \u00fcber das Dateisystem bearbeiten kann, was besonders im Zusammenhang mit Versionierungssystemen wie Git nervig wird. Zu beachten ist au\u00dferdem, dass diese L\u00f6sung mit steigender Anzahl an Daten, die nur unter bestimmten Bedingungen ausgeliefert werden sollen, recht kompliziert und damit sp\u00e4testens in Summe eher unpraktikabel wird.<\/p>\n<p><b>Fazit<\/b><\/p>\n<p>Es gibt auch andere M\u00f6glichkeiten, allerdings mit entsprechenden Nachteilen und Einschr\u00e4nkungen. Zumindest hinsichtlich gr\u00f6\u00dferer Besucherzahlen \u00fcberwiegen diese jedoch. In den meisten F\u00e4llen d\u00fcrfte die beste L\u00f6sung darin bestehen, bei \u00c4nderungen die statisch erstellten optimierten Dateien neu zu erstellen. Oder noch besser diesen Vorgang direkt in den Buildprozess zu verlagern, sofern vorhanden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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\u00e4tzliche Plugins und je nach Umfang und Anspruch hat man schnell 10 einzelne CSS-Dateien und eben so viele &#8230;<\/p>\n","protected":false},"author":5,"featured_media":2017,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61],"tags":[72,70,71],"class_list":["post-1066","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-softwareentwicklung","tag-clientscript","tag-performance","tag-seitenladezeit"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/1066","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=1066"}],"version-history":[{"count":77,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/1066\/revisions"}],"predecessor-version":[{"id":3140,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/1066\/revisions\/3140"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/2017"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=1066"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=1066"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=1066"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}