Sunday, August 29, 2010

Creating a Javascript Library with Maven

A Javascript library consists of some Javascript files, and potentially some resources like images, templates, and stylesheets. In Maven, these are arranged in the following directory structure:


my-library/
. pom.xml
. src/
. main/
. javascript/
. resources/
. test/
. javascript/
. resources/

The one item that might require some explanation is pom.xml. It is a “project object model” file, which has information about your project and its configuration. It'll be explained piece-by-piece below.

Initial Steps

The first thing you need to do is install Maven. Go to http://maven.apache.org and grab a copy of 2.2.x. Extract it somewhere and add the bin directory to your path.

$ export PATH=$PATH:path/to/maven/bin && mvn --version

If that worked out right, you should see a Maven version and some Java environment information displayed.

Next you need to edit your settings.xml file. Run the following command:

$ mkdir ~/.m2 && gedit ~/.m2/settings.xml

and add this content to the file:

http://gist.github.com/557035#file_settings.xml

These settings are adding the Sonatype OSS repository where the Javascript plugin and several popular libraries that I have packaged for Maven use are hosted.

Creating the Project

All that is needed to create a Javascript library is a POM and some source code. A simple POM looks like this, and is called pom.xml:

http://gist.github.com/557035#file_pom.xml


There are a couple notes about this file, as seen in the comments above.

1. In Maven, every project is defined uniquely by these 4 pieces. groupId should be a subdomain under your control. artifactId is the name of this project. version is typically [major].[minor].[point]-[type]; type is either a “release” or a “snapshot”. This pertains to deployment which I'll cover in the next article.

2. A project has many dependencies and a few possible scopes. In this case we're using the “test” scope. The other important one is “runtime”, which I'll describe later. Each dependency has a version; is good practice to use a range. In this case we can use any 1.4.x version of jQuery. This is especially important as many dependencies are added to the project, which may all rely on different point releases of the same library.

3. Each project can have many plugins. The one that makes JS development possible is the javascript-maven-plugin. Not all plugins require the 'extensions' element. This one does because it adds 'javascript' dependency and packaging types which are not built into Maven.

Once you have your POM in place, you need to create some Javascript. Create a file called hello.js in src/main/javascript:

http://gist.github.com/557035#file_hello.js


Adding QUnit Tests

Now that we have a little functionality in place, let's create a test for it. Create suite-hello.html in src/test/javascript:

http://gist.github.com/557035#file_suite_hello.js


First, all tests match the pattern suite-*.html. Second, notice your hello.js file is in the scripts/ directory, while external dependencies (qunit and junit) are in scripts/${artifactId}/filename.js. These are conventions I have put in place that mirror web application packaging, which will be covered later.

One thing to notice is that qunit is never declared as a dependency to the project. This is likely to change in the near future. At the moment it is automatically added by the plugin code. It might be safe to declare it explicitly, but I'll leave that as an exercise to the reader.

Now run the following command:

my-library$ mvn test && cat target/surefire-reports/qunit.txt

If everything went right, you should get a message that says “Build Successful” and have a brief summary of the executed test displayed.

Next Time...

In the next article I'll show you how to release your project to an open source repository, and declare where it exists in an SCM for automatic release tagging.

Saturday, August 28, 2010

Javascript Maven Plugin Revamped

In the process of researching for the Engineering Better Javascript series, I ended up implementing some of my ideas to make them concrete. I've extended the existing Javascript Maven Tools to include a QUnit plugin and report integration, as well as added some integration tests to ensure that things are working as expected. I also added a javascript-project base parent, which takes some of the redundant code out of the POM for a Javascript project. The code is available on GitHub, here.

A good example project to check out is my ActivityStreams JS project. There are just a few things to notice.

In the pom.xml file the packaging type is 'javascript' and the parent project is 'javascript-project'. The former enables Javascript lifecycle phases and packaging, and which also allows Javascript dependencies which you can also notice in the pom.xml.

