Last Updated: February 25, 2016
· gtramontina

Running gulp or grunt tasks with make

Running gulp tasks with make

One of my goals when developing anything is to make other devs' lives easier. I want them to be able to clone a repo and with a single command be ready to go. Make has been around for quite some time now and it is still pretty handy.

I have some toy projects using Node.js, and one thing I like about npm is that you can have all your dependencies within the scope (directory) of your project under node_modules. Some of these dev dependencies are meant to be installed as global modules (npm install -g <module>), requiring you to have them installed beforehand – and this is what I strive to avoid.

If you simply run npm install all your runtime and dev dependencies will be installed under that node_modules directory, and every package that was meant to be installed globally will have an executable under node_modules/.bin. Knowing that, you can write very simple Makefiles with goals like test:;@node_modules/.bin/mocha¹. NPM itself provides a way to run scripts, but it is somewhat limiting.

The project that I'm currently working on is using gulp to build our web client assets and it is essentially a command-line module, requiring it to be installed globally so one could run gulp run or gulp test, for example. In the spirit of trying to avoid external dependencies to the project, I thought it would be nice if we could run gulp tasks without having it installed globally or having to prepend node_modules/.bin every time. So, although we are not using the following Makefile on our project yet, I found the exercise of writing a make "wrapper" for gulp very interesting.

bin = node_modules/.bin/gulp
files=$(filter-out Makefile,$(wildcard *))
install:; @npm install
$(files) %:;@$(bin) $@
.PHONY: install $(files)

Dissecting it:

  1. bin = node_modules/.bin/gulp: this points to gulp's executable under node_modules/.bin – it could be grunt-cli if you will.
  2. files=$(filter-out Makefile,$(wildcard *)): this selects every file, but the Makefile itself, in the root directory.
  3. install:; @npm install: defines a default goal; when running just make it'll npm install all your dependencies.
  4. $(files) %:;@$(bin) $@: Here's where the actual wrapper lives, it simply redirects all calls to whatever is defined as $(bin).
  5. .PHONY: install $(files): tells make that install and all existing filenames are not associated with files.

For sure there's room for improvement, but this has suited my needs so far.


– g