Optimierung externer Client-Ressourcen durch Ant-Deploy-Prozess

Auf diesem Blog gibt es viele interessante Beiträge, wie man die Performance serverseitig verbessert.
Eine mindestens genauso gute Möglichkeit für eine Verbesserung der Performance ist, es dem Client-Rechner etwas leichter zu machen. Dieser Beitrag soll einen Überblick über die Möglichkeiten dazu geben.

Engpässe finden
Eine sehr hilfreiche Erweiterung ist die Firefox-Extension YSlow. Diese identifiziert Engpässe und gibt im Yahoo!-Developer-Network direkte Anleitungen und Hilfsmittel. Einige sollen hier näher erklärt werden

Der deploy-Prozess
Viele Punkte in YSlow, wie z.B: “Make fewer HTTP requests”, “Gzip components” oder “MinifyJS” können mit dem sogenannten deploy-Prozess erreicht werden. Ein deploy ist eine Methode, die aus den Entwicklungsdateien optimierte Versionen für den online-Einsatz erstellt, z.B. indem Dateien zusammengefasst oder komprimiert werden.

ANT
Ein wunderbares Tool, um den deploy-Prozess umzusetzen, ist ANT. ANT ist ein Java-Tool von Apache Foundation, das entweder als Konsolen-Tool oder aber – was ich wesentlich interessanter finde – als Eclipse-Plugin verwendet werden kann. Verwendet man PHPEclipse, ist ANT direkt vorinstalliert und kann über Window – Show View – ANT eingeblendet werden.

build.xml – Allgemein
ANT wird über eine xml-Datei gesteuert, die build.xml. Diese folgt bestimmten Formalien, damit ANT die Datei versteht. Um die Datei zu verwenden, klickt man in der ANT-View auf die Ameise mit dem grünen Plus daneben und wählt die build.xml-Datei aus. Danach ist der play-Button in der ANT-View aktiv und der deploy-Prozess kann theoretisch starten 🙂

build.xml – Aufbau
Die build.xml ist in sogenannte tasks untergliedert. Damit kann man seinen deploy-Prozess sauber strukturieren.
Hier mal eine beispielhafte build.xml-Datei:

<?xml version="1.0" encoding="UTF-8"?>
<project name="dein_projektname" default="deploy" basedir=".">
    <property name="tmp" location="Pfad/Zum/Temporaeren/DeployVerzeichnis" />
    <target name="deploy">
        <echo message="Dein deploy-Task"></echo>
    </target>
</project>

Mit einer property kann man eine Variable setzen, auf die dann später mit ${propertyName} zugegriffen werden kann.
In einem target kann man jetzt alle beliebigen ANT-Tasks ausführen.

Konkrete Umsetzung
Nun geht es an die konkrete Umsetzung der Aufgaben “Dateien zusammenfassen”, “Minifyen” und “Gzip”.

Dateien zusammenfassen
Dieser Teil hat folgenden Vorteil: während der Entwicklungsphase können z.B. CSS-Dateien auseinander gehalten werden (layout.css, colors.css, forms.css), in der Online-Version muss aber nur eine Datei (general.css) vom Server geladen werden. Das bedeutet weniger HTTP Requests und weniger HTML-Code, um die einzelnen CSS-Dateien einzubinden. Um eine zusammengefasste Datei zu erstellen, wird der concat-Befehl verwendet:

<concat destfile="${tmp}/general.css" force="no" fixlastline="true">
    <filelist dir="pfad/zu/deinen/cssdateien">
        <file name="layout.css" />
        <file name="colors.css" />
        <file name="forms.css" />
    </filelist>
</concat>

Darin gebt ihr die Zieldatei an und welche Dateien zusammengefasst werden sollen. Damit es kein Durcheinander in den Dateien gibt, die Datei am Besten in ein temporäres Verzeichnis (${tmp}) legen.

Minify
Minify entfernt Leerzeichen und Zeilenumbrüche und ersetzt
function meinLangerFunktionsname()
durch
function A()
Das bringt eine Ersparnis von bis zu 70% in der Dateigröße! Und keine Sorge, dass hier was durcheinander kommt 🙂 In aktuellen Projekten von mir werden über 100 JavaScript-Dateien damit gehandelt und es funktioniert 1a.
Um ein Minify durchzuführen gibt es verschiedene Tools, die man mit ANT ausführen kann. Ich verwende das von Yahoo. Dafür müsst ihr yuicompressor und YUIAnt runterladen. Anschließend folgenden Code außerhalb eines tasks in eure build.xml einfügen:

<taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">
  <classpath>
    <pathelement path="pfad/zu/den/tools/yuicompressor-2.3.5.jar" />
    <pathelement path="pfad/zu/den/tools/YUIAnt.jar" />
  </classpath>
</taskdef>

So, jetzt haben wir die technischen Voraussetzungen, um den minify-Prozess durchzuführen. Das geht so:

<yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true" outputfolder="${tmp}">
  <fileset dir="${tmp}/" >
    <include name="**/*.js" />
    <include name="**/*.css" />
  </fileset>
</yuicompress>

Zwischenstand
Im temporären Verzeichnis liegen jetzt die zusammengefassen und minifyten JavaScript- und CSS-Dateien. Sind schon schön klein geworden, oder :-)? Um hier noch mehr an der Größe zu tun, können diese Dateien noch gzip-komprimiert werden.

Gzip-Komprimierung
Hierfür sind keine besonderen Tools notwendig, es reicht eine Zeile:

