Javascript applicaties en Apache Ant

ant

Als je wat complexere javascript applicaties aan het ontwikkelen bent dan is het meestal fijn om code te scheiden in verschillende documenten. Dat is met PHP bijvoorbeeld geen probleem maar met javascript wordt dat een stuk lastiger.

Het plaatsen van meerdere script blokken in de pagina is niet heel erg praktisch. Je kan code schrijven die dynamisch bestanden inlaad (zoals bijv. het DOJO framework dat doet) maar dat vind ik in veel gevallen veel te ingewikkeld. Dan blijft er eigenlijk nog maar een optie over en dat is bestanden samenvoegen in een über javascript bestand.

Voor het samenvoegen maken we gebruik van Apache Ant. Het is eigenlijk een tool die gemaakt is om Java-applicaties te compileren maar is flexibel genoeg om hem ook in een webomgeving in te zetten. Daarnaast gebruik ik YUI compressor waarmee je javascript en css bestanden kunt verkleinen. Hoe je moet installeren vind je op de bijbehorende websites.

Configureren

Apache Ant werkt op basis van een XML bestand (build.xml) waarin je de stappen kunt aangeven die moeten worden uitgevoerd. Elk van deze stappen zou je individueel kunnen aanroepen maar de kracht en flexibiliteit ligt in het combineren van deze targets tot een nieuwe target. Zo kun je een aparte debug target en een productie target maken. Zie de Apache Ant handleiding voor meer informatie.

De eerste target init wordt gebruikt om een tijdelijke directory te maken. Waar alle werkbestanden worden opgeslagen. ${tempdir} is een variabele die bovenaan het bestand meegegeven wordt. Zie hieronder.

<target name="init">
	<mkdir dir="${tempdir}"/>
</target>

De target concat voegt de js bestanden samen en plaatst het resulterende bestand in de temp directory. Je kan de fileset en filelist elementen gebruiken om de volgorde te bepalen waarin de bestanden worden samengevoegd. De fileset voegt in dit voorbeeld alle bestanden die in de apps directory staan samen. Daarna worden mbv de filelist het bestand iphone.js en init.js er aan vastgeplakt.

<target name="concat" depends="init">
  <concat destfile="${tempdir}/${outputfile}">
    <fileset dir="${basedir}/apps"
      includes="**/*.js"/>
    <filelist dir="${basedir}"
      files="iphone.js init.js"/>
  </concat>
</target>

De target shrink voert de yuicompressor uit op alle js bestanden die in de temp directory staan. Let op dat je het pad naar de yuicompressor aanpast.

<target name="shrink" depends="concat">
  <apply executable="java" parallel="false">
    <fileset dir="${tempdir}" includes="*.js"/>
    <arg line="-jar"/>
    <arg path="/home/kamiel/tools/yuicompressor-2.4.2.jar"/>
    <srcfile/>
    <arg line="-o"/>
    <mapper type="glob" from="*.js" to="*.js"/>
    <targetfile/>
  </apply>
</target>

De target copy verplaatst de gegenereerde bestanden uit de temp dir naar de juiste plaats.

<target name="copy">
  <copy file="${tempdir}/${outputfile}" todir="${basedir}"/>
</target>

Als laatste stap wordt in de target clean de temp directory verwijdert.

<target name="clean">
  <delete dir="${tempdir}"/>
</target>

Het zou vervelend zijn als we elk van deze stappen individueel zouden moeten aanroepen daarom maken we twee targets (debug en build) die de bovenstaande targets combineert.

<!-- default build -->
<target name="build" depends="init,concat,shrink,clean"/>

<!-- Debug -->
<target name="debug" depends="init,concat,copy,clean"/>

De build file heb ik in de directory geplaatst waar al de bron js bestanden staan en ziet er zo uit:

<?xml version="1.0" encoding="UTF-8"?>
<project basedir=".">
  
  <property name="tempdir" value="${basedir}/temp"/>
  <property name="outputfile" value="martinet.js"/>
  
  <target name="init">
    <mkdir dir="${tempdir}"/>
  </target>
  
  <target name="concat" depends="init">
    <concat destfile="${tempdir}/${outputfile}">
      <fileset dir="${basedir}/apps"
        includes="**/*.js"/>
      <filelist dir="${basedir}"
        files="iphone.js init.js"/>
    </concat>
  </target>
  
  <target name="shrink" depends="concat">
    <apply executable="java" parallel="false">
      <fileset dir="${tempdir}" includes="*.js"/>
      <arg line="-jar"/>
      <arg path="/home/kamiel/tools/yuicompressor-2.4.2.jar"/>
      <srcfile/>
      <arg line="-o"/>
      <mapper type="glob" from="*.js" to="*.js"/>
      <targetfile/>
    </apply>
  </target>
  
  <target name="clean">
    <delete dir="${tempdir}"/>
  </target>
  
  <target name="copy">
    <copy file="${tempdir}/${outputfile}" todir="${basedir}"/>
  </target>
  
  <!-- default build -->
  <target name="build" depends="init,concat,shrink,clean"/>
  
  <!-- Debug -->
  <target name="debug" depends="init,concat,copy,clean"/>
  
</project>

Uitvoeren

Het uitvoeren van de build is nu heel gemakkelijk. Ga naar de directory waar je het build bestand hebt opgeslagen en voer op de command line ant gevolgd door de naam van de target die je wilt uitvoeren.

# Voert een standaard build uit
ant build

# Voert een debug build uit (geen yui compressor)
ant debug

Meer mogelijkheden

Apache ant is een vrij uitgebreide tool en kan nog voor veel meer zaken gebruikt worden waaronder het publiceren van een applicatie naar een server met bijv. ftp, scp, rsync. Voor meer ideeën zie Building web applications with Apache Ant.

Foto genomen door Jeff Kubina

Categorieën: PHP javascript