Creating a Maven Project from Scratch

This section explains how to create a maven project from an empty archetype and set up the basic environment for a JavaScript project.

Table of Contents
1. Getting started
2. Generating the project from an archetype
3. Running the webapp
4. Configuring the target package
5. Adding resource compression
6. Checking the code syntax
7. Setting up unit testing
8. Generating documentation
9. Releasing and deploying the final package

1. Getting started
You should have installed the following applications, and set up your PATH environment variable to make them work properly:

* Maven 2.2.1 (download): the mvn command must be on PATH.
* Subversion (download page): The svn command must be on PATH.


2. Generating the project from an archetype
We'll use the maven-archetype-webapp archetype to generate a naked web application. It will help us to test our application on a server inside the project. Open a console and let's go:


$ mvn archetype:generate

This will show a full-unreadable list of the available archetypes. We must choose the webapp archetype, please find what's the number in your list and select it.

[INFO] Preparing archetype:generate
[INFO] Generating project in Interactive mode
Choose archetype:
61: remote -> maven-archetype-webapp
62: remote -> myfaces-archetype-helloworld
63: remote -> myfaces-archetype-helloworld-facelets

Choose a number: 58: 61
Choose version:
1: 1.0
2: 1.0-alpha-1
3: 1.0-alpha-2
4: 1.0-alpha-3
5: 1.0-alpha-4
Choose a number: : 5

Define value for property 'groupId': : org.moyrax
Define value for property 'artifactId': : test-ui-project
Define value for property 'version': 1.0-SNAPSHOT: 0.1.0-SNAPSHOT
Define value for property 'package': org.moyrax: 

[INFO] ----------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------

$ cd test-ui-project

Now we're located on our project's directory. The project should have the following directory structure:

src
 |--main
 |  |--resources
 |  |--webapp
 |     |--WEB-INF
 |     index.jsp
 pom.xml

Look at the resources directory, it will be our main application's directory where the JavaScript components will be placed.

3. Running the webapp
Once the project is ready, we'll add the jetty plugin to the POM, which runs the application in an embed server. Add the following plugin to the POM's build section:


<build>
  <finalName>test-ui-project</finalName>

  <plugins>
    <plugin>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>maven-jetty-plugin</artifactId>
      <version>6.1.21</version>

      <configuration>
        <contextPath>test-ui</contextPath>
        <useTestClasspath>true</useTestClasspath>
      </configuration>
    </plugin>
  </plugins>
</build>


Now we can start the server from the command line:

~/test-ui-project
$ mvn jetty:run

At this instance you should be able to access the application from the browser through localhost, port 8080:


Once we have our naked application running, let's go to start creating components.

4. Configuring the target package
We need to create a distrubution package for our project. By default, as the webapp packaging is set to "war" by the archetype, the result is a war file containing both the webapp and the application resources.

So we'll use the assembly maven plugin to generate a package containing only the application resources, and skipping the webapp. Add the following plugin to the POM's build section:


<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>2.2-beta-5</version>
  <configuration>
    <descriptors>
      <descriptor>assembly.xml</descriptor>
    </descriptors>
  </configuration>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Note that we specified an "assembly file". It's basically an XML file which contains the instructions to build the target package. This file must be in the project root directory (where the POM is). Create this file and add the following content:

<assembly>
  <id>project</id>

  <includeBaseDirectory>false</includeBaseDirectory>

  <formats>
    <format>jar</format>
  </formats>

  <fileSets>
    <fileSet>
      <directory>src/main/resources</directory>
      <outputDirectory>.</outputDirectory>
      <useDefaultExcludes>true</useDefaultExcludes>

      <includes>
        <include>**/*.js</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

What it does?. Okay, first of all, it specifies that the target package will contain the whole project (setting the id to project, an special id recognized by the plugin). It also specifies the target file format, and we choose jar because we want to use our project as a common dependency in the future, right? =]. Then we indicate what files are included in the distribution using a fileset. In this case, only the files with the js extension are included, but you could add more filters if necessary.

Let's test it building the application:

~/test-ui-project$ mvn clean install

After the building ends, there will be a test-ui-project-project.jar file in the target folder. Note that the assembly plugin automatically adds the "-project" suffix to the file.

5. Adding resource compression
Resource compression is the ability of minimizing a file size to load it faster in the web browser. Additionally, it gives a quality constraint since a compressed resource (either a JavaScript file or a CSS) must have a well-formed syntax to be valid after the compression.

javascript-maven-tools are a set of tools that I developed along the time I worked on UI projects. These tools are thought to simplify creating distribution packages and to stimulate the modular-oriented development. For more information see the project page, we only will use a single component: the javascript-compressor plugin.

To start configuring the compressor plugin, we need to add the plugin repository first. So, add the proper repository configuration at the end of your POM:


<pluginRepositories>
 <pluginRepository>
    <id>moyrax-releases</id>
    <name>Moyrax Artifactory</name>
    <url>http://www.moyrax.com:8081/nexus/content/repositories/moyrax-releases/</url>

    <snapshots>

      <enabled>false</enabled>
    </snapshots>

    <releases>

      <updatePolicy>never</updatePolicy>
    </releases>
  </pluginRepository>
</pluginRepositories>

The compressor plugin will be downloaded from this repository (also a mirror of maven's central repository). Then we're going to add the compressor plugin to the build.

The compressor plugin currently has the following features:

* On-site compression: It compresses resources and places the new compressed files in the same location of each resource, appending a suffix to the file name. For example, if you have a file com/moyrax/Foo.js, the plugin configured in this way will generate a file com/moyrax/Foo-min.js, considering -min as the specified suffix in the configuration.

* Bundle compression: It compresses resources and generates a single file containing all compressed files. It's used to generate a distribution bundle which reduces the loading overhead resulting in a faster application loading and pre-processing.

These ways are not exclusive, we can configure both in different executions, and it's what we're going to do. Let's create two JavaScript files for testing purposes:

src/main/resources/org/moyrax/Foo.js

/**
 * Foo testing object.
 */
