Netbeans, JavaScript, Ant, Hudson, and JSLint: Oh my!

I agree with Douglas Crockford on two points he makes in his book:

  • ... JavaScript became the language of the Web by default, making its popularity almost completely independent of its qualities as a programming language ...
  • Most programming languages contain goo⁞d and bad parts, but JavaScript has more than its share of the bad, having been developed and released in a hurry before it could be refined.

The first point is becoming more debatable, as other RIA technologies (including Sun's JavaFX) become more prominent, but let's leave that aside for now.

As for the second point, there is a lot developers can do to make the experience with JavaScript a whole lot better.  Don't get me wrong, JavaScript can be amazing, but it can also be a nightmare.  Part of the nightmare is that the development environments and tools for JavaScript are not yet on par with other environments.  My current project involves writing a whole lot of JavaScript.  We've gone through the usual JavaScript cycles - we've been burned by both programming errors as well as deployment errors.

This blog entry describes how we've integrated JSLint into our Continuous Build/Integration environment, so we can better control the code that we write.  There are other techniques that we've implemented to improve our experience with JavaScript that I'll describe in future blogs:

  • Build time automated concatenation of all the JavaScript files into a single file that has a unique file name, so that it can be cached.  This of course implies automated munging of the .html/.jsp pages that source the JavaScript files...
  • Selenium - for automated testing of our Web UI - eases the fear of writing and refactoring our JavaScript code.

First, download the components that you'll need, and install them in a tools directory somewhere:

  1. Rhino - JavaScript for Java - Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users.
  2. JSLint itself - get this version which is prebundled to work with Rhino.

This blog assumes you already have a Netbeans project created.  Add the following properties to your nbproject/project.properties file.  The CQS prefix that I use is the name of our project, you should change it to match yours.  As for whether you want your build to fail based on whether JSLint passes or not, that's your call, but I highly recommend it, otherwise developers (myself included) will tend to ignore the output of JSLint.

#
# cqs.build.jslint: true/false setting to determine whether to run the
# jslint javascript analysis utility on the individual javascript
# files.  Default is true for production purposes, but developers can
# set it to false in the file private/private.properties.  It is
# highly recommended that this be left to true.
#
# cqs.build.jslint.failonerror: this true/false setting determines
# whether the build should fail or not if jslint detects any errors.
#
cqs.build.jslint=true
cqs.build.jslint.failonerror=true 

Next, define your list of JavaScript files you want to analyze. 

cqs.js.jslint.files=\\
       js/utilities.js,\\
       js/3rdparty.js,\\
       js/tooltipsprop.js,\\
       js/publish2.js,\\
       js/manageusers.js,\\
       js/login.js,\\
       js/detailhtmlformatter.js,\\
       js/staticsearch.js,\\
       js/searchonready.js,\\
       js/mylibrary.js

Another technique others use is to analyze all the .js files in a given directory, this approach is described in various blogs such as this one.  However, we maintain a list of JavaScript files that are required, since this is used elsewhere in our build scripts (e.g. the automated concatenation aspects of our build script use it).

Next, you'll be making a series of changes to your build.xml file.  First, some stuff that we need to define, since we use it later.  The targets use the propertyregex task defined in ant-contrib, so you'll need to define this task in order to use these targets, this needs to come before the target definitions.  I don't know how people used Ant before ant-contrib was made available:

<property name="tools.dir" value="${basedir}/../tools" />
<property name="ant.contrib.jar.file" value="${tools.dir}/ant/lib/ant-contrib-1.0b3.jar" />
<available file="${ant.contrib.jar.file}" property="ant.contrib.jar.file.available" />
<fail unless="ant.contrib.jar.file.available" message="Ant contrib library not installed" />
<taskdef name="propertyregex" classname="net.sf.antcontrib.property.RegexTask">
    <classpath>
        <fileset dir="${tools.dir}/ant/lib" />
    </classpath>
</taskdef> 

Modify the appropriate Netbeans build target to include a "jslint" target:

<target name="-pre-dist" depends="jslint" >
</target>

These are the actual Ant targets for implementing jslint:

<target name="jslint">
    <if>
        <istrue value="${cqs.build.jslint}"/>
        <then>
            <antcall target="doJSLint" inheritAll="true" inheritRefs="true" />
        </then>
        <else>
            <echo message="Not running JSLint - JSLint is disabled." />
        </else>
    </if>
</target> <!-- jslint -->

<target name="doJSLint">
    <echo level="info" message="JSLint: running...." />
    <property name="rhino.jar.file" value="${tools.dir}/rhino1_7R2/js.jar"/>
    <property name="jslint.js.file" value="${tools.dir}/jslint/jslint.js"/>

    <available file="${rhino.jar.file}" property="rhino.jar.file.available" />
    <fail unless="rhino.jar.file.available" message="Rhino Jar file not found - expected at ${rhino.jar.file}" />

    <available file="${jslint.js.file}" property="jslint.js.file.available" />
    <fail unless="jslint.js.file.available" message="jslint.js file not found - expected at - ${jslint.js.file}" />

    <propertyregex property="cqs.js.jslint.files.spacedelim" input="${cqs.js.jslint.files}" regexp="," replace=" "/>

    <echo level="info" message="JSLint: running on ${cqs.js.jslint.files.spacedelim}...." />
    <exec dir="${basedir}/web" executable="java" failonerror="${cqs.build.jslint.failonerror}">
        <arg line="-jar ${rhino.jar.file} ${jslint.js.file} ${cqs.js.jslint.files.spacedelim}"/>
    </exec>

    <echo level="info" message="JSLint: finished running...." />
</target> <!-- doJSLint -->
And that's it!  JSLint will now be run as part of the regular build.  Within Netbeans, you can just "deploy" the project, that will run it.  On the command line, "ant dist" will do the trick.

We use Hudson for continous build/continuous integration, so every time a source file is checked in, a full build, including a JSLint pass, is done.

Comments:

Just out of interest, did you find jslint4java?

http://code.google.com/p/jslint4java/

If you did find it, was there a reason for not using it?

Just curious!

Posted by Dominic Mitchell on June 24, 2009 at 06:45 AM EDT #

Hi Dominic - thanks for the referral, I did not know about it. I gave it a whirl - I especially liked they way you set up formatters so you can get the output in a different way. I modified the code and added a NetBeans formatter, so that I can use NetBeans' next error command to navigate to the source where the issue is. I'll send you the diffs via email (anybody who wants them, feel free to email me).

Posted by Ari Shamash on July 24, 2009 at 09:15 AM EDT #

I am curious - has anyone integrated jslint4java.jar into Hudson? If so I am wondering how they did it. Did they just add a task?

Also - is there a way to throttle certain errors that jslint will report on? I know there are some options but I am curious if I can turn off certain errors from failing the build until we get those fixed and work iteratively on getting all the errors fixed.

Posted by Ryan Alberts on October 12, 2009 at 07:16 AM EDT #

Ryan: I just make it a standard part of the ant build, so it automatically becomes part of hudson. In the last project, I:

\* Renamed "test" to "test-junit"
\* Added a "test-jslint" target
\* Made a new "test" target which does nothing but depend on "test-junit" and "test-jslint"

With regards to toning down jslint's errors, I'd be tempted to simply not hook it up to the main build until you've cleared down the errors to a manageable level.

Posted by Dominic Mitchell on October 12, 2009 at 07:57 AM EDT #

Ryan: To second what Dominic wrote: You should integrate JSLint into your build script. Assuming you use ant for your build scripts, you can follow the template in this blog (which specifically focuses on NetBeans' build scripts, but this can be easily generalized into any ant based build script).

As for setting specific options for jslint, you can do this via the "options" argument. I described how we did this in this blog entry (search for jslint):

http://blogs.sun.com/thelibrary/entry/improved_communications_between_users_and

Specifically, add the "options" argument as follows:

<jslint4java haltOnFailure="${cqs.build.jslint.failonerror}" options="${cqs.build.jslint.options}">
<formatter type="plain" />
<filelist id="jslint.filelist" dir="${basedir}/web" files="${cqs.js.jslint.files}"/>
</jslint4java>

where:

cqs.build.jslint.options=white, onevar, browser, undef, nomen, eqeqeq, plusplus, bitwise, regexp, strict, newcap, immed

You can experiment around with the list of options you are interested in using at http://jslint.com/ . Also, we specifically set "cqs.build.jslint.failonerror" to "true", so that hudson builds break if jslint errors are detected, but you may want to set this to false until you get all your issues resolved.

I would recommend you set the options you ultimately want in your build scripts, and let jslint report issues until you resolve them. This way, you'll know when you are done.

Posted by Ari Shamash on October 13, 2009 at 04:50 AM EDT #

I should have also mentioned that there is an updated entry for integrating jslint into ant based build scripts here:

http://blogs.sun.com/ashamash/entry/integrating_jslint_more_tightly_into

Posted by Ari Shamash on October 13, 2009 at 05:00 AM EDT #

Sun launching new system and will update the code. Revert back to original code maybe.

Posted by Alex on March 22, 2011 at 09:31 AM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Ari Shamash is the software engineering manager of the Sun Software Library engineering team at Sun Microsystems.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today