There is a profiles.xml file. This defines Sonatype OSS repositories, which is where this plugin and several 'vendor' Javascript libraries are deployed. Releases are eventually synced with Maven Central, but that hasn't happened yet. If you're using Maven 3, you need to copy the profiles to your settings.xml.

The source code to the project lives in src/main/javascript, and the QUnit tests live in src/test/javascript.

When you run 'mvn test' on the command line, all source and test source is copied to a work directory, where all dependencies are also expanded under the lib directory. These can be included by the test suites. After tests are completed, failures are recorded to target/surefire-reports/qunit.txt where they are placed into generated reports exactly as JUnit tests are for Java.

This project does not contain integration tests, but to the best of my knowledge it can easily be done using the Jetty plugin with an integration testing tool of your choice fairly easily. This is a feature I'd like to implement sooner rather than later.

All these tools also work for Webapp projects. I will write a short post about that when I have one working well. To see a sneak peak, check out the hi-og-integration branch of the Soashable OSW project.

This post is lacking on the theory and technical details behind this project, which I've been slower than I'd hoped to deliver. But it's a practical taste of what I've been doing in the past few weeks.

Friday, August 13, 2010

Benefits of a Repository Manager

On the same day I started this series, Tim O'Brien at Sonatype started a series describing the benefits of using a repository manager and saved me a little work ;). He essentially replaced the piece that I've been working on this past week, but he likely did it better (and I still learned tons while researching and writing). Here are links to his articles:


Further pieces to this series are still in the works, though I'll need to do some refactoring and may change the format of some of them to comment on his series with details specific to Javascript, since I'd be repeating much of what he says anyway.

Wednesday, August 04, 2010

Engineering Better Javascript

This is the first in a series of articles exploring a divergent idea for engineering better Javascript using ideas from the Maven build system.

Just a few years ago Javascript became used extensibly enough to warrant automated builds. It went from a language which was embedded sparingly in HTML pages to validate forms, make interactive menus, and disable right clicking, to the central language of the biggest social applications today. Not only is it used in the browser, but increasingly it is used on the server as well.

In these short few years, the need for a build system has arisen. The most popular systems today are Rake, Make and Ant; and recently Jake was introduced. These systems are declarative and task based, and can generally perform any build that is thrown at them with varying levels of complexity. In the simplest case, they concatenate scripts and replace tokens, download a compressor/test framework and other dependencies, run a compression/optimization routine, execute tests, and create a distribution package.

So what's the problem? If every Javascript library requires the same build steps, why should they all have their own slightly-different declarative build script? What happened to DRY? Why can't there be a build system which performs all these steps and allows for customization and extension when necessary, but is zero-config in the general case? It turns out that in Java land there are such systems, including Maven and Gradle. And in Maven's case, there is a plugin which extends it to Javascript.

A few years ago I created a Javascript application that had several library dependencies, and a supporting library for it that also had several of the same dependencies. Having spent a long stint in Java land, building several projects using Ant and eventually porting them to Maven, I had come to love what Maven offered even if it was slightly painful in the beginning. So naturally I wanted to go back to life without the pain of manual transitive dependency management and repetitive build scripts. This is when I found and began using (and contributing to) the Maven Javascript plugin.

Everyone knows the bad things about Maven, myself included. XML based project models are a nightmare. Plugin creation is way harder than it should be, thanks to Plexus. Project creation requires verbose command line arguments. The entire Internet must be downloaded the first time you build a project. There are plenty of less obvious ones, but I'll spare you, dear non-believers. But believe you me, I know Maven can be painful.

Despite this pain, there are some redeeming ideas which I think can be salvaged and used toward the betterment of Javascript development. The key ideas, I believe, are: the build lifecycle with plugins and project archetypes, and transitive dependency management with version ranges and a distributed repository architecture.

Over the coming weeks I will post a series of articles covering these ideas in more depth, and exploring what I see as a good solution to some of the woes of Javascript development. Stay tuned.