April 8, 2017

Cross platform gradle npm builds

This is a quick and dirty one, mostly so I dont forget to write down something painful I had to do recently. If you use node npm in a gradle build process, which is very likely in java projects with react or angular frontends, if you're like me you may think doing something like this will work fine:

    task compileMyFrontend(type: Exec) {
        // or whatever npm script...
        commandLine "npm","run", "build"

You code away on your macbook and have no problems! Fast forward to having to be developing on windows, you quickly realize it will fail to find NPM which is odd. When I initially setup build gradles that needed to execute npm, i ran into the same problem, and found many stackoverflows recommending doing the following (which I did, being windows based at work):

    task compileMyFrontend(type: Exec) {
        // or whatever npm script...
        executable "cmd"
        args "/c npm install && run build"

There is a better way!

It is apparently caused by the Process launching code in JVM needing the FULL executable file name. windows command prompt and powershell are smart enough to know npm's extension and execute it if possible, which they will do for anything that ends in .exe,.bat,.cmd, probably others..

So, what exactly is npm on windows then? it's npm.cmd on node7, you can check yourself with:

    where npm

so to get gradle to work, you need to execute

commandLine 'npm.cmd','args..'.

Great! problem solved, time to drink beer right? Well doing that will break *nix builds. As one would expect, we need to add some glue to the build. Conditionally getting the build os is not built into gradle so you have to import some stuff, but any gradle3+ should work. tldr add this to top of your build.gradle:

    import org.apache.tools.ant.taskdefs.condition.Os

    def iswindows = Os.isFamily(Os.FAMILY_WINDOWS)
    project.ext."npmExe" = swindows ? "npm.cmd" : "npm"

I arbitrary called the variable "npmExe", not "npm" because that looked slightly confusing. Now any npm tasks just need to use that variable directly in their command line, eg:

    task compileMyFrontend(type: Exec) {
        // or whatever npm script...
        commandLine project.ext."npmExe","run", "build"

This will work on windows and mac/linux, etc. Bleck

Build gradle npm

Previous post
endless static site fights After a bit of messing around, completely nuking the old site (GH pages Jekyll setup), putting up silly 10mb ascii art index.html files and writing
Next post
free AWS Certs on non-static sites In this post I will cover how to use AWS to host dynamic content with a free AWS SSL cert. Not much background, the reason I did this is I had a