Der „CSS-JS-Booster“: Eine PHP-Bibliothek zur Ladezeitenbeschleunigung

Achtung: dieser Beitrag ist alt! Es kann gut sein, dass seine Inhalte nicht mehr aktuell sind.

Ein Gastbeitrag von Christian „Schepp“ Schaefer

Dieser Artikel dreht sich um ein immer populärer werdendes Thema, nämlich um die Frage, wie man die Ladezeiten von Webseiten reduzieren kann. In diesem Kontext schauen wir uns mit Fokus auf das Frontend zunächst an, welche Verursacher es geben kann, die unsere Seite langsam werden lassen, und welche Techniken es gibt, um gegen sie anzuarbeiten. Im unteren Drittel stelle ich Euch dann eine PHP-Bibliothek namens „CSS-JS-Booster“ vor, die Ihr ganz einfach in Euer PHP-Projekt einbinden könnt, und die Euch die wichtigsten Optimierungsschritte abnimmt (vor allem rund um CSS und JS). Und wir reden kurz über ein auf die Bibliothek aufsetzendes Wordpress-Plugin.

Die Ladezeit ist ein Erfolgsfaktor

Seit Samstag ist es offiziell: Auch die Ladezeit einer Seite wird künftig zu einem von rund 200 Faktoren zur Bestimmung des Rankings innerhalb der Google-Suchergebnisse. So verkündeten es Amit Singhal und Matt Cutts im Webmaster Central Blog.

Wer Googles Aktivitäten in den letzten Monaten etwas detaillierter verfolgt, für den fällt das nicht aus so ganz heiterem Himmel. Der googlesche Geschwindigkeitswahn nahm Ende 2008 mit dem Release der ersten Chrome Beta, der einige neue Tricks kannte, Fahrt auf. Weiter ging es Mitte 2009 mit dem Firebug-Plugin Google Page Speed, dann der Speed Tracer und Ende 2009 mit dem Google Public DNS, der DNS-Resolving mit einigen Tricks deutlich schneller bewerkstelligt, und ebenfalls seit Ende 2009 gibt es in den Google Webmaster Tools in der Sektion „Labs“ einen Bereich der über die Ladegeschwindkeit der eigenen Seite - auch im Vergleich zum Rest der Welt - informiert.

Google Webmster Tools Labs

Eine schnelle Seite ist angenehm zu bedienen

Warum all das? Nun, Google möchte einfach ein so gutes und schnell ansprechendes Web haben, dass es den Einsatz von Offline-Applikationen überflüssig macht. Das stärkt die Position von Android und von Googles zukünftigem Desktop-OS Chrome OS.

Aber es macht natürlich ganz allgemein mehr Böcke auf einer Seite herumzusurfen, die schnell lädt und die auf Eingaben zügig reagiert. Es handelt sich also um einen handfesten Usability-Aspekt. Und es bestimmt auch maßgeblich die Konversionsrate mit, so man denn bestimmte messbare Ziele mit seiner Seite verfolgt.

Auswirkungen längerer Ladenzeiten auf das Besucherverhalten

Google ist nicht der erste größere Webtechnologie-Konzern, der sich in diesem Sektor engagiert: Schon 2007 gründete man bei Yahoo! ein Team, das sich nur mit Performance-Fragen beschäftigte: das „Yahoo! Exceptional Performance Team“ unter der Leitung des „Chief Performance Yahoo!“ namens Steve Souders (BTW: Coole Jobbezeichnungen, oder?).

Und ebenjener Steve Souders, der heute übrigens für Google tätig ist, schrieb damals ein relativ dünnes Buch namens „High Performance Websites“, über das ich im Folgenden in einer Buchhandlung stolperte. Das Ding ist zwar mäßig gut übersetzt, aber nichtsdestotrotz Gold wert (und mittlerweile flankiert von seinem anderen Buch „Even faster Websites“).

Was macht unsere Seiten schnell?

In „High Performance Websites“ beginnt Souders mit der Feststellung, dass wir mehr gefühlte Performance für weniger Arbeit erhalten, wenn wir uns auf die Optimierung unseres Frontends konzentrieren, als wenn wir am Backend herumschraubten. Im Anschluss benennt er 14 „goldene“ Regeln, die im Bereich der Frontend-Entwicklung entscheidend für die Ladezeiten einer Website sind, und sortiert sie nach Priorität. Je weiter oben eine Regel steht, umso wirkungsvoller ist sie:

  1. Anzahl HTTP-Requests (= Datei-Requests) minimieren
  2. Ein Content Delivery Network verwenden
  3. Dateien mit längeren Verfallsdaten ausstatten
  4. Daten komprimiert verschicken
  5. Stylesheets in den Quelltext-Kopfbereich
  6. JavaScripts in den Quelltext-Fußbereich
  7. Keine Internet Explorer Expressions in Stylesheets verwenden
  8. Stylesheets und JavaScripts nicht einbetten, sondern in Dateien auslagern
  9. Maßvoll viele DNS-Anfragen erzeugen
  10. JavaScript minifizieren (CSS aber auch)
  11. Umleitungen vermeiden
  12. Doppelungen/Redundanzen bei den JavaScripts vermeiden
  13. Auf dem Webserver die ETag-Header abschalten
  14. AJAX-Anfragen cachen

Zusammen mit dem Buch hat Yahoo! damals die Firebug-Erweiterung YSlow! released, die eine Webseite auf das Erfülltsein der Punkte dieser Liste hin untersucht. Am Ende gibt es soundsoviel von 100 Punkten und eine Performance-Klassifizierung von A (für top!) bis F (für schnarchlahm).

Ausschnitt aus der YSlow Bewertung

Die Einstellung mit den 14 Regeln heißt „Classic V1“. Später kamen weitere 8 Regeln hinzu (Setting: „YSlow(V2)“), die größtenteils auf die Darstellungsperformance innerhalb der Renderengine während der Benutzung abzielen. Da kommen aber nicht ganz so Gravierende hinzu weswegen ich weiter über das „Classic“-Set reden werde.

In der obigen Liste gibt es Punkte, die eher für Enterprise-Seiten wichtig sind, als für Ottonormal-Seiten, weswegen YSlow! neben „YSlow(V2)“ auch einen milderen Bewertungspreset namens „Small Site or Blog“ für uns vorhält, der diese Punkte ausklammert. Mit der Zusammenstellung gehe ich aber nicht 100pro konform (die Sache mit dem Verfallsdatum fehlt da zum Beispiel!).

Einige der Regeln habe ich in fett hervorgehoben, weil sie die für uns Webworker interessantesten Regeln sind. Die schauen wir uns im Folgenden nochmal genauer an.

Anzahl HTTP-Requests (= Datei-Requests) minimieren

Im Gegensatz zu früher, als es noch kein breitbandiges Internet gab, bestimmt das Gewicht einer Seite (also die Bytes) die Ladedauer immer weniger. Mit steigendem Durchsatz merkt man den Transfer von sagen wir mal 1 Megabyte kaum: bei DSL 6000 dauert der etwa 1,7 Sekunden. Bei VDSL-25 sind es nur noch 0,4 Sekunden. Das Problem heute ist die Latenz, also die Zeit, die, egal wie dick eine Leitung ist, immer verstreicht bis der Datentransfer endlich losgeht. Und diese Latenz setzt sich aus 3 Teilaspekten zusammen:

  • Falls es sich um einen unbekannten Host handelt: DNS-Anfrage
  • Reisezeit der „Haben wollen“-Anfrage an den Server
  • Reisezeit der „Da hast Du“-Rückantwort an den Browser

Erst danach kommt die Nutzlast. Je mehr Dateien wir also anfragen, desto mehr Latenzzeit läppert sich zusammen. Und je weiter der Server von uns weg steht, desto länger werden die Reisezeiten unserer Datenpakete.

Browser sind aber auch nicht blöd, nicht einmal der IE, weswegen sie hingehen und mehrere Anfragen parallel abfeuern. Obwohl HTTP 1.1 eigentlich nur zwei parallele Anfragen erlaubt, ignorieren moderne Browser diese Vorgabe und kommen auf 4 bis 6 parallelen Anfragen pro Host. Dadurch parallelisieren sich auch die Latenzen: sie liegen weniger zahlreich in Reihe und potenzieren sich somit weniger.

