Includes von Javascript und CSS Files minimieren

Sonntag, 7. August, 2011

Im Laufe der Zeit sammeln sich mehr und mehr kleine Skripte und CSS-Dateien an, die um Einbindung in den Header bitten. Bei mir wurde das Arsenal auch immer grösser:

Javascript:
Ich hatte mehrere Dateien mit eigenen Javascript-Funktionen (wobei die ein oder andere nur im Fall der Verwenung nachgeladen wurde). Hinzu kommen ein Javascript Framework (jQuery) und diverse jQuery Plugins und sonstige Javascripts von Fremdanbietern.

CSS:
Ich verwende 2 CSS-Dateien für die Darstellung auf Bildschirmen und eine CSS Datei für Druckausgabe. Weitere Dateien kommen CSS-Dateien von jQuery-Plugins und sonstigen PHP-Skripten.

Lösungsansatz 1: head.js
Mit dieser Variante lädt man ein einzelnes Javascript im Header und fügt mit einer Javascript die benötigten JS-Dateien nach. Weiterhin bietet head.js nette kleine Features: es Automatismen zum Abfangen von Browser-Features, wie Bildschirmauflösung, HTML-5-Unterstützung, dynamisches CSS. So kam es zunächst auch in die engere Wahl…

Nachteile:
Bei mir zeigten sich einige Unannehmlichkeiten. Bei einer existierendem head.js einzupflanzen und es läuft … so einfach ist es leider nicht. In meinem Fall: ich habe verschiedene Javascript-Funktionen im HTML-Body, die sich bisher darauf verlassen haben, dass die Funktion auch im Header geladen wurde. Durch das asynchrone nachladen stehen beim Rendern der Page die Funktionen machmal noch nicht bereit. Onmousemove in Links oder im Html-Body eingebundene Sektionen finden dann die Funktionen nicht.
Ich habe seinerzeit Content und Funktionen nicht sauber getrennt und müsste jetzt nachträglich leider zu viel umbauen.
Anm.: Die Lösung bestünde darin in einer Sektion beim Event Document Ready anzudocken und seine Elemente mit den Javascript Events nachzurüsten.

Nachteil 2: Für CSS gibt es mit Javascript keinen Ansatz.

Lösungsansatz 2: alle Dateien mergen
Das habe umgesetzt: im HTML-Header ist eine PHP-Funktion, die in einem Array alle Javascripts aufnimmt.

statt

<script type="text/javascript" src="/javascript/script1.js"></script>
<script type="text/javascript" src="/javascript/script2.js"></script>
(...)
<script type="text/javascript" src="/javascript/scriptn.js"></script>

heisst es serverseitig neu

include("/php/inc_compress_static.php");
addJS("/javascript/script1.js");
addJS("/javascript/script2.js");
(...)
addJS("/javascript/scriptn.js");
writeJs();

Die erste Funktion macht erstmal noch nicht viel:

function addJs($sFile) {
    global $aJS; $aJS[]=$sFile; return true;
}

Eine Funktion writeJs() sorgt vereinfacht für Folgendes:

  • alle JS Dateien werden in der angegebenen Reihenfolge ausgelesen und zu einer Datei zusammengefügt
  • die gemergte Datei wird gespeichtert (cachefile)
  • im Header wird genau eine JS-Datei (die Cachedatei) referenziert

Die Cachedatei wird dann erneuert, wenn eine JS-Datei neuer als die Cachedatei ist.

Das Resultat der Aktion ist: aus

<script type="text/javascript" src="/javascript/script1.js"></script>
<script type="text/javascript" src="/javascript/script2.js"></script>
(...)
<script type="text/javascript" src="/javascript/scriptn.js"></script>

wird

<script type="text/javascript" src="/~cache/js_cache.js"></script>

Ansonsten sollte man am Webserver veranlassen, Inhalte zu komprimieren und am Client zu speichern. Nachfolgend Beispiele für den Apache Webserver.

  • Mit gzip komprimieren erfordert mod_gzip. Gzip senkt die Grösse der übertragenen Datei mehr, als es reine Javascript-Code-Kompressoren tun. Zudem spart man sich Arbeitsaufwand, komprimierten Code durchzutesten. Beispiel Apache:
    mod_gzip_on Yes
    
  • Caching am Client aktivieren. Einmal zum Client übertragene JS und CSS Dateien können locker 24 h beim Client gespeichert werden.
    ExpiresActive On
    ExpiresByType application/x-javascript "access plus 2 days"
    ExpiresByType application/javascript "access plus 2 days"
    ExpiresByType text/css "access plus 2 days"
    

Für CSS ist die Verfahrensweise analog. Nur muss man beachten, dass man die CSS-Dateien nach Ausgabemedium (Attribut media) zusammenschweisst und je eine Datei erzeugt:

<link rel="stylesheet" type="text/css" href="/~cache/css_cache_screen.css" media="screen">
<link rel="stylesheet" type="text/css" href="/~cache/css_cache_print.css" media="print">

Nachteile beim Mergen von CSS Dateien:
(1)
Urls von Grafiken können relativ angegegben werden. Diese relativen URLs sind nicht relativ zur aufgerufenen Seite, sondern relativ zur Position der CSS Datei. Damit Referenzen auf Grafiken funktionieren, müssen die Pfade absolut (ab Webroot) angegeben sein.
(2)
CSS basierende Stylesheet Switcher funktionieren so nicht mehr. Abhilfe ist einfach: diejenigen CSS-Dateien, die zum Umschalten braucht, lädt man weiterhin mit den link-Attribut.

Links: