PDA

View Full Version : JsConcat - ant task for concatenating ExtJS projects



Niels Brouwers
31 Dec 2009, 4:48 AM
I am currently working on a rather large ExtJS project and I was looking at build systems for ExtJS. Specifically I want to concatenate all the js files and run it through some compressor/obfuscator.

Ant is a nice tool which I use for a lot of Java projects, and it works really well for ExtJS stuff too. I drive ext-doc with it, as well as yuicompressor, and concatenating or copying files for deployment is a snap.

The 'concat' task can concatenate files, but I didn't want to have to manually enter a file list as we have a large number of files, especially since we generally have a separate js file for each class. We can't just pass the task a list of all files in our source directory, because inclusion order matters (Ext.extends being the number one load-time dependency).

Therefore, I wrote an Ant task called 'JsConcat' that does some quick parsing to detect dependencies between js files based on @class and @extends comments, sorts the file list, and concatenates them. Example build file:



<!-- Define the 'jsconcat' task -->
<taskdef name="jsconcat" classname="com.zarafa.jsconcat.JsConcatTask">
<classpath path="JsConcat.jar"/>
</taskdef>

<!-- Concatinates JavaScript files with automatic dependency generation -->
<target name="concat">
<jsconcat
verbose="false"
destfile="${debugfile}"
prioritize="\w+, Foo.bar.*"
>
<fileset
dir="${sourcedir}"
includes="**/*.js"
/>
</jsconcat>
</target>


If you're familiar with Ant, it should be pretty clear what this does. If not, go have a look at Ant and read the manuals, it's pretty easy. Essentially, the source directory is scanned recursively and all js files are input into JsConcat.

There's three ways to influence the inclusion order. First, there are explicit dependencies that you can enter in your file:



/*
* This file needs to be included after bar.js
* #depends /foo/bar.js
*/


Then there's the dependencies that are extracted from @class and @extends:



/**
* Foo extends Bar, so the file in which Bar is defined should come before this file.
* @class Foo
* @extends Bar
*/


And finally, formatted as a comma-separated list of regular expressions, the prioritise argument can be used to move groups of files up the list. Files that have classes defined in them have those full class names matched against the regexps. Files that match the first priority group have the highest priority, files that match the second group come after that, and so on. We use this mainly to move the 'core' and 'common' packages to the top of the list.

For example,"\w+, Foo.bar.*" will move all files which have classes in the 'root' package (i.e. 'Date', 'Foo') to the top of the list, after wich come all files which have classes in 'Foo.bar' or any of its descending packages, and finally all the files that match neither of these criteria.

The regular expression format is the standard Java format (http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html).

I appended the source and a compiled version, plus an example build file that can serve as a template in case you want to try it out but don't have tons of Ant experience. The code is fairly simple, but if you have any questions, bugs, or want to make adjustments don't hesitate to ask.

Edit: new version, fixed a small bug cobaltblue came across. :">

hat27533
31 Dec 2009, 5:03 AM
Nice one, if you are using Java to build web apps there are a few others to consider too.

I run my js files through a js lint ant task at build time in netbeans using and the jslint4java (http://code.google.com/p/jslint4java/) ant task, this has saved me hours of debugging especial IE issues. I blogged about it here. (http://nnbs.blogspot.com/2009/09/enough-about-minifying-javascript-what.html)

There are also blog entires (http://nnbs.blogspot.com/2008/11/updated-minified-javascript-and-css.html) regarding minifying too, although I now tend to use JAWR (https://jawr.dev.java.net/) now.

jay@moduscreate.com
31 Dec 2009, 6:30 AM
Moved to Examples and extras

jay@moduscreate.com
31 Dec 2009, 8:06 AM
btw, thanks for the contribution :)

cobaltbluedw
21 Jan 2010, 2:11 PM
This tool looked quite handy, and I was going to use it, but when I try, I get a java.lang.NullPointerException.

target:


<target name="concat-dir">
<echo message="Concatinating all of '${srcFolder}' into '${destFile}'"/>
<jsconcat destfile="${destFile}" />
<fileset dir="${srcFolder}" excludes="${destFile}" includes="**\*.js" />
</jsconcat>
</target>


result:


concat-dir:
[echo] Concatinating all of 'C:\blah\blah\blah\scripts
' into 'C:\blah\blah\blah\scripts\pack.js.concat'

BUILD FAILED
C:\blah\blah\blah\build\catzip.xml:43: The following error occu
rred while executing this line:
C:\blah\blah\blah\build\catzip.xml:53: The following error occu
rred while executing this line:
C:\blah\blah\blah\build\catzip.xml:69: java.lang.NullPointerExc
eption


Any insight?

Niels Brouwers
25 Jan 2010, 3:22 AM
@cobaltblue: can you do a `ant -v` for me and paste the output? That way at I know in which line the thing fails, that way I know whether the problem is with the way the input from Ant is processed, or whether it's a problem with parsing the directives (i.e. @extends, etc).

Niels Brouwers
25 Jan 2010, 3:46 AM
@cobaltblue:

well this is embarrassing, turns out I forgot to initialise the 'prioritise' property to "" :"> I uploaded a fixed version, see original post.

cobaltbluedw
25 Jan 2010, 3:53 PM
Thanks a bunch Niels, I'll be sure to re-implement this when I get the chance! :D