Leider hilft auch das nicht ganz aus der Bredouille, denn heutige Webseitenkonstrukte sind dermaßen angereichert mit Grafiken, JavaScript und anderen Komponenten, dass dieser Trick doch nur ein Tropfen auf einen recht heißen Stein darstellt. Beispiel: Allein dieses recht unkomplizierte Blog hier, benötigt 47 verschiedene Komponenten, um eine Seite vollständig anzuzeigen.

Ladeverhalten des Firefox über 47 Dateien hinweg

Die Devise lautet also: runter mit der Zahl der HTTP-Requests!

Wie machen wir das? Naja, je nachdem um was für Typen von Dateien es sich handelt, fügen wir sie entweder alle zu einer großen Datei zusammen: Bei JavaScript reicht wirklich das Hintereinanderhängen aller Scripte in der korrekten Reihenfolge. Bei Stylesheets sollten wir alle @import-Rules auflösen und wir sollten auch mehrere Stylesheets für verschiedene Ausgabemedien (Screen, Print, Mobile) per @media-Rule in eine einzige Datei integrieren. Im Falle von Bildern, aus denen Designelemente erzeugt werden können wir diese per Sprites, zusammenfügen, oder noch besser: per Data URI direkt als Nutzdaten in das CSS einbetten. In allen Fällen reduzieren wir im Idealfall die Anzahl benötigter Dateien auf eine Datei pro Datei-Typ (1 × CSS, 1 × JS, 1 × Bildsprite). Nehmen wir Data URIs brauchen wir sogar nicht mal mehr eine Bild-Datei.

Im Gegensatz zu den klassischen Sprites erlauben Data URIs das Vermengen von verschiedenen Bildformaten (z.B. JPG, 8-Bit- und 24-Bit-PNG) in einer Trägerdatei, sie erfordern weit weniger Gehirnakrobatik bei der Anwendung, und sie müssen bei Grafikänderungen nicht reihum neuorganisiert werden. Sie sind also praktischer. Aber vom Datenvolumen rund 30% größer als die Originale. Aber dafür gibt es auch Abhilfe, nämlich GZIP (siehe unten), und wie oben erwähnt ist das Datenvolumen nicht mehr unser Hauptproblem. So sehen Data URIs aus:

Vorher:

background: url(../design/quoted.gif) no-repeat left top;

Nachher:

background: url(data:image/gif;base64,R0lGODlhEgAPANU/AGhSKtW7ZbOLOvbbXnplM
v7jabaXOZd7L+e/XUk6Hcu0bfTbZbWJRpB1LvXcgsSlUtSzQ4RpObueTCkiFMKWPeLDcjMsGd3G
V9qkUbunTty0WsOlPgcGAxcTDMaZO+TLXyMeDsqaSl5MKFRFJfLRetShTPvhhMWeN9/GY82dQcK
kSuK3Xue8YJdyQOzEXo9yL4RyOqyBR62SSq+SOM6tQSAbEdjBc8WYQODHY9CvV+jPWu/WXcioP8
uiOMqsSwAAACH5BAEAAD8ALAAAAAASAA8AAAavwJ9wSCwWJ4eLZDLkiAyfCFPYofQGropFKPJAC
ixb7ddhpAwZDSnAmYQ8aI0J9ktgbhZOrYJLtEoCIBwADio/IhgCHEIKKCIxJS9CEw4+dRgUCRMW
FSgWEYAJFgQOEj8cZic6CGscHW80CysmBFQCJzsIAVs/IxQQsgpjVAcDOR1NExsFEchNLwMPi03
LI0UcDdHTQhzLItfZ0kTdBd/jxeJNPOXXBBcy26czH9ZCQQA7) no-repeat left top;

Beim Umwandeln der Dateien in Data-URI helfen uns Online-Tools wie das von Dopiaza.org oder aber wir basteln uns das mit PHP selbst:

echo 'background-image: url(data:image/gif;base64,'.base64_encode(file_get_contents('beispiel.gif')).');';

Dummerweise vertragen die älteren IEs (sprich: IE < 8) Data-URIs nicht (IE 8 übrigens auch nur bis 24KB Größe pro Einzeldatei). Wir brauchen da also eine Sonderbehandlung im Stylesheet. Was die alten IEs an Standards nicht unterstützen, das machen sie an proprietären Techniken wieder wett, und so gibt es stattdessen MHTML für die älteren IEs. Dabei werden die Bilddaten nur aus dem Trägermedium heraus referenziert auf eine .mhtml-Datei.

Dummerweise fällt auch hier ein IE raus: der IE7 unter Vista. Unter Vista scheint ein neues Sicherheitsmodell zu verhindern dass MHTML wie zuvor funktioniert. Der Effekt ist der dass Bilder beim ersten Laden da sind, beim zweiten Aufruf sind sie aber weg! Hier ist das clientseitige Caching wohl kaputtgegangen. Aber auch dafür gibt einen Weg, und zwar muss man erzwingen, dass eine Anfrage wirklich immer an den Server rausgeht, dass der Browser das MHTML also niemals in Eigenregie cached. Der Server kann dann gerne ein kurzes „Alles wie gehabt, nimm was'de hast“ antworten und darauf verzichten alles neu zu senden. Aber die Anfrage muss raus.

Wem der IE Wurst ist, der ist sowieso fein raus. Oder man greift zur adaptiven Degradation in Sachen Ladezeiten und serviert den IEs die klassischen Bilder aus einem zweiten Stylesheet heraus. Je nach Gusto.

Dateien mit längeren Verfallsdaten ausstatten

Das hier ist eine sehr wirksame Geschichte: es geht darum, Dateien, die sich kaum verändern und die man einmal erfolgreich an den Mann gebracht hat, weiterhin dort vorrätig zu halten, so dass diese Daten bei einem erneuten Besuch dieser Person nicht nochmal angefordert werden, sondern die noch im Browser liegenden verwendet werden. Wir steuern also das Browser-Caching.

Zwar ist es sicherlich so, dass sich die JavaScript-Dateien und auch das CSS einer in der Entwicklung befindlichen, aber auch einer frisch gelaunchten Seite noch ändern - ist eine Seite aber eine Weile erfolgreich und ohne Wehwehchen am Laufen dann stehen die finalen Dateien fest.

Warum diese also unnötig neu laden? Deshalb können wir nun hingehen, und über einen der unterschiedlichen Wege, HTTP-Header zu setzen, definieren, dass beispielsweise .js, .css, sowie alle .gif. jpg. und .png Dateien einen vollen Monat lang gespeichert sein dürfen ohne neu geladen zu werden. Und das bedeutet wiederum, dass nach dem allerersten Aufruf einer Seite bei allen Folgeseiten nur noch das Inhaltsdokument von bestenfalls einigen Kilobytes und mit einem oder nur wenigen HTTP-Requests geladen wird.

YSlow Komponentenansicht mit Verfallsdaten

Das spart nicht nur Ladezeit, sondern auch der Webserver hat ein laueres Leben und der Webseiten-Traffic sinkt obendrein noch. Unter Apache können wir das Browsercaching durch einen Eintrag in eine/die eine .htaccess-Datei in unserem Basisverzeichnis erzwingen:

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 minutes"
  ExpiresByType text/html "access plus 1 minutes"
  ExpiresByType text/css "access plus 1 months"
  ExpiresByType text/javascript "access plus 1 months"
  ExpiresByType text/plain "access plus 1 months"
  ExpiresByType application/javascript "access plus 1 months"
  ExpiresByType application/x-javascript "access plus 1 months"
  ExpiresByType application/x-shockwave-flash "access plus 1 months"
  ExpiresByType image/gif "access plus 1 years"
  ExpiresByType image/jpeg "access plus 1 years"
  ExpiresByType image/jpg "access plus 1 years"
  ExpiresByType image/png "access plus 1 years"
  ExpiresByType image/x-icon "access plus 1 years"
  <FilesMatch ".*\.mhtml$">
    ExpiresActive Off
  </FilesMatch>
</IfModule>

Das ganze setzt ein aktiviertes Module "Expires" voraus, was es bei den meisten Hostern aber gibt. Ausprobieren. In diesem konkreten Fall verfallen CSS und JavaScript nach einem Monat, Bilder sogar erst nach einem Jahr. Erst dann schaut der Browser nach etwas Neuem. Und ich habe auch eine Ausnahme für .mhtml-Dateien drin, damit diese nicht gecached werden.

