Using Ant to Build a JavaScript Library

Using Ant to Build a JavaScript Library

Tutorial Details
  • Difficulty: Intermediate
  • Completion Time: 45 mins

Applications all seem to have a build version number, don’t they? Anywhere you look for advice about managing a large software project, you’ll find that an automated build process is virtually a requirement. I have found it essential to automate a build process that concatenates and minifies the files needed for a given page. This tutorial will de-mystify the Ant build tool and show you how to create your own, flexible, build files for a JavaScript library.


Software Requirements

For this tutorial, you will need NetBeans with Ant installed. I often use:

  • NetBeans 7.0.1 for PHP projects – Ant version 1.12.1
  • NetBeans 7.1 for JSP projects – Ant version 1.14.1

The Ant tool in the PHP version is a slightly limited version, but is ideal for our purposes, because the PHP projects are not complicated with an automatically generated build file. So for this tutorial, I will demonstrate with the PHP version. However, Ant is of course available at Apache and is widely used in IDEs, like Eclipse. For the .Net C# community, there is a tool called Nant, which I use in my .NET projects – it’s quite similar.


Rationale: Why Build?

In my first serious attempt at creating a one-page Ajax application, I ended up with a list of nearly 40 script tags that produced a start-up time of over a minute. To make the project manageable, I needed to contain the code in multiple modules, not to mention all of the YUI modules that were required. After reading blogs written by the YUI team, I realized how important it is for performance to reduce the number of script tags to as small a number as possible. Hence, my interest in concatenating and minifying JavaScript files.

Combining multiple files reduces the extra bytes from HTTP headers as well as potential transfer latency caused by TCP slow starts, packet losses, etc.
YUI Blog: Performance Research, Part 6

Why Ant?

Lajos Moczar’s excellent Tomcat 5 Unleashed had a huge influence on my attitude to developing a complete web-based application. It’s much more than a book about Tomcat. It gave me the motivation, guidance and courage to start using Ant to build my JSP projects. Ant is built into NetBeans, my favourite IDE for JSP, and I got used to using the automatically generated build file with little need for manual editing when building a Java package of classes. However, as my understanding of JavaScript grew, I found that I needed a build process and was forced to write my own build configuration files manually just for the JavaScript part of the project. Moczar’s build.xml for a Tomcat application gave me a great starting point.

Having a good development environment is absolutely critical to the success of your development efforts. You need a structured environment that allows you to execute your build processes in an efficient and repeatable fashion.
- Lajos Moczar, Tomcat 5 Unleashed

Editor’s Note: If you decide against using Ant, Grunt is a fantastic build tool for your JavaScript applications. Learn more about it here on Nettuts+.


Step 1: Setting Up Your Environment

Open a new project in NetBeans. I’ve called mine NetTutsBuildJs, and have created it inside my Nettuts+ folder here: C:\NetTuts\BuildJs. Obviously, JavaScript doesn’t need to be compiled into an exe file; we have different concerns. There are at least three things that we need for a large JavaScript project:

  • Develop Source: Create a bunch of modules in separate files. This is our source code.
  • Concatenate: Collect all the source files you need for a particular page and concatenate them into one file.
  • Minify: Minify files using a well-know minifying tool to make them as small as possible. I prefer the YUI Compressor tool.

As you can see in the screenshot, I have created a folder, called js for my JavaScript, and then added the folders, src, concat and min.


Step 2: Ignore World

I am a bit bored with saying “Hello World” at the beginning of every new IT tutorial, aren’t you? So I thought it would be nice to ignore the world this time. After all, it might be just a figment of my imagination!

I’m a solipsist. Why aren’t there more of us?

  • Right-click the context menu on the Source Files folder and add a new XML document, called build.xml.
  • Remove all the automatic template text and type in this text:
<project name="NetTutBuildJs"  basedir=".">
</project>

You might not notice anything now, but if you restart the IDE, you will see that build.xml now has a special icon with a yellow triangle associated with Ant files. If you select it, you will see the navigator panel now displays Ant Targets in its header.

Each set of tasks in an Ant build file is called a target, so we need to create a simple message target
nested inside the project tag, like this:

<target name="ignore-world-message">
    <echo message="World. You may be a figment of my imagination."></echo>
</target>

Now, expand the build.xml file in the Project panel and you will see the new target in the Navigator panel. Right click on ignore-world-message and you should see the message in the Output panel, like this:


Step 3: Sort Out Paths

Right. The world may not exist and we have ignored it, but at least Ant seems to be working! Joking apart, we now have to get the most crucial thing in Ant right: paths.

I may be a bit slow, but I always had trouble with this, so let’s tread carefully. Add a property to the top of the file, just below the project tag. Call the property root and set the location to a zero-length string.

<property name="root" location="" />

Add a new target to display this location so that we can ensure that we’ve got our paths straight. Notice the convoluted syntax to refer to the root property? You need to enclose the property name inside double quotes, but, in addition, you have to wrap it with a dollar sign and a curly brace on the left, then close it with a curly brace on the right. What a fuss!

<target name="show-root-path">
<echo message="${root}"/>
</target>

You could put that after the ignore-world target. Now when you right-click the show-root-path target to show the context menu and then click “Run Target,” you should see the correct path to the root of your project. In my case: C:\NetTuts\BuildJs.


Step 4: Add Other Paths

Lovely. We’ve got our environment and we’ve got a root path pointing to the right location on our hard drive. Now we can add the other paths.

<property name="js" location="${root}/js" />
<property name="src" location="${js}/src" />
<property name="concat" location="${js}/concat" />
<property name="min" location="${js}/min" />

Step 5: Concatenating the Files

At last, some real work. We add a new target, which includes a concat tag, like this:

<target name="concat">
<concat destfile="${concat}/tree-concat.js" encoding="UTF-8" >
<filelist dir="${src}"
files= "tree_data.js,
tree.js"
>
</filelist>
</concat>  
</target>

This is just a trivial example, but for quickness so that you can follow along, I’ve created two simple JavaScript files: tree_data.js and tree.js, which depend on the YUI files, yahoo-dom-event.js and treeview-min.js. tree_data.js has the following rather meaningless contents:

var treeData = [{
    "label": "Britain",
        "children":[
            "London",
            "Edinburgh"
        ]
    },{
    "label": "France",
        "children":[
            "Paris",
            "Lyon"
        ]
    },{
    "label": "Japan",
        "children":[
            "Tokyo",
            "Kyoto"
        ]
    },{
    "label": "Thailand",
        "children":[
            "Bangkok",
            "Pattaya"
        ]
}]

And tree.js simply renders a TreeView with that data.

YAHOO.util.Event.onDOMReady(function(){
    var  tree = new YAHOO.widget.TreeView("tree", treeData);
    tree.render();
});

Notice that the filelist tag is exactly what we need here. In JavaScript, order matters, so we probably want the data first and then the rendering file second. If we used a tag that relied on the natural order of the files in the operating system, we might get them in the wrong order. So, we laboriously type out the list manually in a filelist tag to ensure the order we want.

For you JavaScript purists out there: I know my treeData variable is a global variable and I should do it a different way. This is just a quick example to explain how to use Ant. I’m quite sure the people following the tutorial are also following current best practices for their JavaScript library.

Now run the concat target. Lo and behold, a file called tree-concat.js magically appears in the concat directory, and, when you open it up, you can see the data defined at the top and the rendering function at the bottom.

To try this out, I’ve created two simple html files: tree_src.html and tree_concat.html. In the header, they both have the same links to the CSS files needed to create the Sam skin for a TreeView.

<link rel="stylesheet" href="js/yui/fonts-min.css">
<link rel="stylesheet" href="js/yui/treeview.css">
<link rel="stylesheet" href="js/yui/treeview-skin.css">

Just before the end of the body in tree_src.html, I’ve added

<script src="js/yui/yahoo-dom-event.js"></script>
<script src="js/yui/treeview-min.js"></script>
<script src="js/src/tree_data.js"></script>
<script src="js/src/tree.js"></script>

To test the concatenated file. I’ve changed the script tags in tree_concat.html to:

<script src="js/yui/yahoo-dom-event.js"></script>
<script src="js/yui/treeview-min.js"></script>
<script src="js/concat/tree-concat.js"></script>

Step 6: Final Stage: Minifying

Our tree library seems to be working, and, when we concatenate the files, we seem to have gotten the right order. Excellent! It’s now finally time to minify everything and reduce the number of script tags down to one. This is a bit more complicated.

    <target name="min">
        <apply executable="java" parallel="false" dest="${min}" taskname="yui">
            <fileset dir="${concat}">
                <patternset>
                    <include name="tree-concat.js"/>
                </patternset>
            </fileset>
            <arg line="-jar"></arg>
            <arg path="${compressor}"></arg>
            <arg line="--charset UTF-8"/>
            <arg line="-v"></arg>
            <srcfile/>
            <arg line="-o"></arg>
            <mapper type="glob" from="*-concat.js" to="*-min.js"></mapper>
            <targetfile/>
       </apply>        
    </target>

Notice the property compressor. To get this all to run, I copied the YUI compressor jar file to the yui_compressor folder in my project and created a property in the build file:

    <property name="compressor"  location="${root}/yui_compressor/yuicompressor-2.4.2.jar"/>

When we run the min target, you should now see this output and a new file, called tree-min.js in the min folder. If you open it, you’ll see a long continuous stream of JavaScript with no whitespace, all on one line.

There’s just one more target needed: concatenate the two YUI files with our new minified file.

    <target name="all">
        <concat destfile="${min}/all-tree-min.js" encoding="UTF-8" >
            <filelist dir="${yui}"
                files= "yahoo-dom-event.js,
                treeview-min.js"
                >
            </filelist>
            <filelist dir="${min}"
                files= "tree-min.js"
                >
            </filelist>
        </concat>  
    </target>

In the test file, tree_min.html, I now only need one script tag:

<script src="js/min/tree-min.js"></script>

Step 7: One-Click Build

The final step is to add a target that calls all the necessary targets and runs them in the correct order. The convention is to call this target, build. It’s also useful to have a clean target to delete the concat and min directories, and an init target to set up those directories.

    <target name="clean">
        <delete dir="${concat}"/>
        <delete dir="${min}"/>        
    </target>
    <target name="init">
        <mkdir dir="${concat}"/>
        <mkdir dir="${min}"/>        
    </target>

The build target should now run:

  1. clean
  2. init
  3. concat
  4. min
  5. all

The way to combine all these is to simply add them to the depends attribute, like this.

<target name="build" depends="clean, init, concat, min, all">    
</target>

Conclusion

We walked through the steps required to create a configuration file for Ant to build a JavaScript library.

In this tutorial, we walked through the steps required to create a configuration file for Ant to build a JavaScript library. Starting from the source code, we concatenated all the files in the library into one file, ensuring that each of the source files is added in the correct order. We tested the resulting concatenated file to ensure that nothing was missing or out of place. We then minified that file and concatenated it with the YUI files it depended on.

The final result was that we had a web page with only one script tag, containing all the complex JavaScript needed to run the page. I think you can see how easy it would be to adapt this example to a very large complex JavaScript library. With this basic example as a starting point, you should be able to explore the Ant documentation and develop a fully working build file to automate every part of your build process.

I also use Ant for SQL to build the local clone of my database.

Additionally, I use this kind of build for CSS files as well. They can become almost as convoluted as the JavaScript files and it really helps to concatenate and minify them too. I also use Ant for SQL to build the local clone of my database. I find that when I want to start afresh with a project, cleaning out all the experimental code and starting from scratch, it’s really useful to bring along a nice fresh new database. The Ant tool makes it easy to quickly build the tables, functions and procedures, then populate the thing with some sample data.