var Foo = {
  /**
   * Displays the Hello World alert.
   *
   * @param {String} msg The Hello World string. It cannot be null or empty.
   */
  sayHello : function(msg) {
    alert(msg);
  }
};


src/main/resources/org/moyrax/Bar.js

/**
 * Bar testing object.
 */
var Bar = {
  /**
   * Displays the Hello World alert.
   *
   * @param {String} msg The Hello World string. It cannot be null or empty.
   */
  sayHello : function(msg) {
    Foo.sayHello(msg);
  }
};

Then we'll configure the compressor plugin in both ways. Add the following configuration to the build section from the POM:

<!-- Configures the compressor using the "On-site compression" mode -->
<plugin>
  <groupId>org.moyrax</groupId>
  <artifactId>javascript-compressor</artifactId>
  <version>0.1.1</version>
  <executions>
    <execution>
      <goals>
        <goal>compress</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <sourceDirectory>
      <directory>src/main/resources/</directory>
      <includes>
        <include>**/*.js</include>
      </includes>
    </sourceDirectory>
    <outputFilesSuffix>-min</outputFilesSuffix>
  </configuration>
</plugin>

<!-- Configures the compressor using the "bundle compression" mode -->
<plugin>
  <groupId>org.moyrax</groupId>
  <artifactId>javascript-compressor</artifactId>
  <version>0.1.1</version>
  <executions>
    <execution>
      <goals>
        <goal>bundle</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <bundles>
      <bundle>
        <compress>true</compress>
        <outputFile>src/main/resources/org/moyrax/${project.artifactId}-${project.version}-min.js</outputFile>
        <files>
          <directory>src/main/resources</directory>
          <includes>
            <include>**/*.js</include>
          </includes>
        </files>
      </bundle>
    </bundles>
  </configuration>
</plugin>

Note that in the case of the Bundle Compression mode (the second execution), there's a compress flag which allows to enable or not the compression. If the compression is disabled setting the compress flag to false, the result will be an uncompressed bundle.

As the javascript-compressor-plugin is triggered in the process-test-resources phase (see the maven's build lifecycle reference for more information), the results will be included in the distribution package.


6. Checking the code syntax
Another quality assurance practice is to check the source code syntax during build time. This will ensure that the code is well-formed and the compression or bundling will work properly. There're a lot of tools which verify a source for well-formed code, but jslint is the one we're interesting.

JSLint has a java port which can be integrated to the build using the exec-maven-plugin. This jslint port can be configured through a file containing ant tasks. Please, see the following example configuration file:


<project xmlns:jsl="antlib:com.googlecode.jslint4java">
  <target name="jslint">
    <jsl:jslint haltOnFailure="true">
      <formatter type="plain" />
      <fileset dir="${root}/src/main/resources" includes="**/*.js" excludes="**/*-min.js,**/lib/**/*.js" />
    </jsl:jslint>
  </target>
</project>

I could explain the configuration fields, but there is a page which contains the full documentation: http://jslint4java.googlecode.com/svn/docs/1.4/ant.html. As a summary, this ant task allows to configure the jslint validations and also the way as the errors are reported. The reporting includes plain text (the default, output to the console), XML and JUnit-compliant reports.

Now let's add the plugin to the POM build section:


<!-- JSLint validations. -->
<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <dependencies>
    <dependency>
      <groupId>com.googlecode.jslint4java</groupId>
      <artifactId>jslint4java-ant</artifactId>
      <version>1.3.1</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
      <id>jslint</id>
      <phase>test</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <tasks>
          <ant antfile="${basedir}/jslint.xml">
            <property name="root" location="${basedir}" />
            <target name="jslint" />
          </ant>
        </tasks>
      </configuration>
    </execution>
  </executions>
</plugin>

That's all. We have now a tool which checks the sources syntax at build time and breaks the build if it hasn't the quality that we want.

1 comment:

Santiago said...

Really useful, thanks for the guide. :)