YSlow Statistik über das Datenladen beim ersten und bei weiteren Besuchen

Wer übrigens gerne beides hätte, sprich: hohe Vorhaltezeiten im Browser solange die Dateien sich nicht ändern und garantiertes Neuladen beim Update von Dateien, der sollte mit Versions- oder Datums-Parametern hinter den verlinkten Dateien arbeiten:

<link rel="stylesheet" type="text/css" href="styles.css?v=1.0" />

Beim nächsten Update der Datei ändert man den Link auf:

<link rel="stylesheet" type="text/css" href="styles.css?v=1.1" />

Das zwingt den Browser dazu, die Datei neu zu laden. Wer das automatisiert haben mag und PHP verwendet, der kann mit so einem Verfahren arbeiten:

echo '<link rel="stylesheet" type="text/css" href="styles.css?timestamp='.filemtime('styles.css').'" />';

Die zweitbeste Methode ist diejenige, wo der Browser die Dateien nicht cached, er also alle Anfragen beim zweiten Seitenaufruf erneut stupide erzeugt, der Server aber seinerseits feststellt (anhand von sogenannten ETags), dass sich anscheinend nichts geändert hat und mit einem kurzen und knackigen „304 Not Modified“! antwortet. Das war's auch schon, die Latenz bleibt, aber die komplette Nutzlast fällt immerhin weg.

Peter hat das hier in seinem Blog auf diese Art eingerichtet, und so werden aus den 206.7KB des ersten Seitenaufrufs schlanke 7.7KB ab dem zweiten (es bleibt aber immer bei den vollen 47 HTTP-Requests, die bei der optimalen Methode auch noch wegfallen könnten).

Daten komprimiert verschicken

In Zeiten wo man die Quadcores hinterhergeworfen bekommt, warum nicht ein paar Rechenzyklen darauf verpulvern alle komprimierbaren Daten, das sind vor allem Textdateien, beim Versenden per ZIP-Verfahren kleinzuschrumpfen? Und das verstehen auch alle anständigen Browser.

GZIP-Anzeige in der YSlow Komponentenansicht

Ganz speziell hilft uns das bei großen JavaScript-Libraries, aber auch beim Eindampfen von Data URI Einbettungen, und wir aktivieren das wiederum mit einem Eintrag in einer/der .htaccess-Datei in unserem Basisverzeichnis:

<FilesMatch ".*\.(html|php|css|js)$">
  SetOutputFilter DEFLATE
</FilesMatch>

JavaScripts in den Quelltext-Fußbereich

Warum JavaScript nicht in den Kopfbereich des Quelltextes? Nun, das Problem mit JavaScript ist dass es vom Browser vollkommen anders angefasst wird als andere Dateitypen. Der Browser rechnet bei JavaScript-Dateien nämlich mit dem Schlimmsten (= document.write), und blockiert das progressive Weiterrendern der Seite so lange, bis die verlinkte JavaScript-Datei vollständig geladen und geparsed, und die Gefahr eines document.write gebannt ist. Wenn Sie nun einen riesen Brummer von JavaScript-Datei in den Kopf der Seite packen, dann geht halt erst einmal gar nichts für den User.

Packen Sie sie hingegen vor das schließende </body>, dann bekommt Ihr Besucher ihre komplette Seite schonmal zu Gesicht, und dass der Browser nun am Schluss festhängt, das fällt dem Benutzer sowieso nicht auf, weil er sich ersteinmal orientiert. Ein wirklich effektiver psychologischer Trick!

JavaScript minifizieren (CSS aber auch)

Über den Begriff „minifizieren“ sind bestimmt alle schon gestolpert, spätestens wenn es um das Einbinden von JavaScript-Bibliotheken ging: hier bieten die Hersteller immer auch „minified“ Versionen an. Worum geht es bei dieser Minifiziererei? Grob gesagt darum, mit genialen Kniffen so viel unnötige Zeichen aus der JavaScript-Programmierung rauszuwerfen wie nur möglich, ohne sie dabei zu zerstören. Dazu werden Umbrüche und Leerzeichen entfernt, aber auch Variablen und Funktionen umbenannt in so etwas Kurzes wie „a“ oder „b“. Das spart richtig viel Platz: jQuery schrumpft minifiziert von 155 KB auf 72 KB (was per ZIP beim Ausliefern nochmals auf 24 KB schrumpft). Wow!

Vorher, nachher Ansicht des Minifizierens

Bei CSS werden Anweisungen in sogenannten Shorthand Anweisungen zusammengefasst und HEX-Farbwerte in Kurzformen überführt. Das spart nicht so viel, aber hey, immerhin.

Die Tools der Wahl sind da der Yahoo! YUI Compressor, eine Java-Applikation, die sowohl JavaScript als auch CSS eindampfen kann, sowie der Google Closure Compiler, der ebenfalls in Java geschrieben ist, der aber nur JavaScript minifizieren kann. Als PHP-Libraries gibt dann noch JSMin+ und CSSTidy.

CSS-JS-Booster

So, und weil alles das echt saumäßig viel Stupido-Arbeit ist und eigentlich auf jeder Seite, egal wie groß, von Nutzen ist, bin ich eines schönen Tages im letzten Jahr hingegangen und habe das ganze in eine schöne PHP5 Library hineingesteckt und diese auf Github abgelegt. „Nomen est Omen“ und deshalb heißt das gute Ding auch CSS-JS-Booster, kurz der Booster.

CSS JS Booster auf Github

Was nimmt der Booster Euch alles an Arbeitsschritten ab?

Der Booster arbeitet zweigleisig: einmal auf der CSS-, einmal auf der JS-Schiene. Manche Teilschritte sind dieselben, manche unterscheiden sich. Beide Teile können auch separat verwendet werden, zum Beispiel wenn man nur den JS-Teil gebrauchen kann.

CSS Optimierung

  • Der Booster bekommt einen Haufen CSS-Sourcedateien übergeben (oder CSS im Klartext im „stringmode“), die er der Reihe nach in ein großes Workfile hineinzieht. Findet er @import-Regeln im CSS, dann werden auch die an der entsprechenden Stelle in das Workfile hineingezogen, und alle Dateipfade darin entsprechend angepasst.
  • Im nächsten Schritt wird das CSS nochmal optimiert (minifiziert) mit Hilfe der Bibliothek „CSS Tidy“, die Einstellungen sind nicht extrem sondern möglichst ungefährlich und orientieren sich an einer Empfehlung von Dirk Jesse.
  • Nun durchforstet der Booster das CSS nach Bildverweisen, und wenn er einen findet dann schaut er auf der Platte ob er die Datei dort finden kann. Ist dem so, und ist sie kleiner als 24KB, dann liest er diese Datei ein, und je nach Browser des Users kodiert er die Daten ins Base64-Format und bettet sie als Data URI ins CSS ein, oder aber, wenn es sich um einen älteren IE handelt, dann schreibt er eine MHTML-Datei raus und verweist im CSS auf diese.
  • Beim Erzeugen des HTML-Codes zum Einbetten der CSS-Dateien, splittet er diese wieder auf in zwei gleichgroße Stylesheets, um die Tatsache auszunutzen dass die Browser mehrere Dateien parallel laden können und da tatsächlich schneller sind.
  • CSS wie auch MHTML werden bei der Ausgabe GZIP-komprimiert
  • Der Booster kümmert sich um ein effektives server- und clientseitiges Caching mit Timestamping. Wird das CSS aktualisiert, liefert er ein neues CSS aus. Aber nur dann.
  • Der Booster umgeht den Bug des IE7 auf Vista mit den MHTML-Dateien
  • Der Booster repariert das CSS-Hintergrundbild-Caching im IE6
  • Der Booster GZIP-komprimiert auch die Seite, in die das CSS eingeklinkt wird

JavaScript Optimierung

  • Der Booster bekommt einen Haufen JS-Sourcedateien übergeben (oder JavaScript im Klartext im „stringmode“), die er der Reihe nach in ein großes Workfile hineinzieht.
  • Im nächsten Schritt wird das JS an den Google Closure Compiler Webservice verschickt und, sofern es nicht die maximale POST-Grenze des Google Closure Compilers von 200KB überschreitet, minifiziert zurück in Empfang genommen.
  • Das JavaScript wird bei der Ausgabe GZIP-komprimiert
  • Der Booster kümmert sich um ein effektives server- und clientseitiges Caching mit Timestamping. Wird das JavaScript aktualisiert, liefert er ein neues JavaScript aus. Aber nur dann.

