Recently, I needed to make a single-page web app that would be served by a Java backend.
That would be as simple as copying the static files into the relevant folder, right?
Well, as it turns out, not quite,
as each project used a different build system.
Single-page web apps are typically built using the Grunt and Bower toolchain,
which are NodeJs scripts.
Java backends are typically built using either the Ant or Maven toolchains.
Pick one, or make a bridge?
So, should we replace the build tool of with the build tool of the other,
or should we just make one of them talk to the other?
Addy Osmani has an article, Making Maven Grunt,
whichdescribes this situation quite succinctly:
"More times than not, it’s the back-end team who will define the build process and end up having to wrangle your front-end code into there."
Thus it appears that in order to get the best of both worlds,
the best option would be to create the bridge that allows one build system to talk to the other.
In this case, to make maven invoke grunt.
Turns out that this is a problem that several have had, and solved, before.
If you your web app is generated by yeoman,
yeoman-maven-plugin provides some sensible configurations that work out of the box.
However, if you need something a little more flexible,
maven-antrun-plugin, or the
exec-maven-plugin is your best bet.
However, I did not want to throw Ant into the mix,
as I was already using two other build systems,
and their syntaxes -
and thus reluctant to throw a third syntax into the mix;
exec-maven-plugin it was!
Why don’t my plugins run?
I asked a question on Stackoverflow:
"Maven exec-maven-plugin and maven-resources-plugin not running, not sure why"
Excuse the newbie question on this one -
this was my first time using maven after all!
When including a maven plugin,
you define a list of
I thought that defining a
<phase> for each
<execution> was sufficient to trigger them.
I learnt that it simply was not.
It is necessary to define at least one
<goal> for the plugin to get invoked.
Why can’t my plugin find executables?
A follow up question, also on Stackoverflow:
exec-maven-plugin says cannot run specified program, even though it is on the PATH
Now this one was not a newbie question at all - it turned out to be a Windows-specific bug.
Basically, even though entering
grunt on the command line worked,
as it was on the path, when the maven plugin ran,
it failed to find it, much to my puzzlement.
After much tinkering, and inspecting the source code of
I found what I think is a bug in the plugin:
if ( OS.isFamilyWindows() && exec.toLowerCase( Locale.getDefault() ).endsWith( ".bat" ) )
toRet = new CommandLine( "cmd" );
toRet.addArgument( "/c" );
toRet.addArgument( exec );
toRet = new CommandLine( exec );
It assumes that only commands that invoke
.bat files need to be prepended with
I checked the
npm path, where the links to all the global installed NodeJs libraries are,
i.e. the ones installed using
npm install -g,
and found that it had, for each,
a Unix shell script, with no extension,
and a Windows batch script, with a
Fixing the problem
Normally I would have fixed the problem by patching the bug in
However, it was using a
svn instead of
git, and using
xircles instead of
I was not new to Subversion, but had not used it before in the context of
a open source contributions.
github the way I contributed to open source projects was:
svn diff > bug-that-this-patch-should-fix.diff
bug-that-this-patch-should-fix.diff to the issue tracker, forum, or email the maintainer of the project.
I have since been spoilt by git’s cheap branching,
and the ease with which pull requests can be managed in github’s interface.
I did give it a go, nonetheless, but I the web interface took more than a minute to load (kid not!),
and that was all it took for me to start looking for another way to solve the problem.
A quick and easy way was to simply rename the
.cmd files to
since they were batch script files anyway,
and everything magically began working once more.
See my answer for a more detailed explanation.
That has been half rant, half description of my learning experience.
I must say, I wish that a rather simple task like this were a little easier.
Hopefully this helps anyone else trying to use maven with grunt, on Windows.