Mavenizing Javascript Projects

Installing an automatic build process for your projects is very common today and best practice. In the java world Maven is a very popular build tool and has proven its matureness over the years. In this blog post we will show you the benefits of a Maven build and how we can utilize them for javascript projects. Finally we present two maven archetypes for creating ready to go fully mavenized javascript projects for your first steps.

Automatic build process, what is it all about ?

Installing a maven build process will bring various benefits for your daily development. But what are these benefits and what are they good for ?

Running your tests automatically

Having a large testbase for your javascript code is a good and necessary requirement of being able to handle modifications on your code base like refactorings. Furthermore, tests will strengthen your confidence in your own code. But the full benefit of existing tests can be utilized best if  they are run automatically on a regular base.

Generating code documentation

Documenting your code is another good practices for developing. If you develop some kind of javascript library you want to document the api to make it useable by your targeted audience. The generation of your api documentation should be part of the build process.

Running static code analysis

Static code analysis will help you to find potential problems in your code. Bugs might be identified and breaking code conventions can be detected early.

Compression of js and css files

For deploying your javascript to the runtime environment (e.g. a webserver) a good performance tuning trick is to use compressed versions of javascript and css files. Most of the common javascript libraries (like jQuery) are providing a development and a production version of their javascript files, improving loading times in the production environment. So the javascript and css files provided by ourself should be available in a compressed version as well.

Aggregated collection of your project documentation

Having automatically running tests, created api documentation and code analysis tools we have to deal with a lot of informations these tools providing us. So we would like to have a single point of entry to see the result of all the automatically running tools.

Continuous integration

The big advantage of having an automatic build process is the ability to do continuous integration. Having a continuous integration server like hudson your are able to run a complete build including tests, code analysis etc automatically on a separate machine. Whenever a developer is checking in some code, a complete build is started on the continuous integration server and feedback about that build is published immediately. So the most recent status of the project is visible at any time.

Introducing Maven to the javascript world

Mavenizing a javascript project is not much different than doing a regular java project.
Like in java projects the source files of your javascript project should be provided in a similar folder structure like this:

.
|-- pom.xml
`-- src
    |-- main
    |   `-- javascript
    |       `-- quickstart.js
    `-- test
        `-- javascript
            `-- quickstartTest.js

We have two different source folders, one for the productive code and one for the tests only.

The pom.xml file contains all the maven configurations which are necessary to meet our goals defined in the last section.

Since javascript source files are not supported in maven in the first place we have to add the new javascript source folders as a maven resource:

...
<build>
  <resources>
    <resource>
      <directory>src/main/javascript</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
...

Since the javascript folder is now a declared resource location, the content is automatically copied to the generated maven artefact. Furthermore you can now use the maven filtering mechanism to alter the finally generated javascript file as you wish. For instance here you can insert license header to each of your source files, if you want.

At this point we are able to produce a maven artefact, a jar-file, which contains the javascript source files. For integrating all the remaining tasks like test execution or compression we have to rely on different maven plugins to do so.

Behavior driven testing with Jasmine

For javascript there are some good testing frameworks with different approaches available. With Jasmine you can write your tests in a behavior driven way. Your test implementations are more readable and it makes just more fun to write them.
Here is a little example to get the initial idea:

describe('The quickstart object',function()
{
    it('adds two numbers',function()
    {
        var result = DE_AKQUINET.quickstart.addNumbers(1, 4);
        expect(result).toBe(5);
    });
});

To include the automatically execution of your jasmine tests the jasmine-maven-plugin is provided.

Your written javascript test files are located into the maven like folderstructure:

src/test/javascript

additional javascript files (f.i. needed javascript libraries like jQuery) will be placed under

src/test/javascript/lib

The following plugin-entries in your pom.xml is all you need to activate the automatic test execution:

...
<plugins>
  <plugin>
    <groupId>com.github.searls</groupId>
    <artifactId>jasmine-maven-plugin</artifactId>
    <version>1.0.1-beta-6</version>
    <executions>
        <execution>
            <goals>
                <goal>generateManualRunner</goal>
                <goal>resources</goal>
                <goal>testResources</goal>
                <goal>test</goal>
                <goal>preparePackage</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <jsSrcDir>src/main/javascript</jsSrcDir>
        <jsTestSrcDir>src/test/javascript</jsTestSrcDir>
        <preloadSources>
            <preloadSource>lib/jquery-1.4.4.min.js</preloadSource>
        </preloadSources>
    </configuration>
  </plugin>
