With continuing reliance on front-end Javascript plugins and CSS, it's important to keep HTTP requests and file sizes smaller to reduce page load times. On this site, we use jQuery, jQuery Address, a custom application Javascript include, and other plugins. We also use a master CSS file as well as a reset file and other CSS additions for things like @media queries and the like. We can reduce all these file requests to one or two requests by combining them all into one file and minifying them.
We can use a compression tool such as YUI Compressor to handle the minifying, but actually doing the work to compile all those files together and run them through the compressor can be a time-consuming task to perform manually. It'd be great if we had a tool to do that for us. Enter Apache Ant.
Ant is a java-based build automation tool. It can be used to perform a variety of tasks and is ideally suited for building files for web applications. If you're on Mac OS X, Ant comes pre-installed (1.7.x on 10.5 and 1.8.x on 10.6). For other systems, check out the easy instructions here. YUI is a simple download and extraction from here.
All we need for a basic Ant task is a build file. Create a "build.xml" file in the root of your application. To start, you just need some basic markup. I added a property that contains the path to the YUI Compressor .jar file.
<?xml version="1.0" encoding="UTF-8"?>
<!-- project name, default target and base directory -->
<project name="typeoneerror" default="init" basedir=".">
<!-- path to YUI Compressor -->
<property name="yuic" location="/Users/typeoneerror/bin/yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar"/>
<!-- path to build resources -->
<property name="css" location="public/css"/>
<property name="js" location="public/js"/>
<property name="ui_css" location="public/ui/css"/>
<property name="ui_js" location="public/ui/js"/>
<!-- default target -->
<target name="init"/>
</project>
This defines our project build with a default target (one of the actions that will run when we build) called "init". Also, we've defined some properties (paths to YUI and to our CSS and Javascript folder) that we'll use later.
Next, create the first target:
<!--concatenate javascript-->
<target name="concat.js" description="Stick all the JS together">
<concat destfile="build/application.js">
<!-- first concat all the files in the /ui/js directory -->
<filelist dir="${ui_js}" files="jquery.min.js,jquery.address.min.js"/>
<!-- then add our application js file -->
<filelist dir="${js}" files="application.js"/>
</concat>
</target>
This target uses the concat process to concatenate a list of javascript files into a destfile (destination file) build/application.js. This combines everything we're using into one file. The next target will use that file and minify it:
<!--minify javascript-->
<target name="minify.js" depends="concat.js" description="Minify JavaScript using YUI Compressor">
<apply executable="java" parallel="false">
<!-- look for any javascript files in the build dir -->
<fileset dir="build" includes="*.js"/>
<!-- pass arguments to the yui program -->
<arg line="-jar"/>
<arg path="${yuic}"/>
<srcfile/>
<!-- output minified files to our js dir with .min.js extenstion -->
<arg line="-o"/>
<mapper type="glob" from="*.js" to="${js}/*.min.js"/>
<targetfile/>
</apply>
</target>
The depends property defines actions that need to be performed before running the target. Add the minify.js target to the depends property of our default action:
<target name="init" depends="minify.js"/>
When we run the build, init will be run and then minify.js. Of course, concat.js will be run before minify.js since minify.js depends on it.
We add another two targets to concat and minify our CSS. Add another target to the list of targets in the init target. Our final build file looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- project name, default target and base directory -->
<project name="typeoneerror" default="init" basedir=".">
<!-- path to YUI Compressor -->
<property name="yuic" location="/Users/typeoneerror/bin/yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar"/>
<!-- path to build resources -->
<property name="css" location="public/css"/>
<property name="js" location="public/js"/>
<property name="ui_css" location="public/ui/css"/>
<property name="ui_js" location="public/ui/js"/>
<!-- default target -->
<target name="init" depends="minify.js,minify.css"/>
<!--concatenate javascript-->
<target name="concat.js" description="Stick all the JS together">
<concat destfile="build/application.js">
<!-- first concat all the files in the /ui/js directory -->
<filelist dir="${ui_js}" files="jquery.min.js,jquery.address.min.js"/>
<!-- then add our application js file -->
<filelist dir="${js}" files="application.js"/>
</concat>
</target>
<!--minify javascript-->
<target name="minify.js" depends="concat.js" description="Minify JavaScript using YUI Compressor">
<apply executable="java" parallel="false">
<!-- look for any javascript files in the build dir -->
<fileset dir="build" includes="*.js"/>
<!-- pass arguments to the yui program -->
<arg line="-jar"/>
<arg path="${yuic}"/>
<srcfile/>
<!-- output minified files to our js dir with .min.js extenstion -->
<arg line="-o"/>
<mapper type="glob" from="*.js" to="${js}/*.min.js"/>
<targetfile/>
</apply>
</target>
<!--concatenate css-->
<target name="concat.css" description="Stick all the CSS together">
<concat destfile="build/core.css">
<filelist dir="${ui_css}" files="reset.min.css"/>
<filelist dir="${css}" files="screen.css,additions.css"/>
</concat>
</target>
<!--minify concatenated css-->
<target name="minify.css" depends="concat.css" description="Minify CSS using YUI Compressor">
<apply executable="java" parallel="false">
<fileset dir="build" includes="*.css"/>
<arg line="-jar"/>
<arg path="${yuic}"/>
<srcfile/>
<arg line="-o"/>
<mapper type="glob" from="*.css" to="${css}/*.min.css"/>
<targetfile/>
</apply>
</target>
</project>
Running an Ant build file is as simple as shelling into the directory via your Terminal or command line interface and entering ant. It automatically looks for a file called "build.xml". You can also grab Simon Gregory's Ant TextMate Bundle if you want to just hit Cmd+R to build in your TextMate project (awesome).