Cache Optimierungen für alles andere via .htaccess

Desweiteren habe ich auch eine .htaccess-Datei beigefügt, die sinnvolle Caching-Einstellungen für Bilder auf dem Webspace vornimmt, und die man in das Basisverzeichnis des Webservers kopieren kann/darf/sollte.

Anwendung des CSS-JS-Boosters

Das Einbinden des Boosters ist eine ganz einfache Sache: Ladet die aktuelle Version bei Github herunter und hängt das entpackte Verzeichnis „booster“ irgendwo auf Eurer Webseite ein. Dann braucht es noch ein Unterverzeichnis darin namens „booster_cache“ mit Schreibrechten zum Cachen der serverseitig generierten optimierten Dateien. Dann binden wir die Bibliothek ein und erzeugen ein neues Booster-Objekt:

include('booster/booster_inc.php');
$booster = new Booster();

Dann sagen wir dem Booster welche CSS- und JS-Dateien wir verarbeitet haben wollen. Dazu nennen wir ihm entweder ein Verzeichnis, dessen Dateien er alphabetisch einliest…

$booster->css_source = 'css-folder';
$booster->js_source = 'js-folder';

oder eine Datei…

$booster->css_source = 'css-folder/styles.css';
$booster->js_source = 'js-folder/javascript.js';

oder mehrere Verzeichnisse und/oder Dateien per Array, gerne wild gemischt…

