As Frontenders, or front-end engineers, we spend a lot of time in convincing people that we are actual “engineers” so it makes sense that we should leverage tools outside of markup and script to help us do our job. This article is about one of those tools I use, Ant.
I spend a lot of time building applications as well as wireframes (in HTML/CSS/JavaScript) to work out customer requirements and to test interactions with users. Because of this I am constantly doing “boilerplate” tasks, but I don’t need to if I use a little Ant. Ant was originally created as a way to build Tomcat, because of its success the Apache Foundation started using it for almost everything Java. The basic purpose for Ant was to allow a developer to setup, compile, and deploy a Java application. For more details and installation instructions visit the official Ant documentation. What I am going to share here is how I use Ant from a Frontenders perspective.
A little explanation is in order. I have developed a dev template for our development teams, as well as a component library that contains assets, JavaScript, and CSS. These items are tucked away in our Subversion repository, yes Git is great but you work with what you have to (translation – we are not converting 80+ enterprise level apps over to Git anytime soon). From this standpoint here is a brief step by step of how a wireframe, or prototype would start off.
- Checkout current devkit from SVN
- Create a new directory on the local server
- Create directory structure
- Move files from SVN checkout to appropriate directories
- Begin coding
- Concatenate JS and CSS files (sometimes manually)
- Minify JS and CSS
- Deploy prototype
- Rinse and repeat
This is absolutely absurd, to do the same manual tasks over and over. Here comes my friend Ant to save the day.
Here are the steps we take today using Ant:
- Open terminal
- Copy build.xml to a directory (or pull it from scm)
- run command: ant
Done! Everything is setup for us to begin coding. Our dev kit is pulled in from scm, we also have the ability to minify, concatenate, run tests, and deploy all from the command line anytime we want, it’s simple. I like simple. So how is it done?
WARNING – This is a quick and dirty high level overview, don’t be afraid to try it out as it is pretty simple.
After you install Ant everything works off of the build.xml file. You simply place the build.xml file in the directory you want to create your project (this assumes you have Ant installed). From there you will be editing xml.
My basic example of build.xml
<project name="ANTExample" default="init" basedir=".">
<description>
Example build file for base setup
</description>
<!-- set global properties for this build -->
<property name="src.dir" location="src"/>
<property name="build.dir" location="build"/>
<property name="dist.dir" location="dist"/>
<property name="assets.dir" location="assets"/>
<property name="css.dir" location="css"/>
<property name="lib.dir" location="lib"/>
<taskdef name="jsmin"
classname="net.matthaynes.jsmin.JSMin_Task"
classpath="/users/adrian/Development/jsmin/jsmin.0.2.4.jar"
/>
<target name="init">
<mkdir dir="${dist.dir}"/>
<mkdir dir="${src.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${assets.dir}"/>
<mkdir dir="${css.dir}"/>
<mkdir dir="${lib.dir}"/>
<touch file="${src.dir}/app.js" />
<touch file="${css.dir}/app.css" />
</target>
<target name="concatenate">
<concat destfile="${build.dir}/build.js" fixlastline="yes">
<filelist dir="${src.dir}" files="Person.js, Company.js" />
<fileset dir="${src.dir}" includes="**/*.js" excludes="Person.js, Company.js" />
</concat>
</target>
<target name="minify">
<jsmin destdir="./dist" force="true">
<fileset dir="./build/" includes="**/*.js"/>
</jsmin>
</target>
</project>
Say what!? Okay let me explain a few things. Every build.xml file contains a project tag and in that tag you provide a value for the name, default, and basedir attributes. This one is set to be the name of ANTExample and run the init target if I do not specify a specific target after the ant cmd.
What the hell is a target? Targets are basically like commands that you can call from the command line or have other targets depend on. So for instance, if I wanted to simply minify my JavaScript I would type the command “ant minify” and all my JS files found in the build directory would be minified and placed in the destination directory of “dist.”
Okay, where did all these directories come from? When I initially run just the ant cmd with no arguments the default target is run, which was specified in the project tag as init. You will see this below, I even created some basic files with the “touch” cmd.
<target name="init">
<mkdir dir="${dist.dir}"/>
<mkdir dir="${src.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${assets.dir}"/>
<mkdir dir="${css.dir}"/>
<mkdir dir="${lib.dir}"/>
<touch file="${src.dir}/app.js" />
<touch file="${css.dir}/app.css" />
</target>
What’s with all the $ brackety things? The ${dist.dir} and similar are simply variables that reference the parameters at the top of the build.xml file, or as seen here:
<property name="src.dir" location="src"/> <property name="build.dir" location="build"/> <property name="dist.dir" location="dist"/> <property name="assets.dir" location="assets"/> <property name="css.dir" location="css"/> <property name="lib.dir" location="lib"/>
So when the script runs it uses the values set in property tags or as passed in arguments from the command line. Easy peasy, especially since we all tend to use a common structure each time we create a project.
How did you minify the JavaScript? Ant doesn’t minify JavaScript but it can run external programs and call out to them via tasks. In this example I have a target called minify that uses JSMin to minify my JavaScript.
<target name="minify">
<!-- <jsmin srcfile="${build.dir}/build.js" suffix="true" /> -->
<jsmin destdir="./dist" force="true">
<fileset dir="./build/" includes="**/*.js"/>
</jsmin>
</target>
For this to work you need to download the JSMin jar file and point to it on your system. To do this you set up a taskdef as such:
<taskdef name="jsmin" classname="net.matthaynes.jsmin.JSMin_Task" classpath="/users/adrian/Development/jsmin/jsmin.0.2.4.jar" />
You will see that I have the classname and classpath set appropriately. That is all Ant needs.
How do you concatenate? Setup a target for concatenation as seen below:
<target name="concatenate">
<concat destfile="${build.dir}/build.js" fixlastline="yes">
<header>/* Author:Adrian
Title: Why do you do that with your JavaScript
at ${build.time} */
</header>
<filelist dir="${src.dir}" files="Person.js, Company.js" />
<fileset dir="${src.dir}" includes="**/*.js" excludes="Person.js, Company.js" />
</concat>
</target>
Now my concatenation task is an example that allows you to specify the order of files to be concatenated but there are more examples in the Ant documentation.
You mentioned pulling from SCM? Yeah, but in an effort to keep this post light I did not include all of that. This however does show you how to set up a file structure, concatenate and minify.
I know this is brief, but I was inspired to blog about this after reading “Maintainable JavaScript” by Nicholas C. Zakas. I never talked about using Ant with my Front-end friends so I was glad to see he had a section about concatenation using Ant in his book. I also have to thank Jim Priest, as he kept telling me to “blog it!”
Nice! You could batch the build.xml copy / run ant steps so you just run one command
Added to my Ant wiki: thecrumb.com/wiki/ant