<gzip src="${tmp}/general.css" destfile="pfad/zu/deinem/htdocs/verzeichnis/general.css"/>

Der Gzip-Vorgang kann leider nicht über ein fileset gemacht werden, sondern jede Datei braucht eine eigene Zeile…

Ergebnis
Die Dateien sind jetzt perfekt für den Online-Einsatz vorbereitet und ihr müsst trotzdem kein bisschen auf Übersichtlichkeit oder andere Strukturierung während der Entwicklung verzichten.
Die fertige build.xml sieht so aus:

<?xml version="1.0" encoding="UTF-8"?>
<project name="dein_projektname" default="deploy" basedir=".">
 
  <!-- Variablen festlegen -->
  <property name="tmp" location="Pfad/Zum/Temporaeren/DeployVerzeichnis" />
 
  <!-- Definition des Minify-Tasks -->
  <taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">
    <classpath>
      <pathelement path="pfad/zu/den/tools/yuicompressor-2.3.5.jar" />
      <pathelement path="pfad/zu/den/tools/YUIAnt.jar" />
    </classpath>
  </taskdef>
 
  <!-- Der deploy-Task -->
  <target name="deploy">
    <echo message="Dein deploy-Task"></echo>
 
    <!-- Die Dateien zu einer zusammenfassen -->
    <concat destfile="${tmp}/general.css" force="no" fixlastline="true">
      <filelist dir="pfad/zu/deinen/cssdateien">
        <file name="layout.css" />
        <file name="colors.css" />
        <file name="forms.css" />
      </filelist>
    </concat>
 
    <!-- Die Dateien minifyen -->
    <yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true" outputfolder="${tmp}">
      <fileset dir="${tmp}/" >
        <include name="**/*.js" />
        <include name="**/*.css" />
      </fileset>
    </yuicompress>
 
    <!-- Die Dateien gzipen -->
    <gzip src="${tmp}/general.css" destfile="pfad/zu/deinem/htdocs/verzeichnis/general.css"/>
  </target>
</project>

Jetzt in der ANT-View in Eclipse play drücken 🙂
Wenn ihr es ausprobieren und nicht Stück für Stück aus diesem Artikel kopieren möchtet, könnt ihr die fertige build.xml auch herunterladen.

Ich hoffe, diese kurze Einführung in die Arbeit mit einem deploy-Prozess und ANT hat euch weitergeholfen.

Christian

strauberry hat 3 Beiträge geschrieben

7 Kommentare zu “Optimierung externer Client-Ressourcen durch Ant-Deploy-Prozess

  1. Jan sagt:

    Genau das ist eben keine Alternative, da das Script ja dann bei jedem Aufruf erstmal die JS-Dateien komprimieren müsste. Das bremst dann eher.
    Wieso sollte der Aufwand für jeden User betrieben werden, wenn er 1 mal nach jeder Veränderung der JS- bzw. CSS-Dateien völlig ausreicht? Und auch fürs Caching ist der hier beschriebene Weg optimal.

  2. strauberry sagt:

    Vielen Dank für Deinen Kommentar Jan 🙂 Genauso ist es. Zudem gibt es noch einige weitere Vorteile: die hier beschriebenen Möglichkeiten von ANT kratzen ja nur an der Oberfläche, man kann z.B. beliebige Tokens in Dateien ersetzen (wenn die Bild-Pfade in CSS auf dem Server z.B. anders heißen müssen).
    Zudem vertrete ich den Standpunkt, dass eine saubere und performante Anwendung im Vordergrund stehen sollte und nicht die “Faulheit” (sorry :-)) des Entwicklers. Zumal zentralisiert die build.xml alle Pfadangaben. Ändert sich etwas, muss also nur die Zusammenstellung der general.css geändert werden, nicht aber der Pfad zur general.css in der ganzen Anwendung…

  3. Meine 2 Cent hierzu: erstmal eine sehr nette Methode, und ANT wollte ich mir eh immer schon mal anschauen…

    Minify ist mittlerweile aber eben nicht mehr so “dumm” wie oben beschrieben. Im Projekt http://code.google.com/p/minify/ ist z.B. mittlerweile ein Caching Layer implementiert, was verhindert, dass minify und Kompression für jeden Neuaufruf erneut ausgeführt werden. Außerdem sendet es korrekte Expires Header. Ich experimentiere damit gerade bei http://sixgroups.com herum (noch nicht live) und bin mit den Ergebnissen bisher sehr zufrieden.

  4. Stefan sagt:

    Genau die von euch genannten Dinge kann minify auch. (Pfadangaben, etc.)
    Das Performance Argument stimmt so auch nicht ganz, denn minify führt die Komprimierung, etc. nur EINMAL durch und cached die erstellten Dateien dann auf dem Server.

    Der ganze Rechenaufwand findet also ledglich nur statt sobald ihr eine der Dateien ändert.

  5. Ignaz sagt:

    Vielen Dank für den Hinweis auf ANT und die Erläuterungen dazu! Das ist eine hervorragende, bequeme, schnelle Lösung, ich setze sie nun in Eclipse ein. – Ein kleiner Fehlerhinweis: Im oben zu sehenden Code (und dementsprechend in der Datei build.xml) darf in Zeile 37 „destfile“ keinen Pfad zum Wert haben; statt dessen muß dort der Name der zu erzeugenden komprimierten Datei stehen, also zum Beispiel „general.css.gzip“.

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>