JavaScript Dateien effizient übertragen mit GZIP, PHP und Apache


Wenn man diese schönen JavaScript Bibliotheken, wie z.B. jQuery, nutzt, dann steht man schnell vor dem Problem, dass man ein Dutzend JavaScript Dateien laden muss, um die Seite korrekt angezeigt zu bekommen. Wenn man dann den Webserver falsch konfiguriert hat werden die Dateien alle unkomprimiert übertragen. Ausserdem muss der Browser für jede Datei den Webserver fragen. Und wenn man dann auch noch das Caching falsch konfiguriert hat, dann werden für jeden Seitenaufbau alle JS Dateien neu geholt.

Ob man sein System richtig Konfiguriert hat lässt sich sehr schön mit dem Firefox Plugin Firebug beobachten. Wie das geht bleibt dem geneigten Leser als Übung überlassen, denn mir geht es hier hauptsächlich um die Lösung dieses Problems.

Nach Monaten intensiver Recherchen und langen Versuchsreihen bin ich auf folgende Lösung gestoßen: Anstatt die JS Dateien direkt herunterzuladen, kopiere ich einfach den Inhalt von allen Dateien on-the-fly in eine Große. Diese wird dann hübsch komprimiert und mit den notwendigen HTTP Headern ausgestattet, damit das Caching auch funktioniert. Irgendwann hat sich folgendes PHP Script als optimal herauskristallisiert:

<?php 
// License: none (public domain) 
/*
 * Dieses Script concateniert mehrere Dateien und schickt sie gzip
 * komprimiert an den Browser. 
 * Ausserdem wird ein Etag gesetzt, der nötig ist, um das Cachen der 
 * Javascript Datei zu ermöglichen. Der Etag ändert sich jedesmal, wenn 
 * eine der Dateien geändert wird, oder eine hinzu-/weggenommen wird. 
 */ 
header('Content-Type: text/javascript');
header("Expires: ".gmdate("D, d M Y H:i:s", time() + 3600*24)." GMT");

/*
 * Hier die JavaScript Dateien angeben:
 */
$files = array(
    "jquery-1.4.2.min.js",
    "ui.core.js",
    "ui.dialog.js",
    "ui.draggable.js",
    "ui.resizable.js",
    "jquery.textarearesizer.compressed.js"
);

$md5 = '';
foreach ($files as $file)
{
    $md5 .= md5_file($file);
}

$etag = md5($md5);
header("Etag: $etag");

if ( isset($_SERVER['HTTP_IF_NONE_MATCH'])
  && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
{
    header('HTTP/1.1 304 Not Modified');
}
else
{
    if ( isset($_SERVER['HTTP_ACCEPT_ENCODING'])
      && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip") !== false )
    {
        ob_start("ob_gzhandler");
    }
    else
    {
        ob_start();
    }

    foreach ($files as $file)
    {
        echo file_get_contents($file);
    }
}
?>

Vorgehensweise:

Lege eine Datei ‚js.php‚ in dem Ordner mit den JavaScript-Dateien an. Kopiere obigen Code in die Datei. Ändere das $files Array so, dass deine JavaScript-Dateien da drin stehen. Füge folgenden Script-Tag in deinen HTML-Code ein:

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

Das ganze funktioniert natürlich auch mit CSS-Dateien, wobei man dann den Content-Type auf text/css ändern muss.

Advertisements

4 Kommentare on “JavaScript Dateien effizient übertragen mit GZIP, PHP und Apache”

  1. […] das richtige Zusammenpacken der JS-Scripte verwende ich diesen Code von […]

  2. Benjamin sagt:

    Vielen Dank für den schönen Code! Ich nutze ihn für meinen neuen Service LiModu (http://www.LiModu.com) und bin sehr zufrieden! Habe dich auch im Blog erwähnt.

  3. Steve sagt:

    Hallo,
    danke für den Code!!
    Hier eine kleine Verbesserung, da es so bei mir zu einem Fehler kam, da in einer meiner Javascript-Datei folgender String vorkommt: „?>“
    Somit wurde die obige PHP-Datei geschlossen.

    Besser ist daher, folgende letzte foreach-Schleife mit folgender Schleife zu ersetzen:

    foreach ($files as $file)
    {
    $str_file = file_get_contents ($file);
    echo $str_file;
    }

    Grüße,
    Steve


Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s