Tuesday, December 2, 2014

Npm, Bower, CI and the Network

Ok, I accepted the reality that building single-page applications (SPA) is better done using the tooling options embraced by the JavaScript community, rather than building those apps using purely Gradle or Maven (and respective plugins). The reason being that building a complete web-UI is rather involved and tools like Yeoman, Grunt (Gulp) and Bower provide quite a bit of useful tooling while also having a much larger user-base than the (less complete) options in the Java world.

So life was good. Everything builds. Of course we still need to integrate the app with our backend that provides the REST endpoints. Personally, I prefer it that developers can build the entire stack at once. Also, can we assume that every (Java) developer has Node/Npm intalled?

Luckily, there are some plugins available for Maven and Gradle that provide useful wrappers around Npm and Node:
Thus, with some trial and error you get a fairly portable build (Linux, Mac and Windows) that not only executes the Grunt build but also downloads and installs Node and its dependencies, Grunt, Bower etc.

You think you finally arrived...Things run mostly okay on the continuous integration (CI) server...mmh, wait... "Mostly" is causing some headaches. This is actually an area where I have some frustrations lately. Looks like the Maven Central in the node world is a tad more volatile than Maven central itself.

In the Java world you have 2 layers of protection that ensure that the CI server build process is fairly resilient to internet hick-ups. Heck, it would even build off-line (assuming no library dependency changes were done). First, you have your local repository of course, which in the case of Maven is typically ${user.home}/.m2/

Second, any serious CI environment would also use a dedicated repository manager that serves as a proxy to the outside world, so that for already retrieved dependencies you would not need to hit Maven Central or other 3rd party repositories.

With NPM you all of a sudden realize you are a tad back into the wild west. Not only do you have to consider NPM (Managing tooling dependencies) but Bower (managing JS/CSS dependencies) as well.

NPM actually provides npm-cache - and you see dependencies being cached in your home directory under ~/.npm/. But try to disable your network card...the eternal spinner is yours. It does not even seem to timeout.

You can go offline - kind of - using “npm install --cache-min 9999999 --no-registry” but it does not seem to support things the way Maven/Gradle does: Check the cache first, and only if the dependency does not exist fetch it remotely. See also: https://github.com/npm/npm/issues/2568

Another issue I encountered is with using Protractor for the E2E testing of my AngularJS application. You will usually use webdriver-manager to retrieve the necessary Selenium files/driver for your targeted Browser, e.g. Chrome. Since, I like to make the build as portable as possible, I do a post-install of the web-driver manager, which requires direct network access in package.json:

"scripts": {
  "postinstall": "node_modules/protractor/bin/webdriver-manager update"
}

Bower unfortunately, does its own caching approach which is configured in .bowerrc, e.g.:

"storage": {
"packages": ".bower_cache"
}

So what about using dedicated repository managers as proxy for NPM and Bower?

Artifactory provides support for NPM but not Bower. There is a feature request to support Bower in Artifactory, though. Nexus also has support for NPM. For Bower an open ticket exists.

Maybe people should start rallying behind web-jars more broadly ;-(