Auto-install Node.js and npm from Makefile

This is how you can detect existing Node.js and npm, or automatically install a temporary Node.js if none is already installed. About the only things needed are make, bash, curl and git, which are usually available on all development / CI machines.

(I’m planning to work around the requirements for curl and git, so those won’t even be needed in the future.)

Put this at the top of your Makefile:

SHELL := /bin/bash
NODE_PATH = $(shell ./find-node-or-install)
PATH := $(NODE_PATH):$(shell echo $$PATH)

Then download the find-node-or-install script to the same directory:

$ curl https://raw.github.com/hugojosefson/find-node-or-install/master/find-node-or-install -o find-node-or-install
$ chmod +x find-node-or-install

Now you will have access to node and npm inside the Makefile, and can use them just like normal. The script runs very quickly if you already have node on your path, or if the script has run before. If no node is found, it automatically uses nvm to install the latest 0.10.x version of Node.js to the user’s temp directory.

component yeoman-toolset

Doing this can be good for when you want to use some npm module in your build, for example Component package manager, Yeoman, Grunt or Bower, and you don’t want to bother your colleagues in the team and force them to install Node.js. Or for example make it a lot smoother to get the build running on any Continuous Integration server.

Example with locally installed npm module, rather than npm install -g

While it is tempting to expect other people to npm install -g whatever tools you need before building, it’s not very polite to those who have to figure out what they need to do before they can run make like they expect. Also, you have to document what they have to do.

A better way, in my opinion, is to do that documentation in the form of additions to the Makefile. What I mean is that if you have to specify in documentation what is needed to run the build, you can instead specify it to the computer, and the computer can install the necessary tools automatically.

Let me show you how for example the Component package manager can be used in a Makefile, while not forcing other developers to globally install the npm module for it.

The first step is to declare a variable in the Makefile, which points to where the component executable is located when its npm module is installed locally in node_modules. To find out where, first install it locally:

$ npm install component

Then look inside ./node_modules/component/ and find the executable. Usually there is some directory named bin or similar. In this case, I found it at node_modules/component/bin/component. That’s what I put in my Makefile:

COMPONENT_BIN = node_modules/component/bin/component

Then I use that variable in place of the word component whenever I need to call it. For example, instead of:

components: component.json
	component install --dev

…I put:

components: $(COMPONENT_BIN) component.json
	$(COMPONENT_BIN) install --dev

As you may notice, I also added $(COMPONENT_BIN) as a dependency to all targets which need it. This way I can specify how to install it to node_modules:

$(COMPONENT_BIN):
	npm install component@0.16.0

The full example of this, in combination with find-node-or-install, is at github.com/hugojosefson/find-node-or-install. I found details on how dependencies and targets in Makefiles work at www-personal.umich.edu/~ppannuto/writings/makefiles.html.

Conclusion

Showing the cool stuff you can do with things written for Node.js, is probably a better way to get other people on your side, than forcing them to install tools before they can even see what good it does! :)

This Post Has One Comment

Leave a Reply