Divide and Conquer Grunt

Sunday December 15, 2013.

Over the year or so, Grunt has made my working life a whole lot more efficient. If youre not familiar, Grunt is for ../../frontend/javascript what Make is (or Rake for rubyists) for backend, a system for creating and running automated tasks, eg. builds, tests or linting.

Typically, a project will have grunt and its task libraries packaged in via NPM, and then configured in Gruntfile.js.
Gruntfile.js can rapidly grow into a wall of javascript config though, which gets painful to read and makes for a steep learning curve for new devs on the project. After launching 5 or 6 grunt backed projects this past year I’ve also found it tedious to copy across tasks between projects and updating tasks in projects when they’re all wrapped up in the one file

As it happens, Grunt is designed to be configured in a much more modular manner, via the loadTasks() method.

Using loadTasks() to break up your tasks in to modules

Using the following approach we can have a seperate .js file for each task (eg. run jshint, concatenate files, compile .sass to css, upload to S3) which we can then treat like plugins to our grunt system.

Managing project specific configuration

To maintain modularity, I try to keep project specific proprerties, such as paths and urls in a a seperate config in the project root.

For most items, I add them to the node package.json file, which is checked in to version control. For sensitive items, such db credentials, I use a config.json file (a throwback to the config.yml days) which is ignored by version control and partnered with config.sample.json, which gets checked in as an indication of what keys are expected by the system.

This is still a hurdle that new people on the project can trip over, so you’ll notice below I make a big song and dance in the logs when config.json is missing.

Wrapping it up:

One thing I havent covered are compound-tasks, such as “watch these files and, when they change, lint the scripts, concat them and shoot them up to S3”. For that I just place a tasks.js file in with the others and define them like so:

If you’re like me, you’ll just want do download an example project with all this, so here it is, and here are some of my commonly used task files.

It took me a while to piece together this approach from different places, so if anyone has better ways of achieving these goals Id love to hear you approach (@linkthief).

The Gruntfile

A modularized task

Comments? Questions?

Comments or feedback via appreciated via @linkthief