days
-1
-2
hours
-1
-8
minutes
0
-8
seconds
-3
-2
search
Automated build systems

Local continuous delivery with Node.js and Grunt

Christian Janker
Abstract image via Shutterstock

Nowadays, everybody’s talking about continuous delivery, but how many of us can say we’ve encountered “Local Continuous Delivery”? In this guest post, blogger Chris Yanx shows us a novel approach to automating a local build system with Grunt, Node.js and Java.

Some days ago I read an old blog entry from Gregor Riegler about how being a lazy developer may be a good characteristic of a software developer (because lazy developers always question the way how they work and try to find new ways to increase their working experience). Just by becoming a much more lazier developer? Sounds great. That’s a good skill – I guess I’m a very good developer then ;)

SEE ALSO: Developers are strategically lazy

Nowadays everybody talks about continuous delivery. If you aren’t already implementing it, then you probably want to. But no worries – in this blog post I’m not going to talk about about how you ship your code into production and how often you do it. Today, I want to introduce the topic of Local Continuous Delivery, a.k.a:

Automating your local build system

Caveat: This is no JRebel or Springloaded post. Both are good tools for hot class reloading, and both have the right to exist. However, both do have their limitations. JRebel isn’t free and Springloaded does not recognise changes within libraries that a project is depending on. What is more, when it comes to an error during development, the first thing you’ll do (if the error is not obvious) is to turn off hot class reloading, because you can never be sure that it worked out how you’d expected.

And now here it comes – my very own method of continuous delivery and hot deployment: Grunt in combination with Java. Grunt is a Javascript taskrunner, based on Node.js. A task can be a Maven build. A task can be a copy command. A task can be a command to start a server. A task can be a file listener. A task can be a http call to a specific url to reset caches. A task can be anything. Furthermore multiple tasks can be chained, so that a task can trigger other tasks. For a short introduction please read the Grunt getting started guide.

So let’s start with an example to clarify my idea.

Given:

  • Application: JavaEE Multi-Module-Maven project
  • Server: Wildfly 8.2.0
  • IDE: Eclipse

Goal:

Automatically build and deploy the project after a filechange.

Requirements:

The only thing you have to install manually is Node.js itself. After that a simple npm install -g grunt-cli is required to install the grunt command-line interface.

Then within the project root you do an npm install grunt and create a package.json and a Gruntfile.js file. The package.json file contains our Javascript dependecies. With an npm install within the project root they automatically get downloaded for you.

Within the Gruntfile.js we configure our grunt tasks.

Application Structure

testbox
|__ testbox-ejb
|__ testbox-war
|__ pom.xml
|__ package.json
|__ Gruntfile.js

package.json

{{
   "devDependencies": {
      "grunt-contrib-watch": "latest",
      "grunt-notify": "~0.3.0",
      "grunt-shell-spawn": "latest",
      "load-grunt-tasks": "latest"
   }
}

Gruntfile.js

(function() {
	'use strict';

	var project = {
		javaFiles : [ 'testbox-war/src/main/java/**/*.java',
		              'testbox-ejb/src/main/java/**/*.java']
	};

	module.exports = function(grunt) {

		require('load-grunt-tasks')(grunt);
		grunt.loadNpmTasks('grunt-notify');

		grunt.initConfig({
			watch : {
				files : [ project.javaFiles ],
				tasks : [ 'notify:start',
				          'shell:build',
				          'shell:copy',
				          'notify:finished' ],
				options : {
					interrupt : true
				}
			},
			shell : {
				build : {
					command : 'mvn clean install -DskipTests',
					options : {
						stdout : true,
						stderr : true,
						failOnError : true,
						execOptions : {
							maxBuffer : "Infinite"
						}
					}
				},
				copy : {
					command : 'cp testbox-war/target/testbox-war-0.0.1-SNAPSHOT.war /Users/chrisyanx/wildfly-8.2.0.Final/standalone/deployments/testbox.war',
					options : {
						stdout : true,
						stderr : true,
						failOnError : true,
						execOptions : {
							maxBuffer : "Infinite"
						}
					}
				}
			},
			notify : {
				start : {
					options : {
						message : "Starting Deployment..."
					}
				},
				finished : {
					options : {
						message : "Finished"
					}
				}
			}

		});

		grunt.registerTask('default', [ 'watch' ]);

	};
})();

On the top of the file there is a variable project defined that represents my project structure. Further down in the configuration of the watch task it is referenced to tell the Grunt watch plugin which file changes it should listen out for. If a file change is detected, several subtasks are triggered: notify:start - shell:build - shell:copy - notify:finished

  1. User gets notified that a change has been detected – notify:start
  2. The project gets built via a maven command – shell:build
  3. The resulting war file is copied to the running server – shell:copy
  4. User gets notified that grunt has finished – notify:finished

The JBoss Wildfly server has no need to be restarted when a war package is dropped into its deployment folder. But, if required, a grunt task for starting/stopping the server could be added as well.

Start it

Simply type grunt in a command line interface located at the project root and hit enter. Then change a file and see what happens.

Conclusion

One could argue that you could achieve the same with maven plugins. That my be true, but in my eyes that is not a clean and separated solution. I would rather not pollute the Maven config any more, creating dozens of Maven profiles and plugins.

Furthermore, using the Grunt approach you can really take a strain off your IDE, because you’re not building within your IDE and your server can run within a terminal. Combine this approach with JRebel or Springloaded and you can become even faster!

Author

Christian Janker

Mein erster Blogpost. Auch lesbar unter http://yanxch.github.io


Leave a Reply

Be the First to Comment!

avatar
400
  Subscribe  
Notify of