...

After that the tests are executed by default:

$ mvn install
...
[INFO] Executing Jasmine Tests
[INFO]
-------------------------------------------------------
 J A S M I N E   T E S T S
-------------------------------------------------------
[INFO]
describe The quickstart object
  it adds two numbers
[INFO]
Results:

1 specs, 0 failures
...

The result of your jasmine test execution can be found under:

target/jasmine/
|-- ManualSpecRunner.html
|-- SpecRunner.html
|-- TEST-jasmine.xml

Here you can find a JUnit like xml (TEST-jasmine.xml) file with the testresults for further processing through other tools like a CI server.
Additionally there are two HTML test runners generated: one for test-driving locally in your browser (SpecRunner.html), and one to run as part of the build (ManualSpecRunner.html). Opening the latter one into your favorite browser will execute all the tests right away inside a real browser.

Compression of js and css files with yuicompressor-maven-plugin

To created compressed versions of your javascript and css files the yuicompressor-maven-plugin is used.

To activate automatically creation of compressed versions of your javascript and css files the following plugin configuration must be present in your pom.xml file.

...
<plugin>
  <groupId>net.alchim31.maven</groupId>
  <artifactId>yuicompressor-maven-plugin</artifactId>
  <version>1.1</version>
  <executions>
    <execution>
      <id>compress-js</id>
      <goals>
        <goal>compress</goal>
      </goals>
    </execution>
  </executions>
</plugin>
...

Finally your generated target maven artefact is containing the following files:

target/classes/
|-- quickstart-min.js
`-- quickstart.js

Jslint and Jsdoc with maven-jstools-plugin

With the help of jsdoc you can easily create your own separated documentation about your code quite similar to javadoc.

...
        /**
         * Adds two numbers ...
         * @param number1 first number
         * @param number2 second number
         * @return the sum of the two numbers
         */
        addNumbers : function(number1, number2) {
            return number1 + number2;
        }
...

Your api documentation is put into the comments of your methods. After the automatically generation during the build process a html document is created:

A very well known code analysis tool for javascript is jslint. Its a code quality tool which looks for potential problems in your javascript code. For jslint we would like to have a seamless integration into the build process as well.

To integrate jsdoc and jslint into the build process the maven-jstools-plugin is used.

This plugin has to be configured inside your reporting section of your pom file. After that jslint and jsdoc is executed and a report is generated containing the results.

...
<reporting>
  <plugins>
    <plugin>
      <groupId>gr.abiss.mvn.plugins</groupId>
      <artifactId>maven-jstools-plugin</artifactId>
      <version>0.7</version>
      <configuration>
        <jsDir>src/main/javascript</jsDir>
        <includePrivate>true</includePrivate>
        <includeUndocumented>true</includeUndocumented>
      </configuration>
      <reportSets>
        <reportSet>
          <reports>
            <report>jslint</report>
            <report>jsdoc</report>
          </reports>
        </reportSet>
      </reportSets>
    </plugin>
...

After calling

$ mvn site

you will find the generated documentation under:

target/site/index.html

Here you have access to the generated reports of jslint and jsdoc.

The whole thing

After the configuration the complete pom.xml is looking like that

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>de.akquinet.javascript</groupId>
    <artifactId>quickstart</artifactId>
    <version>1.0</version>
    <name>Javascript quickstart</name>

    <organization>
        <name>akquinet A.G.</name>
        <url>http://www.akquinet.de/en</url>
    </organization>

    <build>
        <resources>
            <resource>
                <directory>src/main/javascript</directory>
                <filtering>true</filtering>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>com.github.searls</groupId>
                <artifactId>jasmine-maven-plugin</artifactId>
                <version>1.0.1-beta-6</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generateManualRunner</goal>
                            <goal>resources</goal>
                            <goal>testResources</goal>
                            <goal>test</goal>
                            <goal>preparePackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <jsSrcDir>src/main/javascript</jsSrcDir>
                    <jsTestSrcDir>src/test/javascript</jsTestSrcDir>
                </configuration>
            </plugin>


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.1.2</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>yuicompressor-maven-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <id>compress-js</id>
                        <goals>
                            <goal>compress</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

    <reporting>
        <plugins>
            <plugin>
                <groupId>gr.abiss.mvn.plugins</groupId>
                <artifactId>maven-jstools-plugin</artifactId>
                <version>0.7</version>
                <configuration>
                    <jsDir>src/main/javascript</jsDir>
                    <includePrivate>true</includePrivate>
                    <includeUndocumented>true</includeUndocumented>
                </configuration>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>jslint</report>
                            <report>jsdoc</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>2.6</version>
            </plugin>
        </plugins>
    </reporting>
</project>

Javascript Archetypes

To avoid writing such long pom files we are providing two maven archetypes which are creating ready to go skeletons for your very own javascript project.

  • Sources on github
  • javascript-quickstart

    The quickstart archetype creates a simple javascript application. To use this archetype just call:

    mvn archetype:generate \
    -DarchetypeArtifactId=javascript-quickstart \
    -DarchetypeGroupId=de.akquinet.javascript.archetypes \
    -DarchetypeVersion=1.0.0 \
    -DgroupId=your.company \
    -DartifactId=javascript-quickstart-application
    

    After running the archetype the following content is created:

    javascript-quickstart-application/
    |-- pom.xml
    |-- src
    |   |-- main
    |   |   `-- javascript
    |   |       `-- quickstart.js
    |   `-- test
    |       `-- javascript
    |           `-- quickstartTest.js
    

    This is a very simple Javascript project which is including a jasmine test, running jslint, jsdoc and compressions.

    javascript-jqueryplugin

    The jqueryplugin archetype creates a simple jquery plugin implementation which is a good starting point for your very own jquery plugins. The skeleton code obeys the rules of developing good jquery plugins. For further information check the jquery plugin authoring guide.

    mvn archetype:generate \
    -DarchetypeArtifactId=javascript-jqueryplugin \
    -DarchetypeGroupId=de.akquinet.javascript.archetypes \
    -DarchetypeVersion=1.0.0 \
    -DgroupId=your.company \
    -DartifactId=javascript-jqueryplugin
    

    The created content should be similar to this:

    |-- pom.xml
    |-- src
    |   |-- main
    |   |   `-- javascript
    |   |       `-- jquery.helloworld.plugin.js
    |   `-- test
    |       `-- javascript
    |           |-- helloworldPluginTest.js
    |           `-- lib
    |               `-- jquery-1.4.4.min.js
    

    This example jQuery plugin is simply modifying the DOM by adding some “hello world” message to it. Additionally you will find a jasmine testcase for this plugin. Furthermore there is a fully configured build process which is running the jasmine test, jslint, jsdoc and compressions.

    Conclusion

    We showed how to utilize the power and benefit of bringing maven to the javascript world. With the help of three additional maven plugins we were able to create an build process which does the following steps automatically:

  • Execution of your javascript tests
  • Generating code documentation based on jsdoc
  • Running static code analysis
  • Perform compression of js and css files
  • Be ready for easy integration of your favorite continuous integration server like hudson
  • After that, we also introduced two very handy maven archetypes to give you a quick and easy start into the world of maven and javascript.

    21 thoughts on “Mavenizing Javascript Projects

    1. Thank you for this! It’s one of the best write-ups I’ve seen on how to do a build for the front end. And the Archetypes are a generous gift!

      Question… are there many situations when you would want to ONLY build the front-end, or would you usually run this at the same time that you build the back end?

      Also, where or how would I set my preferences for how JSlint or any of the other plugins function?

    2. Hi, great article. I have a question, how can I mix several javascript files into one?. What plugin allows me to do this?.

    3. Very nice article. Do you have a recommendation for how to include such a generated artefact containing JavaScript files as a dependency e.g. for a war-Artefact (which must be extracted somehow so that it get included into the webapp as a web-resource) ?

    4. Thank you for a great article.
      I’m a little confused with surefire plugin at the end of artifact. It is not explained, and from what I found on internet, it’s for Java tests. Has it some purpose or it shouldn’t be there?

    5. Great Article, thank you so much!

      I want to learn how to create a similar maven archetype for my enterprise. Could you please share / link to a good learning resource to create an archetype from an existing project?

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s