We are the Dev Teams of
  • brands
  • ebay_main
  • ebay
  • mobile
<
>
BLOG

Integrating Grunt into Your Maven Build

by Florian Semrau
in Tutorials

Maven and GruntAt ebay Kleinanzeigen, we use many maven plugins during our build to improve the loading time of our page. This includes for example a minification plugin for CSS and JavaScript as well as creating sprites from images in order to lower the number of browser requests.

Many plugins with similar features recently became very popular for Grunt, and a lot of these plugins even go far beyond the features that are currently available from a maven build. At ebay Kleinanzeigen the frontend team was curious to try some of the plugins from the Grunt world, however we did not want to break the existing maven build chain. Luckily there is a maven plugin, that closes the gap between maven and Grunt: The frontend-maven-plugin.

It offers the functionality of Grunt within your maven build. In order to do so, it downloads and installs node and NPM (Node Packaged Modules) locally for your project and then runs NPM install and Grunt. The plugin also supports gulpjs and Karma, and thus gives you even more possibilites to enhance your build. Since we develop in all different flavors of environments and operating systems, it was important to us that the frontend-maven-plugin works platform independent. It claims to work on Windows, OS X and Linux.

We decided to evaluate the pros and cons of the frontend-maven-plugin, so in this tutorial I will describe how to wire a Grunt plugin into your maven build, so you can take it from there and start your experiments. In my experimental setup I used MacOS and had no problems running Grunt from the frontend-maven-plugin.

First we start by adding the maven-frontend-plugin to our pom.xml.

<plugins>
    <plugin>
        <groupId>com.github.eirslett</groupId>
        <artifactId>frontend-maven-plugin</artifactId>
        <version>0.0.14</version>
        <executions>
            <execution>
                <id>install node and npm</id>
                <goals>
                    <goal>install-node-and-npm</goal>
                </goals>
                <configuration>
                    <nodeVersion>v0.10.18</nodeVersion>
                    <npmVersion>1.3.8</npmVersion>
                </configuration>
            </execution>
            <execution>
                <id>npm install</id>
                <goals>
                    <goal>npm</goal>
                </goals>
                <configuration>
                    <arguments>install</arguments>
                </configuration>
            </execution>
            <execution>
                <id>grunt build</id>
                <goals>
                    <goal>grunt</goal>
                </goals>
                <configuration>
                    <arguments>--no-color</arguments>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>

This configures the maven build to include the maven-frontend-plugin. Now we need to give the downloaded NPM some configuration within the file package.json, that resides in the same directory as our pom.xml:

{
    "name": "webapp-static",
    "version": "0.0.1",
    "dependencies": {
        "grunt": "~0.4.2",
        "grunt-cli": "~0.1.9",
        "grunt-image-embed": "~0.3.1"
    }
}

The json tells NPM the name and version of the current module and passes the names and versions of the dependencies used later on. Notice how compact the json is compared to the maven pom.xml.
The maven-frontend-plugin will then call the Grunt build, which also needs some configuration that we place within another file called Gruntfile.js, which is also saved in the same folder as our pom.xml. The path details within this configuration is adjusted to a typical maven project layout, but you may have to make some adjustments here to make it work for your project.

module.exports = function(grunt) {
    grunt.loadNpmTasks("grunt-image-embed");

    grunt.initConfig({
        imageEmbed: {
            dist: {
                src: [ "src/main/webapp/css/*.css" ],
                dest: "target/webapp-static/css/styles.css",
                options: {
                    deleteAfterEncoding : false
                }
            }
        }
    });

    grunt.registerTask("default", ["imageEmbed"]);
};

Once we have this in place, we can do a first run of mvn clean install. During this run, maven will download all necessary dependencies. In our case, we had two more folders that appeared in our folder structure afterwards (node/ and node_modules/).
The second time the maven build is triggered, the execution should be a lot faster.

We chose to try out the grunt-image-embed plugin. This plugin inlines images as base64-encoded data URI into your CSS files and thus lowers the number of requests from your browser.
After the maven build has successfully completed, you should find a pretty large styles.css files within your maven target directory, that now also hold all image data that are otherwise loaded during further requests from the browser.

A nice thing about the grunt-image-embed plugin is, that it is aware of the maximum size of the base64 string in bytes. It defaults to 32768, the limit of Internet Explorer 8. This can be configure using the maxImageSize parameter, or you can set it to 0 in order to remove the limit and allow any size string.

So what's the outcome of the Grunt experiment? First of all, the maven-frontend-plugin worked stable in my local experiments. I found it a little hard to wire the configuration together and mostly got stuck trying to guess the correct path whenever the build failed because something could not be found where it was expected. Another issue are the versions defined in the package.json. You eventually have to do some digging in the online documentation to find out whether all included versions work well together.

A feature that I was missing at first when using the grunt-image-embed plugin is the possibility to define many sets of stylesheets, instead of just one monolithic block that contains all CSS and data URIs. It turned out that this can be easily configured with gruntjs. An adjusted sample configuration would then look like this:

imageEmbed: {
    dist: {
        files: [{
                src: [ "src/main/webapp/css/styles-homepage.css",
                    "src/main/webapp/css/styles-details.css" ],
                dest: "target/webapp-static/css/main.css"
            },{
                src: [ "src/main/webapp/css/styles-imprint.css" ],
                dest: "target/webapp-static/css/imprint.css"
            }]
    }
}

Migrating from our working maven build to the maven-frontend-plugin would currently mean a lot of effort for us, because we would also have to  integrate further plugins e.g. for CSS/JS minification and test if the plugin would work well on our linux build systems.

However we will definitely keep an eye on the further development of the plugins of the Grunt universe. It was fun playing around with the Grunt plugins and the setup was quite fast and easy. Once I had everything setup I was very tempted to go on and include even more plugins to see how far I could take it. So we would be happy if you come back here from time to time to find out if there are news from us on this topic.

maven, grunt, npm, node, css

?>