Chapter 14. Ant

The choice of a build tool is usually based on the tools familiar to the developers who will be using it. My personal favorite tool for JavaScript build systems is Ant. Ant was originally created as a build tool for Java projects, but its easy XML syntax and built-in tasks make it an excellent choice for JavaScript as well. In an informal survey I conducted prior to writing this book, Ant was by far the most frequently cited build tool used for JavaScript, despite the recent introduction of newer build tools. If you find that Ant doesn’t quite work for you, several alternatives are listed in Appendix B.

This book focuses on JavaScript build systems using Ant, but all of the tools and techniques discussed can be applied to other build systems as well.

Installation

Ant requires Java to run, so make sure that you have Java installed on your system. If you’re using Mac OS X, then Ant is already installed by default; for Ubuntu, run sudo apt-get install ant to install Ant. For other operating systems, following the instructions at http://ant.apache.org/manual/install.html.

The Build File

The main build file for Ant is build.xml. When Ant runs on the command line, it looks for this file in the current directory, so it’s best to place build.xml in the root directory of your project. You needn’t keep all of the build-related information in this file, but build.xml must be present for Ant to work.

As you might expect, build.xml is an XML file containing instructions on how to perform the build. There are three basic parts of an Ant build system:

Task

A single step in the process such as running a program or copying a file

Target

A named grouping of tasks into sequential order

Project

A named container for all targets

Each part of the build system is represented by an XML element. Here’s a sample build.xml file:

<project name="maintainablejs" default="hello">

    <target name="hello">
        <echo>Hello world!</echo>
    </target>

</project>

Every build.xml file begins with a <project> element representing the overall project. The name attribute is required and uniquely identifies this project. The default attribute specifies the default target to execute if no target is explicitly provided.

This file contains a single target, represented by the <target> element. The name attribute is also required here. The <echo> element represents the echo task, which outputs the enclosed text to the console. You can have any number of tasks in a target and any number of targets in a project.

Note

It’s a standard practice to define targets as atomically as possible so they can be combined in any number of ways. Think of targets like you would functions, as a logical grouping of repeated tasks.

Running the Build

Once you have a build.xml file, open a command prompt in that directory and type:

ant

By default, Ant will read the build.xml file and default attribute of <project> to determine which target to execute. If you were to run ant with the build.xml file from the previous example, it would execute the hello target. You can optionally specify which target to run right on the command line:

ant hello

When the target name is specified on the command line, Ant no longer uses the default target.

In both cases, you’ll see console output that looks like this:

Buildfile: /home/nicholas/tmp/build.xml

hello:
     [echo] Hello world!

BUILD SUCCESSFUL
Total time: 0 seconds

The output always shows you the build file being used as the first line. After that, you’ll see the target being executed followed by a list of tasks being executed. The task name is enclosed in square braces; any output is displayed to the right. You will also see a message in capital letters indicating whether the build was successful, followed by the amount of time the build took. These items are all helpful in determining the cause of build errors.

Target Dependencies

Each target may optionally be specified with dependencies—other targets that must be run and must succeed before the current target is executed. Dependencies are specified using the depends attribute, which is a comma-separated ordered list of targets to execute first. Here’s an example:

<project name="maintainablejs" default="hello">

    <target name="hello">
        <echo>Hello world!</echo>
    </target>

    <target name="goodbye" depends="hello">
        <echo>Goodbye!</echo>
    </target>

</project>

In this build.xml file, the target goodbye has a dependency on the target hello. Thus, running ant goodbye results in the following output:

Buildfile: /home/nicholas/tmp/build.xml

hello:
     [echo] Hello world!

goodbye:
     [echo] Goodbye!

BUILD SUCCESSFUL
Total time: 0 seconds

You can tell from the output that the hello target was executed before the goodbye target, and that both succeeded.

In most build files, there are a small number of targets that you’ll use frequently. The majority of targets are single steps that are designed to be used by rollup targets that execute multiple targets in a specific order.

Properties

Ant properties are similar to variables in JavaScript, as they are generic containers for data that can be changed and manipulated throughout execution of the build script. A property is defined using the <property> element:

<project name="maintainablejs">

    <property name="version" value="0.1.0" />

</project>

Each <property> element requires name and value attributes. You can later reference the property by using ${version}, such as:

Version is ${version}

When this Ant script is executed, the output is:

Buildfile: /home/nicholas/tmp/build.xml

version:
     [echo] Version is 0.1.0

BUILD SUCCESSFUL
Total time: 0 seconds

The special ${} syntax is used any time you want to insert a property value into task.

Properties can also be defined in a Java properties files and loaded directly into Ant. For instance, suppose you have a properties file named build.properties containing the following:

version = 0.1.0
copyright = Copyright 2012 Nicholas C. Zakas. All rights reserved.

You can import these properties into the Ant script by using the <loadproperties> element and specifying the filename with the srcfile attribute:

<?xml version="1.0" encoding=UTF-8"?>

<project name="maintainablejs" default="version">

    <property name="version" value="0.1.0" />

    <target name="version">
        <echo>Version is ${version}</echo>
    </target>

</project>

Properties loaded using <loadproperties> are accessible in the same manner as those defined explicitly within build.xml. For a large number of properties, or properties that need to be shared among multiple Ant scripts, it’s best to have them in a separate Java properties file.

At a minimum, it’s best to have several properties declared that can be used throughout your project, such as:

src.dir

The root source code location

build.dir

Where the built files should end up

lib.dir

Location of dependencies

Throughout the rest of this book, you’ll see these properties used in Ant tasks. Be sure to define them appropriately in your project.

Buildr

Buildr (https://github.com/nzakas/buildr) is a project that seeks to collect common frontend-related Ant tasks with easier syntax. A wide range of tools is available for working with JavaScript files, but they all work a bit differently. Buildr wraps all of these different tools in tasks that can be used in your Ant scripts.

To use Buildr, you must first get a copy of the source. Once you have the directory structure on your computer, you can import all of the tasks with this command:

<import file="/path/to/buildr/buildr.xml"/>

This command allows your build.xml file to make use of all the custom tasks defined in Buildr. The following chapters show you both how to create Ant tasks from scratch as well as how to use the Buildr tasks.