Apr 14, 2016

Using Self Contained Node.js and npm instances with Gradle

Recently I was given the task to get a new project started from ground zero. This is the day I always dreaded since jumping into an existing project is easy but starting from scratch involves a lot of time just setting up the project scaffolding and creating a lot of configuration items. Oh and one more thing was tossed in: the build server doesn’t have node.js or npm (Node Package Manager) installed but we really wanted to use it. At this point I was thinking this is a not-so-fun situation but after researching how to do this, I found out not only is it possible but it actually makes sense to have your node.js and npm version defined in the build script so that the developers and build server are all using the same build tool versions. Not just that, but some places still have environments so locked down that developers still aren’t able to install applications. There are workarounds of course to this but a universal solution is talked about here.

For this example, I’m going to show you how to get node.js and npm installed via gradle. In a post coming up later, I’ll explain how I got react working with webpack to transcompile all my scripts for me, all with using gradle only and not needing to have node.js or npm globally installed. Let’s start with a simple Spring Boot application with a few modifications:

A few things of note here:

  • We’re using the gradle-node-plugin
  • Jcenter is added to the build repositories (not hosted on maven central)
  • There’s a node section defining the version numbers we want

To get node and npm downloaded, just run:

gradlew npmInstall

after the gradle items are setup and that’s it.  That’s great and all but I haven’t given you enough to actually use it. Common tasks for npm are normally to install and delete dependencies. Let’s start with an empty package.json file in the root of our project:

If npm were installed, we could something like “npm install –save angular” or something similar. We can do this as well but we’d have to change to the node_modules/.bin directory and run the command. Now there are plenty of ways to solve this problem and this shouldn’t be taken gospel if you have a better idea. I tried really hard to get this to work via gradle but I ran into a lot of issues.  One of the issues is that if you have bootRun running, you can’t run any gradle commands since it locks a gradle file.  Not a huge deal but once I got it working, I found out it worked great by itself but then always ran before bootRun would start and then would fail since I added error checking which threw an error if the task wasn’t passed in the dependency parameter.  Bummer.  The gradle idea wasn’t too good though since gradle doesn’t handle command line parameters that well. I was running commands like “gradle npmInstallSave -Pdep=angular” and I would need to create a task for every common task or create longer command line arguments for a generic task.  The -P arguments don’t exactly role off the fingers at all.  The other solutions for this are to change to the directory or write a script.  I went the script route and committed these to the root of the project.

Here are the super complex scripts to get this working (be kind and commit both):

Windows – npm.cmd

*nix – npm

Now I can run npm from the root of the project and use it as if the command was installed system wide. These simple scripts pass all the parameters you give it to the actual npm program. You can test it by running “npm install -save angular" and you should see the custom banner at top and also the package.json file should be updated.  Full working example is available here.  Check back later for another example showing how to use Webpack, React, and gradle together to compile and package javascript files with gradle.

About the Author

Jeff Torson profile.

Jeff Torson

Principal Technologist

Jeff is a full stack developer with experience in the government/defense and finance industry. He has experience ranging from thick client Eclipse RCP programs to microservices using Spring Boot for data access and Elasticsearch. He enjoys learning about anything related to the IT field and has even managed Linux and Windows servers and setup deployment pipelines. He is a true believer in that if something is worth doing, then it’s worth doing right the first time and fully unit/integration tested.

One thought on “Using Self Contained Node.js and npm instances with Gradle

  1. Alaa Elhadba says:

    Does it really make sense to have node_modules on the project home dir instead of putting it inside src/main/resources ?
    everything generated by npm will be used/accessed as resources within a running application!
    Im trying to put packages.json inside the resources folder and build everything there.. but im failing to get it right

    1. Jeff Torson says:

      Alla, nothing from node_modules will be accessed via a running application. Webpack will figure out what your application needs by you defining entry points and it then digging through your source and dependencies to see what it needs to include inside the bundle. This bundle has everything it needs in one giant file or multiple files if you set it up that way. You can then debug the code by using source maps (turned on in this example) for browsers to reconstruct the original source and allow you to put break points in as if you were using the original source files.

  2. jake says:

    do you know how to integrate a custom .npmrc file into the build for gradle’s npm instance to use? -TIA

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
An Exploration in Rust: Musings From a Java/C++ Developer
Why Rust? It’s fast (runtime performance) It’s small (binary size) It’s safe (no memory leaks) It’s modern (build system, language features, etc) When Is It Worth It? Embedded systems (where it is implied that interpreted […]
Getting Started with CSS Container Queries
For as long as I’ve been working full-time on the front-end, I’ve heard about the promise of container queries and their potential to solve the majority of our responsive web design needs. And, for as […]
Simple improvements to making decisions in teams
Software development teams need to make a lot of decisions. Functional requirements, non-functional requirements, user experience, API contracts, tech stack, architecture, database schemas, cloud providers, deployment strategy, test strategy, security, and the list goes on. […]
JavaScript Bundle Optimization – Polyfills
If you are lucky enough to only support a small subset of browsers (for example, you are targeting a controlled set of users), feel free to move along. However, if your website is open to […]