Tags: ant
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.antsmagazine.com/ Unaiz

    Thanks for this excellent tut..

    • David Mann
      Author

      Thanks Unaiz. This is my first tutorial for NetTuts and your comment is the first comment I’ve received, so thanks for making it so comment.

      • David Mann
        Author

        My reply to Unaiz should have read: “Thanks Unaiz. This is my first tutorial for NetTuts and your comment is the first comment I’ve received, so thanks for making it so positive.”, but I can’t edit it.

  • Andrea

    We want more about JSP :)

    • David Mann
      Author

      Andrea, there are so many good tutorials and books out there giving guidance about JSP. What aspect of JSP are you most interested in?

  • Razvan

    It seems that step by step all Java techniques and technologies are going to be used in the development:ant build, dependency injection, etc.

    • David Mann
      Author

      Ant requires a Java environment to run the build process, but the final concatenated, minified JavaScript file is completely independent of that and it can be deployed wherever you need it in a web application.

  • Jared

    “I’m a solipsist. Why aren’t there more of us?”

    - brilliant :-)

  • http://kingluddite.com Pip

    Three items that might prove useful to others in order to complete this tutorial:
    1) How to add a plugin to Netbeans:
    You need to add Ant. Go to: Tools > Plugins.
    Then click the available plugins.
    Use the search box to search for Ant.
    Select it and add the plugin.

    2) In your build.xml you need to add this property to include your yui stuff (I just added it after the ‘min’ property and before the ‘compressor’ property:

    3) The link to the html:
    Should not be this:
    Should be this:

    Overall, a great tutorial that opened my eyes to how Ant can save me time and that NetBeans, while not as sexy as Sublime Text 2 it still offers some nifty features.

    Thanks for taking the time to write about this useful topic.

    • http://kingluddite.com Pip

      Here is the yui property (addresses point 1 listed above)

    • http://kingluddite.com Pip

      Here is the yui property (addresses point 1 listed above)
      <property name=”yui” location=”${js}/yui” />

      I guess the fourth time is a charm

    • David Mann
      Author

      Just watched your screencast on your blog explaining how to add the Ant Plug-in to NetBeans. People can easily reach just by clicking on Pip above your comment. That’s a really useful addition to my tutorial. Thank you Pip. It’s really clear and simple the way you explained. I’m afraid I set up my NetBeans quite a while ago to develop in PHP and probably installed Ant on automatic pilot then forgot about it. I’m assuming you followed the tutorial with the PHP version of NetBeans. I’m pretty sure if you use the NetBeans version set up for building JSP/Tomcat projects, Ant really is already set up because it’s an important tool for the way NetBeans builds JSP projects.

    • http://kingluddite.com Pip

      darn, they keep removing my html snippets…
      3) the link to html should be this:
      <script src=”js/min/tree-min.js”> </script>

      instead of this:
      <script src=”js/min/tree-min.js”> </script>

      • http://kingluddite.com Pip

        I wish I could edit my past comments… sorry for the comment bombardment but I messed up point 3 again

        it should be this:
        3) the link to html should be this:
        <script src=”js/min/all-tree-min.js”> </script>

  • http://kingluddite.com Pip

    Here is the yui property (addresses point 1 listed above) {They say the third time is a charm :) )

  • Kernkonzentrat

    Funny – yesterday I built nearly the same workflow inside of Sublime Text 2 (as System Build). Nevertheless great tut (if I only read it earlier instead of getting headaches over de-mystifying Ant on my own ;)…)

  • http://tuts.guideplease.com Dilawer Pirzada

    I’m very thankful to your for this article!

  • http://www.codedevelopr.com/ Jason Davis

    For the PHP users, there is Phing which is largely based off Ant. You can find some tutorials about it on nettuts by Jeffrey Way as well

  • http://www.linkedin.com/in/vgrigory vgrigory

    Thanks a bunch for great useful, working tutorial :)

    Very excited about this tool.

    Thanks again for demistifying :)

  • Marko Jozic

    I recommend to work with Eclipse for PHP-Developers (Eclipse – PDT) :-)

    • David Mann
      Author

      Marko, I tried Eclipse for Java and never really got comfortable. I always found NetBeans easier for JSP and other Java work. I was delighted when I found a PHP version of NetBeans. Each to his own, I suppose. It’s true NetBeans 6 had some performance issues, but this latest version 7 is really smooth. For JavaScript I often go back to Aptana (basically Eclipse with a plug-in) and I really like that.

  • http://lacomunidad.elpais.com/diseno-y-creacion-web/ Julia

    Wow! Amazing tutorial, I need time to study it.
    Thanks

  • Tim Down

    I’ve used Ant for building JavaScript libraries in the past, notably log4javascript and Rangy. I have since moved to a JavaScript build script running in Node.js, and while Node.js is inappropriate for the task in some ways (the asynchronous model is completely unhelpful for a single linear build script), it is very appropriate in a one crucial way: modern JavaScript tools (minifiers, linters, test frameworks) integrate with it. I consider my current build mechanism vastly superior, for the following reasons, among others:

    1. The build script is written in the primary programming language of the project
    2. Integration with superior minifiers such as UglifyJS
    3. Integration with linters such as JSHint
    4. Integration with other JavaScript tools such as test libraries
    5. Build logic is done with the power of a programming language rather than a deeply clunky and limited XML syntax
    6. Shorter build file
    7. Can use and create reusable JavaScript functions
    8. Avoids backslash escaping nightmares in regular expression replacement

    Despite many years of Ant use, and the fact that I’m a competent Java developer, I am enormously more productive and fast creating a build script for JavaScript using Node.js than Ant and my results are better. I would strongly recommend it.

    • David Mann
      Author

      Thanks Tim for your useful recommendation and clear, convincing rationale. I’ve become more aware recently of discussions like this and maybe it’s time to move to a build tool that is native to the programming language I’m using for the application instead of configuration files written in XML. For me, Ant (and Nant for .NET applications when I was working with version 2) worked well because it was easier to integrate with the tools I was using for the server side component of the application. In other words, the client-side and server-side were unavoidably different environments, so it was nice that the build tool was shared. Having said all that, perhaps because I’m used to it, I relish the clear and simple control over the build process that Ant gives me. I’ve been learning to use Visual Studio 2012 for .Net 4.5 recently and miss the direct access to the build configuration that I’m used to with Ant.

    • David Mann
      Author

      Tim, just looked up your profile in Stackoverflow. I think with your reputation it would be fair to call you an “advanced” developer. This tutorial was aimed at “intermediate” – in other words, someone who’s created some kind JavaScript application (probably because of a move to Ajax environment) and found the need for a build process for their growing mountain of JavaScript modules. If they are already working in an IDE that has Ant built in or easily added, like NetBeans of Eclipse etc, then I think I would continue to recommend an unambitious configuration of Ant such as the approach I’ve recommended. When we reach your dizzy heights, I can see where the tools you recommend will become more appropriate.

      • Tim Down

        David,

        Fair enough, I see what you’re saying. It’s true that the projects I work on now are more JavaScript-focussed than those I used to work on, and bolting on a completely different JavaScript build technology onto an existing Java or .NET project that already uses Ant / NAnt is likely to be overkill in many cases.

        Regarding IDE support, IntelliJ (along with other JetBrains IDEs built on the same platform) has a Node.js plug-in that works quite well and makes it trivial to launch a Node build script with a single click.

  • http://jsser.com jsser

    why not grunt
    why not grunt
    why not grunt
    why not grunt
    why not grunt
    why not grunt

    • David Mann
      Author

      Why repeat?
      Why repeat?
      I recognise that grunt is the new kid on the block and Ant is long in the tooth, but Ant is just sitting there in my favourite IDE, and I’m not fond of the command line. It concatenates, and I’ve figured out how to run my favourite minifier – I don’t need much more from my build tool for my purposes. I want to point my mouse from within the IDE I’m working in and do my JavaScript build from there. I admit, It would be nice to run something like JSLint as part of the build process, and grunt seems to have the advantage there, but is there an easy way to integrate grunt into, for instance, NetBeans as a plugin so that I can stay away from the command line?

  • Junaid Qadir

    Can you plz guide me on how can i make my build system re-usable for multiple projects?

    • David Mann
      Author

      I’m guessing what you mean exactly. Do you want to run basically the same build routine for a lot of similar projects?

      If so, I think you should think about the paths you set up in your build file. Very near the top of my sample build file for this tutorial I set a root property

      That property is using a relative value for root because I find it simplest just to copy and paste my build file from project to project and just tweak a few values where a new application has slightly different needs. So I have my build file inside the directory structure of the project.

      You could have a separate project with a build file that has multiple root properties

      root_proj1

      root_proj2

      etc

      and use absolute values for the path. On a Windows machine the root_proj1 might look like this:

      You could then set multiple build targets each of which point to a different root.

      Personally, I think this is all getting a bit complicated and I honestly think it’s easier to copy a successful build file and paste it in to a new project and then adjust to suit. Every project is slightly different and you have to maintain the build file for each one anyway. Combining them into one giant complicated build file seems counter-productive to me.

  • KG

    Hi David,

    What is your twitter or email address. I can’t seem to find you anywhere.

    • David Mann

      Sorry KG, I haven’t monitored these comments for a while because I thought the comments had finished. I really value privacy so don’t really get involved in social media much. You could contact me via my company’s website at webmaster@sumikin-intercom.com