$booster->css_source = array('css-folder-a','css-folder-b','css-folder-b/styles.css');
$booster->js_source = array('js-folder/javascript-a.js',''js-folder/javascript-b.js');

Zu guter letzt platzieren wir ein

echo $booster->css_markup();

an die Stelle wo der Booster unser CSS-Link-Markup ausspucken soll, idealerweise irgendwo im Kopfbereich der Seite, und ein

echo $booster->js_markup();

an die Stelle, wo der Booster das JavaScript-Markup ausgeben soll, idealerweise vor dem schließenden Body-Tag.
Das war's auch schon, fertig! Seite sollte nun schnell sein. Wer nur einen Teil von beiden nutzen will, der kann den anderen auch weglassen.

Das Wordpress-Plugin

Damit auch der weniger nerdige Netizen in den Genuss einer Webseitenbeschleunigung kommt, aber auch weil es so viele Wordpress-Seiten gibt, weil das die Bibliothek populärer macht und nicht zuletzt weil ich Bock drauf hatte, habe ich ein entsprechendes WP-Plugin als Spinoff gebaut.

Wordpress-Plugins

Ein, zwei Dinge handhabe ich hierbei anders: Zum einen schalte ich den Google Closure Compiler hier ab, da ich denke, dass es durchaus Plugins gibt, deren JavaScript so unsauber ist, dass sie einem kaputt gingen. Und wer wäre es dann Schuld? Ich natürlich! Zum anderen hänge ich mich erst kurz vor der endgültigen Ausgabe des gesamten HTML hinein, und schnappe mir das HTML. Dann durchforste ich es ausschließlich im Kopfbereich (Head-Element) nach CSS und JS Einbettungen und Inline-Code - nur im Head deshalb weil sonst die Gefahr groß ist dass etwas kaputt geht, das per document.write in den Body schreibt (z.B. Werbebanner). Die Pfade zu diesen Dateien löse ich auf, Inline-CSS oder -JS verfrachte ich in neuerzeugte lokale Dateien. Ebenso downloade ich externe Dateien in neue lokale Dateien. Anschließend ziehe ich alle Dateien in den passenden Reihenfolgenden zusammen, optimiere alles, kommentiere die alten Verlinkungen im HTML-Code aus und bette meine neuen Dateien statt der alten ein. Zum Schluss gebe ich das HTML-Resultat dann endlich aus.

Aufgearbeiteter HTML-Code

Funktionieren tut das ganze mit recht ansehnlichen Ergebnissen.

Ergebnisse, geblogt von Futtta

Download und weiterführende Infos zum Booster

Die CSS-JS-Booster Bibliothek bekommt Ihr hier und steht unter GNU Lesser General Public License V3.

Eine Übersicht über die Art und Weise der Einbindung bekommt Ihr im Wiki. Am besten, man steigt mit der Seite zum Basic Usage ein, und arbeitet sich dann gegebenenfalls tiefer in die Materie im Bereich Advanced Usage.

Das Wordpress-Plugin gibt es mit dabei, oder offiziell bei wordpress.org im Plugin Directory bzw. per Plugin-Suche in Wordpress selbst.

Wichtig: Der Booster ist ein reines PHP5 Konstrukt. Zum einen verwende ich neue PHP5 Befehle, die einem das Leben erleichtern, zum anderen verwende ich einen objektorientierte Aufbau auf den PHP4 leider nicht klarkommt. Dass mir da keine Beschwerden kommen! Falls Euer Provider Euch PHP4 aufgesetzt hat, erkundigt Euch wie Ihr den Webspace auf PHP5 umschalten könnt. Das geht fast immer.

Wenn Ihr Lust habt, baut auf Basis des Boosters gerne weitere CMS-Plugins, oder forked mich. Wenn Ihr Bugs findet (und das lässt sich nie vermeiden), gebt im Issue-Tracker Bescheid (aber checkt bitte vorher ob Ihr auch wirklich PHP5 am Start habt!).

Über den Autor

ScheppChristian Schaefer ist Jahrgang '78, hat seine Wurzeln bei Köln, lebt aber seit 2004 unbehelligt in Düsseldorf, und wird von jedermann außer den Eltern „Schepp“ genannt. Und das ist auch gut so. Es verschlug ihn 1998 ohne Studium direkt in eine 3D-Firma in Köln. Dort entwickelte er virtuelle Figuren für Messen und TV. Selbstständigmachung Anfang 2004 und Verlagerung des Fokus' auf die Webentwicklung. Sieht seine Schwerpunkte bei der Frontend-Entwicklung, hat aber auch kein Problem mit Backends und dem Architekten großer Sites in PHP und MySQL. Fertige CMSe nerven ihn. Frameworks sind OK. Nebenbei unterstützt er technisch den Kölner Multimediatreff, hat gerade ein Videotraining biblischen Ausmaßes in der Mache. Er twittert unter dem Account derSchepp und mag alles was sich um Essen dreht.

Kommentare (60)

  1. Marc

    12. April 2010, 14:16 Uhr

    U N G L A U B L I C H guter Beitrag. Danke.

  2. Sascha

    12. April 2010, 14:19 Uhr

    Nice! Sehr ausführlich und verständlich. Wird gleich beim nächsten Projekt angetestet! Danke für die Arbeit und die Beschreibung...

  3. Jörg

    12. April 2010, 14:53 Uhr

    Ich wollte gerade das Wordpress-Plugin bei mir einsetzen. Nach Aktivierung wird auf der Seite ganz oben "--> --> " ausgegeben ... Beißt sich das Plugin mit irgendwas?
    (Ich habe es natürlich wieder deaktiviert ... weil, sieht ja blöd aus ...)

  4. thomasweise

    12. April 2010, 15:12 Uhr

    Danke für diesen ausführlichen Beitrag!

  5. Dirk

    12. April 2010, 15:25 Uhr

    Ich sage mal ganz frei raus: Hut ab, Herr Schepp. Ganz großes Kino, sich all dieser Performance-Regeln in diesem Umfang und in einem Projekt anzunehmen. Ich hoffe, ich habe alsbald die Zeit zum Testen.

  6. FrankyBoy

    12. April 2010, 17:45 Uhr

    Hm, eine Frage besteht für mich noch: Wie wirkt sich das Minifizieren aus nachdem man dann GZIP drüber rennen lässt? Ich mein: zip sollte doch wiederkehrende Elemente nach Möglichkeit eindampfen, bleibt da also noch so viel Vorsprung über?

  7. schepp

    12. April 2010, 18:22 Uhr

    Zitat Jörg:

    Ich wollte gerade das Wordpress-Plugin bei mir einsetzen. Nach Aktivierung wird auf der Seite ganz oben "--> --> " ausgegeben ... Beißt sich das Plugin mit irgendwas?
    (Ich habe es natürlich wieder deaktiviert ... weil, sieht ja blöd aus ...)

    Schwer zu sagen. Es gibt zum einen so viele verschiedene Webserver-Konfigurationen, zum anderen auch zig Wordpress-Plugins, die da hineingrätschen könnten. Vielleicht machen wir es so, dass Du das Plugin nochmal bei Dir aktivierst, und mir dann den Quelltext der Seite zuschickst? Vielleicht kann ich da Rückschlüsse draus ziehen. Meine Email ist schaepp (ja, tatsächlich mit ae), dann ein At, dann gmx.de. Dank Dir!

    @all Danke an alle für die freundlichen Komplimente! So tolles Feedback macht richtig Laune :)

  8. Oliver

    12. April 2010, 18:50 Uhr

    Sehr lesenswerter Beitrag mit genau der richtigen Art trotz Umgangsprache die technischen Aspekte nicht hinten runter fallen zu lassen. Lesenswert, unterhaltsam, lehrreich.

  9. Michael van Laar

    12. April 2010, 19:55 Uhr

    Super! Da muss jetzt für mich nur noch ein hübsches MODx-Snippet draus werden. Mal sehen, ob ich das trotz beschränkter PHP-Kenntnisse schnell mal hinkriege.

  10. Ingo

    12. April 2010, 20:04 Uhr

    Die Idee, den Minify-Klumpen zu zweiteil-parallelisieren finde ich nett ;-)

    Wie sieht's denn aus mit Conditional Comments a la "if lt IE 7"? Normalerweise fällt einem sowas beim Minifizieren erstmal auf die Füße.

    Und dann ebenfalls (wie FrankyBoy) die Frage: Lohnt sich tidy überhaupt, wenn man eh GZIP drüberjagt?

  11. schepp

    12. April 2010, 20:15 Uhr

    Zitat FrankyBoy:

    Hm, eine Frage besteht für mich noch: Wie wirkt sich das Minifizieren aus nachdem man dann GZIP drüber rennen lässt? Ich mein: zip sollte doch wiederkehrende Elemente nach Möglichkeit eindampfen, bleibt da also noch so viel Vorsprung über?

    Guter Grundgedanke, aber die Praxis zeigt: beide Methoden zusammen führen zum besten Ergebnis. GZIP schrumpft für sich alleine auf etwa 33%, das Minifizieren erreicht zwischen 50% und 33% der Ausgangsgröße, aber zusammen schaffen sie es, die Ausgangsdatei auf etwa 20% der Dateigröße zu verkleinern.

    Wenn es aber nur um ein schnelles unkompliziertes Tunen geht, dann ist GZIP sicherlich das Mittel der Wahl.

  12. Uwe Kuhl

    12. April 2010, 20:16 Uhr

    Chapeau! Das ist ein ganz heisses Ding, das Du da von der Leine gelassen hast. Meine lieben SEOs da draussen: So macht man einen Linkbait. Wünsche Dir viele Backlinks, erfrischende Kommentare und einen standhaften Server, der den Besucheransturm verkraftet :)

    @Marc: Kann vielleicht jemand auf dieser Basis ein MODx Plugin basteln? Hüstel.

  13. schepp

    12. April 2010, 20:23 Uhr

    Zitat Ingo:

    Wie sieht's denn aus mit Conditional Comments a la "if lt IE 7"? Normalerweise fällt einem sowas beim Minifizieren erstmal auf die Füße.

    Die von Dir genannten CC's gibt es ja nur in HTML, und das verarbeite ich ausschließlich drüben im Wordpress-Modul. Da muss ich allerdings wirklich mal nachsehen, ob ich die korrekt auflöse.
    Mit denen hat der Stand-Alone-Booster aber zum Glück nichts zu schaffen.

    Ansonsten gibt es noch die recht seltenen JavaScript-CC's, die der Google Closure Compiler tatsächlich nicht kann (der YUI Compressor kennt sie, hat aber leider keine Schnittstelle). Den Closure Compiler müsste man dann per

    $booster->js_minify = FALSE;

    Kommando vor der Ausgabe abschalten.

  14. Michael van Laar

    12. April 2010, 22:26 Uhr

    Zitat Uwe Kuhl:

    @Marc: Kann vielleicht jemand auf dieser Basis ein MODx Plugin basteln? Hüstel.

    Da würde ich mithüsteln ;-) Mein erster Versuch, aus dem Stand-Alone-Booster ein halbwegs komfortables MODx-Snippet zu basteln, war komplett erfolglos. Ich muss eben doch erst noch ein wenig fester im PHP-Sattel sitzen.

  15. Fexxx

    13. April 2010, 10:05 Uhr

    Vielen Dank für das vielversprechende Wordpress-Plugin!

    Ich nutze dieses mit einer aktuellen Wordpress Installation auf einem Strto Standard-Webpaket. Was mich jetzt irritiert ist, dass ich keine HTML-Kommentare wie im artikel beschrieben im Quelltext meiner Seite finden kann - der Primed Cache Wert aber ca. auf ein Drittel geschrumpft ist?

    LG
    Fexxx

  16. Siegfried

    13. April 2010, 11:32 Uhr

    Manueller Pingback: http://www.rorkvell.de/news/2010/Schnell-Seiten.html.de

  17. Jörg Dutschke

    13. April 2010, 11:55 Uhr

    Auflösung meines Problems (s.o.):
    Ich hatte in der Header.php zwei Zeilen mit Stylesheetanweisungen nur mit HTML-Kommentaren auskommentiert. Da das Plugin sich genau da reinhängt, wurden die HTML-Kommentare quasi gedoppelmoppelt und heraus kam die Ausgabe von "--> -->" am Anfang der Site.

  18. Schepp

    13. April 2010, 12:06 Uhr

    Zitat Fexxx:

    Vielen Dank für das vielversprechende Wordpress-Plugin!

    Ich nutze dieses mit einer aktuellen Wordpress Installation auf einem Strto Standard-Webpaket. Was mich jetzt irritiert ist, dass ich keine HTML-Kommentare wie im artikel beschrieben im Quelltext meiner Seite finden kann - der Primed Cache Wert aber ca. auf ein Drittel geschrumpft ist?

    LG
    Fexxx

    Dann wirkt bei Dir nur mein Expires-Tuning in der .htaccess-Datei, aber das Quelltext-Parsen steigt aus. Hast Du einen Link?

  19. Fexxx

    13. April 2010, 13:20 Uhr

    @schepp

    gibt es eine möglichkeit dir den link als pm / email zukommen zu lassen?
    meine ist fexxx/at/kuhmuhneDOTcom
    lg
    fexxx

  20. Schepp

    13. April 2010, 15:19 Uhr

    Zitat Fexxx:

    @schepp

    gibt es eine möglichkeit dir den link als pm / email zukommen zu lassen?

    Mail ist zu Dir unterwegs...

  21. Pelle

    13. April 2010, 15:50 Uhr

    Top Script fuer WP, danke dafuer. Leider funktioniert das mit unserem AdServer nicht. Kann man irgendwie bestimmte Scripte davon ausnehmen?

  22. Markus Thömmes

    13. April 2010, 16:41 Uhr

    Ich hab arge Probleme mit dem Wordpress Plugin:
    Ich bekomm zwar die Kommentare in der Ausgabe, allerdings fügt er keine neue CSS-Datei ein. Irgendwie suboptimal.

    Aber: Super klasse Artikel und geniales Projekt!

  23. Markus Thömmes

    13. April 2010, 16:46 Uhr

    Sorry für Doppelpost:
    Hat sich erledigt, war wohl eine falsche Konfiguration meines lokalen PHP-Servers.

    Danke für das coole Plugin.

  24. Sven

    14. April 2010, 07:17 Uhr

    Das Wordpress Plugin funktioniert bei mir nicht korrekt (http://www.sgeblog.de). Die CSS scheinen alle ersetzt zu werden, auch die JS, aber das CSS ist bei der Ausgabe quasi nicht mehr existent und die Seite wird komplett unformatiert angezeigt.

  25. jmar

    14. April 2010, 08:19 Uhr

    Ich freue mich über diese tolle Lösung. Wesentlich besser als die minify lib. Ich werde deine Lösung heute oder morgen auf unserer Seite einbauen und schauen, wie alles läuft und welche Ersparnis das ganze bringt. Melde mich danach hier wieder zu Wort.

  26. Kai

    15. April 2010, 10:29 Uhr

    Hi,

    sehr tolle Arbeit. Ein Test mit dem Wordpress-Plugin hat sehr gut funktioniert.
    Nun versuche ich den CSS-JS-Booster in einem Template-basierendem System einzubauen. Gibt es eine Möglichkeit statt der relativen-Pfad-Angaben absolute Pfade zu verwenden?

    Vielen Dank
    Kai

  27. Ingo

    15. April 2010, 19:29 Uhr

    Absolut paths are a recipe for DOOM. Wollt ich mal anmerken.

  28. Schepp

    16. April 2010, 14:22 Uhr

    Zitat Kai:

    Gibt es eine Möglichkeit statt der relativen-Pfad-Angaben absolute Pfade zu verwenden?

    Hallo Kai,

    das muss ich noch einbauen. Allerdings kannst Du Dir mit folgender Konstruktion behelfen, die eine Methode des Boosters zr Pfadberechnung nutzt:

    // Arbeiten mit absoluten Pfaden
    // CSS liegt im Verzeichnis $_SERVER['DOCUMENT_ROOT'].'/css';
    $booster = new Booster();
    $basisverzeichnis = $_SERVER['DOCUMENT_ROOT'];
    $diesesverzeichnis = str_replace('','/',dirname(__FILE__));
    $prefix = $booster->getpath($basisverzeichnis,$diesesverzeichnis);
    $booster->css_source = $prefix.'/css';
    
    echo '<p>'.$booster->css_source.'</p>';
  29. Schepp

    16. April 2010, 14:32 Uhr

    Zitat Pelle:

    Leider funktioniert das mit unserem AdServer nicht. Kann man irgendwie bestimmte Scripte davon ausnehmen?

    Probier mal die 0.2.5. Ich hab das "nach Lokal"-Kopieren des WP-Plugins wieder abgeschaltet. Zu viele Scripte scheinen dann nicht zu laufen.

    Leider ändert das "nicht-Einverleiben" der Scripte von externen Servern auch die Reihenfolge, wann diese ausgeführt werden. Kann also ebenfalls zu Problemen führen, aber vielleicht sind die dann seltener.

    Zitat Sven:

    Die CSS scheinen alle ersetzt zu werden, auch die JS, aber das CSS ist bei der Ausgabe quasi nicht mehr existent und die Seite wird komplett unformatiert angezeigt.

    Ohne die Resultate vor Augen und Details zu haben, kann ich da nichts zu sagen. Das kann alles möglich sein. Hast Du mal in das generierte CSS reingeschaut?

  30. Pelle

    16. April 2010, 14:43 Uhr

    Zitat Schepp:

    Zitat Pelle:

    Probier mal die 0.2.5. Ich hab das "nach Lokal"-Kopieren des WP-Plugins wieder abgeschaltet. Zu viele Scripte scheinen dann nicht zu laufen.

    Leider ändert das "nicht-Einverleiben" der Scripte von externen Servern auch die Reihenfolge, wann diese ausgeführt werden. Kann also ebenfalls zu Problemen führen, aber vielleicht sind die dann seltener.

    Hi Schepp,

    danke fuer die Antwort. Bringt aber leider auch nichts, die Werbung wird weiterhin nicht angezeigt, wenn ich das Plugin aktiviere :(

  31. Kai

    16. April 2010, 14:53 Uhr

    Hallo Schepp,

    vielen Dank für Deine Antwort zum Thema absolute Pfade. Leider funktioniert das bei mir nicht. Ich benutze das Template-System Smarty, wodurch die templates immer in einer Ebene liegen. Da die URLs aber über mod_rewrite generiert werden, kann es sich durchaus um "Unterordner" handeln.

    Beispiel:
    /pfad/zum/webserver/templates/xyz.html
    /pfad/zum/webserver/css/
    /pfad/zum/webserver/images/

    Da die URLs über mod_rewirte mal www.example.com/ebene1/asdf.html oder auch www.example.com/ebene1/ebene2/ebene3/asdf.html heißen können, wird entweder der Pfad zum CSS falsch generiert oder er kann die eingebundenen Images nicht finden, da diese im CSS immer absolut (also /images/beispiel.png) angegeben sind.

    Gibt es eine Möglichkeit das irgendwie voneinander zu trennen?

    Beste Grüße
    Kai

  32. mona

    21. April 2010, 14:43 Uhr

    Schön wäre noch ein Performance Vergleich zwischen diesem Plugin und http://wordpress.org/extend/plugins/wp-minify/ gewesen.

    Auf jeden Fall, werde ich mir das mal noch näher ansehen.

  33. jb

    24. April 2010, 10:36 Uhr

    Hi,
    sehr schöner und gut verständlicher Artikel!

    Habe da aber noch eine Frage bezüglich des Einbinden von JS am Ende des Dokuments: Bringt es was bzw. macht es Sinn kurz vorm mit JS die ganzen wichtigen Sachen in den zu schreiben, oder wäre das unnötig?

    mfg

  34. jb

    24. April 2010, 10:41 Uhr

    Zitat jb:

    Hi,
    sehr schöner und gut verständlicher Artikel!

    Habe da aber noch eine Frage bezüglich des Einbinden von JS am Ende des Dokuments: Bringt es was bzw. macht es Sinn kurz vorm </body> mit JS die ganzen wichtigen Sachen in den <head> zu schreiben, oder wäre das unnötig?

    mfg

    sorry, da hab ich wohl das codieren vergessen ;)

  35. Schepp

    24. April 2010, 10:51 Uhr

    @jb
    Nein, das bringt dann nichts mehr. In den Head packt man die Sachen nicht der Form halber, sondern damit sie jederzeit während des Parsings der Seite von oben nach unten für Inline-Javascript verfügbar sind (Variablen, Funktionen, whatever). Wenn Du Inhalte also am Ende des Parsing oben ins Dokument einfügst, dann hat das Parsing dabei nichts gewonnen - denn das ist ja dann vorbei.

    Wenn man allerdings nicht so den 100%igen Peil hat, was die Javascripte so treiben, die man auf seiner Seite verbaut, und wenn Funktionalitäten beim In-den-Fuss-Verfrachten kaputtgehen, dann geht Fehlerfreiheit vor Performance und dann sollte man die Dateien doch im Kopf belassen. Ausprobieren, wenn nicht dann eben nicht.

  36. Klaus Thieme

    28. April 2010, 19:48 Uhr

    Hallo Schepp,
    ich finde dein Tool echt Klasse, habe jedoch folgendes Problem:
    Auf meiner Seite (www.hallen.wenqu.org) setze ich den Booster ein...
    Hier finde ich jedoch im Quellcode 2 CSS Dateien verlinkt: Part 1 und Part 2.

    Wenn ich mir die Datei anschauen besitzen diese den exakt gleichen Inhalt.

    Warum schreibt er dann 2 Parts?

    Letztes Update des Boosters war 28.04.2010.

    Hoffe auf schnelle Hilfe

    Freundliche Grüsse
    Klaus Thieme

  37. Schepp

    28. April 2010, 20:11 Uhr

    Hallo Klaus,

    ich hab mir Deine Seite und die beiden CSSen angesehen und da sieht alles spitzenmäßig aus. Beide Dateien enthalten auch unterschiedliches CSS. Ich würde demnach sagen: alles im grünen Bereich, genau so muss es aussehen! :)

    Viele Grüße

    vom Schepp

  38. Klaus Thieme

    29. April 2010, 06:59 Uhr

    Hallo Schepp,
    das kann ich nicht bezeugen...
    ich habe folgende Dateien mit WinMerge und Notepad++ verglichen:

    http://hallen.wenqu.org/booster/booster_css.php?dir=../css&cachedir=booster_cache&totalparts=2&part=1&nocache=1272481322
    http://hallen.wenqu.org/booster/booster_css.php?dir=../css&cachedir=booster_cache&totalparts=2&part=2&nocache=1272481322

    Und sie sind identisch. Mache ich was falsch? Wie kommt das Zustande?

    Freundliche Grüsse
    Klaus

  39. Schepp

    29. April 2010, 07:36 Uhr

    Zitat Klaus Thieme:

    Und sie sind identisch.

    Stimmt, die zwei verlinkten sind absolut identisch. Aber wenn Du mal (z.B. mit Firefox) in den Quelltext Deiner Handball-Seite gehst, und oben auf die eingebundenen CSSen klickst, dann wirst Du sehen, dass beide nur genau den Teil zeigen, den sie zeigen sollen.

    Des Rätsels Lösung: Wenn Du Dir die URLs aus dem Quelltext in die Adressleiste kopierst, dann musst Du die

    &amp;

    gegen

    &

    tauschen. Denn im Quelltext muss ich die ja standardkonform entitätskodieren während sie in der Adresszeile kaufmännische Unds bleiben dürfen. Korrigierst Du das nicht, werden die Anhängsel für PHP zu Paramatern à la "amp;totalparts" statt "totalparts". Und dann rafft der Booster nichts und geht auf einen Fallback, bei dem er alles komplett ausgibt.

  40. Klaus Thieme

    29. April 2010, 08:34 Uhr

    Vielen Dank,
    ich habe auch selbst mit YSlow nach der Dateigröße geschaut, die war auch unterschiedlich.

    Da ich meist mit GoogleChrome arbeite habe ich dort im Quelltext auf die CSS Dateien geklickt, aber da wurden die &amp:'s nicht ersetzt im Firefox hingegen schon.

    Nocheinmal ein Dankeschön für deine Mühe.

    Klaus

  41. Cujo

    23. Mai 2010, 14:11 Uhr

    Vielen Dank für diesen tollen Artikel. Vieles kannte ich schon, aber der Trick mit der durch PHP aktualisierten Versionierung der styles.css war mir neu.

  42. Fexxx

    5. Juli 2010, 21:48 Uhr

    Hallo, ich bin es nochmal :) - Hoffe hier gibt es noch "Support" ?
    Nutze das Script nun für eine CMS (www.contao.org) Seite. Das CSS "boosten" klappt jetzt prima - nur bei den JS Files wird eine leere Cache Datei erstellt und dementsprechend klappen auch keine JS Funktionen mehr auf der Webseite?
    Der Pfad stimmt aber >> $booster->js_source = 'tl_files/js/'; <<

    LG
    Felix

  43. Schepp

    6. Juli 2010, 10:55 Uhr

    Zitat Fexxx:

    Hallo, ich bin es nochmal :) - Hoffe hier gibt es noch "Support" ?

    Aber in jedem Fall!

    nur bei den JS Files wird eine leere Cache Datei erstellt und dementsprechend klappen auch keine JS Funktionen mehr auf der Webseite?
    Der Pfad stimmt aber >> $booster->js_source = 'tl_files/js/'; <<

    Wenn Du den Booster am Wochenende gezogen, oder gar aktualisiert hast: ich habe die Pfadangabe zu den CSS und JS der neuesten Version von Relativ zur Booster-nutzenden Datei auf Relativ zum Booster-Verzeichnis umgestellt. Ergo würde die neuere Version möglicherweise ein
    $booster->js_source = '../tl_files/js/';
    benötigen, so Du den Booster im Unterordner /booster liegen hast.

    Ich tippe aber, Du nutzt noch die Version davor, richtig?
    Wenn ja: Schickst Du mir mal den Link zu der Seite mit der Ladehemmung?

  44. Fexxx

    8. Juli 2010, 07:49 Uhr

    Hallo Schepp,

    habe den JS Booster auf folgender Seite eingebaut. Leider geht dann gar kein JS mehr auf der Site: mediastuff-PUNKT-de/test.html

    Das ist der Code vor dem schließenden Body-Tag (der im Quelltext / live) dann garnicht mehr erscheint?

    >>
    js_source = 'tl_files/js';
    echo $booster->js_markup();
    ?>
    <<

    Danke Dir

    LG
    Fexxx

  45. Fexxx

    8. Juli 2010, 07:52 Uhr

    Oha, die Kommentarfunktion hat den Code etwas beschnitten. Hier nochmal vollständig:

    <?php
    include('booster/booster_inc.php');
    $booster = new Booster();
    $booster->js_source = 'tl_files/js';
    echo $booster->js_markup();
    ?>
  46. Schepp

    8. Juli 2010, 08:01 Uhr

    Zitat Fexxx:

    <?php
    include('booster/booster_inc.php');
    $booster = new Booster();
    $booster->js_source = 'tl_files/js';
    echo $booster->js_markup();
    ?>

    Die Anweisungen sehen OK aus.

    Nur kann ich leider nicht viel an Deiner Seite herumtesten, da wenn ich http://www.mediastuff.de/booster/booster_inc.php aufrufe, ich nur ein "Not Found" zurückbekomme.

    Hast Du Twitter am Start? Mich findest Du unter @derSchepp. Dann müssen wir uns nicht hier bei Peter im Blog ausbreiten. Das Endergebnis, so es denn für andere interessant wäre, würde ich dann hier posten.

  47. Fexxx

    8. Juli 2010, 11:32 Uhr

    Hallo Schepp,

    ok habe einen Tweet http://twitter.com/mediastuffDE angelegt

  48. Schepp

    9. Juli 2010, 10:03 Uhr

    Zitat Fexxx:

    Hallo Schepp,

    habe den JS Booster auf folgender Seite eingebaut. Leider geht dann gar kein JS mehr auf der Site

    Wen es interessiert: des Rätsels Lösung waren zum einen in der Tat der Pfad zum JavaScript-Ordner, welcher nicht relativ zum Booster-Verzeichnis gesetzt war (wie es neuerdings erforderlich ist) und zum anderen wurden die JavaScript-Dateien in diesem Verzeichnis zwar aus meiner Sicht wunschgemäß alphabetisch, aber aus Fexxx's Sicht in einer für den Gesamtablauf nicht passenden Reihenfolge eingelesen.

    Wir haben also den Pfad zum Verzeichnis per vorangestelltem ../ ergänzt, und die darin enthaltenen Scripte per Umbenennung in die richtige alphabetische Reihenfolge gebracht.

    Bitte immer schon das Wiki lesen! ;)

  49. Franz

    17. Juli 2010, 09:04 Uhr

    Hi Schepp,

    schön, dass du hier noch liest, auf github kann man ja anscheinend keine Kommentare/Bugs posten. Habe vorhin folgendes festgestellt:
    Wenn man eine CSS-Datei via

    <style type="text/css" media="screen">
    	@import url( <?php bloginfo('stylesheet_url'); ?> );
    </style>

    einbindet, so verschwindet diese, wenn das WordPress-Plugin installiert ist. Wenn ich die Einbindung zu

    <link type="text/css" rel="stylesheet" media="screen" href="<?php bloginfo('stylesheet_url'); ?>" />

    ändere, funktioniert es bestens.

    Noch eine Frage: Ist es möglich, z.B. die JS-Kompression auch bei WordPress zu aktivieren oder muss ich da im Plugin-Code "herumpfuschen"?

    Danke für das tolle Plugin!

    Franz

  50. Schepp

    19. Juli 2010, 13:41 Uhr

    Zitat Franz:

    Wenn man eine CSS-Datei via

    <style type="text/css" media="screen">
    	@import url( <?php bloginfo('stylesheet_url'); ?> );
    </style>

    einbindet, so verschwindet diese, wenn das WordPress-Plugin installiert ist.

    Ah... das wird wahrscheinlich an Wordpress' absoluten Pfaden liegen. Als ich den Booster schrieb, hatte ich relative Pfade vor Augen, also den Regelfall, und muss das für das Auflösen des @imports nachrüsten. Habe ich dort verpennt. Wird auf jeden Fall gemacht. Dank Dir für den Hinweis!

    Noch eine Frage: Ist es möglich, z.B. die JS-Kompression auch bei WordPress zu aktivieren oder muss ich da im Plugin-Code "herumpfuschen"?

    Das ist möglich. Allerdings musst Du dazu tatsächlich, da ich mich bislang aufgrund der Aufwands-Nutzen-Relation noch scheue ein WP-Admin-Interface für den Booster zu bauen, in der wp_booster.php herumpfuschen. Dort findest Du ein

    $booster->js_minify = FALSE;

    das Du entweder auf TRUE setzen, oder das Du auskommentieren müsstest (Booster-default ist TRUE). Ist allerdings nervig, dass diese Änderung bei Updates wieder verschwinden werden. Da muss ich mir mal was überlegen.

    Zum Hintergrund: Ich hab es deshalb in WP abgeschaltet, weil es durchaus sein kann, dass es irgendwelche Plugins mit unorthodox geschriebenem JavaScript zerstört.

    Danke für das tolle Plugin!

    Danke für das nette Feedback! Das freut mich sehr!

  51. Schepp

    22. Juli 2010, 15:30 Uhr

    Zitat Franz:

    Wenn man eine CSS-Datei via

    <style type="text/css" media="screen">
    	@import url( <?php bloginfo('stylesheet_url'); ?> );
    </style>

    einbindet, so verschwindet diese, wenn das WordPress-Plugin installiert ist.

    Wenn es tatsächlich die von mir vermuteten absoluten Pfade bzw. vollen URLs waren, die dort in der @import-Regel drinstanden, dann sollte das Problem ab Version 0.3.7 des WP-Plugins sowie im regulären Booster passé sein.

  52. LuK

    18. Oktober 2010, 23:12 Uhr

    Zitat Michael van Laar:

    Zitat Uwe Kuhl:

    Da würde ich mithüsteln ;-) Mein erster Versuch, aus dem Stand-Alone-Booster ein halbwegs komfortables MODx-Snippet zu basteln, war komplett erfolglos. Ich muss eben doch erst noch ein wenig fester im PHP-Sattel sitzen.

    hier noch einer der mithüsteln würde =)...ich versuch mich demnächst daran, mal schauen ob ichs hinkrieg...

  53. Rodney Rehm

    24. Oktober 2010, 11:47 Uhr

    Nicht nur ein sauberer Artikel, auch ein echt nettes Tool. Habt Ihr fein gemacht.

    Auf der Suche nach Lösungen unsere bereits (händisch) minifizierten CSS (und Sprites) Geschichten auf die nächst höhere Ebene zu bringen, hat speziell die Idee der Embedded Images meine Aufmerksamkeit auf sich gezogen.

    In Bezug darauf hab ich ein bisschen experimentiert - Schlussendlich lediglich ein Anstoß den Booster vielleicht noch um ein kleines Detail zu verbessern.

  54. Schepp

    24. Oktober 2010, 21:44 Uhr

    Zitat Rodney Rehm:

    Nicht nur ein sauberer Artikel, auch ein echt nettes Tool. Habt Ihr fein gemacht.

    Dank Dir! Stecken mittlerweile auch viele viele Stunden Arbeit drin.

    In Bezug darauf hab ich ein bisschen experimentiert - Schlussendlich lediglich ein Anstoß den Booster vielleicht noch um ein kleines Detail zu verbessern.

    Ich hab Dir unter Deinem Artikel geantwortet ;)

    Grüße!

  55. joseph

    26. Oktober 2010, 12:22 Uhr

    Hi.
    Schönet Ding!

    Bei mir funktionierte die Kompression nicht, da in der booster_inc.php Zeile 42 (!) die zlib.output_compression nur boolsch' überprüft wird, in der php.ini aber off steht.

    greetz

  56. Schepp

    27. Oktober 2010, 15:50 Uhr

    Zitat joseph:

    Bei mir funktionierte die Kompression nicht, da in der booster_inc.php Zeile 42 (!) die zlib.output_compression nur boolsch' überprüft wird, in der php.ini aber off steht.

    Danke für die Bugmeldung! Das ist natürlich dann Grütze so. Werd' ich für's nächste Release 1.8.1 korrigieren.

  57. Alois

    5. November 2010, 14:27 Uhr

    Bevor ich es vergesse: das Ziel Advanced Usage wäre hier eher angesiedelt (siehe weiter oben im Beitrag).

    Das Eigentliche: dieser Beitrag und die CSS-JS-Booster Library haben mir eine schöne Stange Zeit gekostet, konnte ich doch nach dem ersten Testlauf nicht mehr die Finger davon lassen. Hut ab: gut recherchiert, effizient dargestellt und codiert.

    Leider habe ich bis dato aber keine Möglichkeit gefunden, zu verarbeitende Dateien als Variable bzw. als Array zu übergeben. Ein ...

    <?
     ...
     $arrCSS = array('.......');
     array_push($arrCSS,'...');
     ...
     $booster->css_source = $arrCSS;
     ...
     ?>

    ... schlägt leider fehl. Die vorgegebenen Lösungsansätze durch die Angabe von Verzeichnissen bzw. Datei-Pfaden sind trotz ihrer Vielfältigkeit - speziell in meinem Fall - nicht praktikabel, weil CSS und JS in unterschiedlichen Verzeichnissen (je PlugIn) liegen und diese auch nur dann geladen werden, wenn ein PlugIn aktiviert ist (<head> wird dynamisch erstellt). So beinhaltet ein $arrCSS Array auch nur Angaben über .CSSe, ergo .JSe, die zum einen vom System und zum anderen von aktivierten PlugIns benötigt werden (6-40).
    Habe ich da eine Möglichkeit übersehen?

    Die PHP Warnung Cannot modify header information - headers already sent by (output started at...habe ich noch nicht weiter verfolgt. Der Ursprung liegt wahrscheinlich in der Kombination von session_start(); header('content-type:...'); und @ob_start; (CSS-JS-BOOSTER). Hänge noch dran...

    Danke, klasse Arbeit!

    Just my 2 cents

  58. Schepp

    5. November 2010, 16:18 Uhr

    Zitat Alois:

    Bevor ich es vergesse: das Ziel Advanced Usage wäre hier eher angesiedelt (siehe weiter oben im Beitrag).

    Autsch, ja, der ging neuerdings ins Leere. Ist geändert, dank Dir!

    Leider habe ich bis dato aber keine Möglichkeit gefunden, zu verarbeitende Dateien als Variable bzw. als Array zu übergeben.

    Warum schlägt es denn fehl? Was passiert genau? An sich sieht das nämlich absolut richtig aus, was Du da machst. Bei den/dem array_push(s) fügst Du auch jeweils einen String ins Array hinzu, oder? Also hast quasi am Ende einen Array, das ausschließlich aus Strings besteht?

    Die PHP Warnung Cannot modify header information - headers already sent by (output started at...habe ich noch nicht weiter verfolgt. Der Ursprung liegt wahrscheinlich in der Kombination von session_start(); header('content-type:...'); und @ob_start; (CSS-JS-BOOSTER). Hänge noch dran...

    Jepp, das ist genau die Ursache. Wenn Du den header-Befehl unterhalb der includierten booster_inc.php einhängst, dann dürfte der Fehler weg sein.

    Danke, klasse Arbeit!

    Freut mich! Danke :)

  59. InforMedic

    14. Januar 2011, 10:29 Uhr

    NAHTLOS BEGEISTERT!!! Super ausführlicher und verständlicher Beitrag!!!

  60. Lars

    8. September 2013, 18:26 Uhr

    Hallo Schepp,

    zuerste einmal danke auch von meiner Seite für das Tools, welches ich schon eine ganz Weile sehr erfolgreich nutze. Jetzt bin ich jedoch auf ein Problem aufmerksam geworden, wo ich echt nicht weiter weiss:

    - manche Bilder (alles PNG im Bereich um die 2-10kb) werden nach base64 umgewandelt und ins CSS eingebunden (die Cache Datei vom Booster)
    - andere wiederum nicht, obwohl sie auch im Bereich um die 5kB sind und auch angezeigt werden

    Ein Blick in den Quellcode hat mich nur zu der Zeile mit den 24kB-Limit gebracht. Trifft ja aber nicht zu.

    Wäre super, wenn Du einen Tipp für mich hättest.

    Danke und viele Grüße,
    Lars

Die Kommentarfunktion ist seit Juli 2014 deaktiviert, weil sie zu sehr von Suchmaschinenoptimierern für manuellen Spam mißbraucht wurde. Wenn du Anmerkungen oder Fragen zum Artikel hast, schreib mir eine E-Mail oder melde dich via Twitter.

Folgt mir!

Kauft mein Zeug!

Cover der HTML5-DVD
Infos auf html5-dvd.de, kaufen bei Amazon

Cover des HTML5-Buchs
Infos auf html5-buch.de, kaufen bei Amazon

Cover des CSS3-Buchs
Infos auf css3-buch.de, kaufen bei Amazon