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:
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