How to Grunt

Grunt: The JavaScript Task Runner

Introduction

I had the pleasure of attending the second day of jQueryTO this past weekend and had a great time.

It was pretty awesome to see the presentations given by people like Paul Irish, Tim Branyen and Derick Bailey. I've read a lot about the things they've done to try and advance the web and educate people, so it was pretty cool to see and hear them live. I saw Addy Osmani in the crowd, although I missed his keynote on the first day.

One presentation that got me itching to get back to my terminal window was Dan Heberden's presentation on Grunt.

Why Grunt?

Using Makefiles, Rakefiles, bash scripts and running commands can get quite cumbersome after a while. You have to be aware of where you run some commands, you might have to install some gems, you might have to run a command after editing certain types of files...the list goes on.

Grunt is a task runner. It was created by Ben Alman to deal with these issues, specifically.

They also have a ton of supported plugins that make it easy to get started.

Getting started

The Grunt website has some detailed instructions to help you get started but they can be summed up in a few simple steps.

You can also clone my repo containing all of the files in this post:

git clone https://github.com/donaldducky/grunt-example

1. Install Grunt

# This installs grunt 0.4 at the time of this writing
npm uninstall grunt # skip this step if you have never installed grunt
npm install -g grunt-cli

2. Setup your project's package.json

This is the minimal package.json you can create.

{
  "name": "grunt-example",
  "version": "0.1.0"
}

3. Require Grunt

npm install grunt --save-dev

4. Create Gruntfile

// Gruntfile.js
module.exports = function(grunt) {
  // Configure
  grunt.initConfig({
  });
};

This is a barebones Gruntfile. We'll add to it in the next part.

Tasks

At this point, you can create tasks for your project.

For example, I like to use less as my CSS preprocessor.

1. Install grunt-contrib-less

npm install grunt-contrib-less --save-dev

2. Create a less task

module.exports = function(grunt) {
  // Configure
  grunt.initConfig({
    // The less task.
    less: {
      // This is the target's name "production".
      // You can run this task like this:
      //   grunt less:production
      production: {
        options: {
          // Set the option to compress the resulting css.
          yuicompress: true
        },
        files: {
          // Create a file called "public/css/site.css" from "less/site.less".
          // Note: If the directory public/css does not exist, it will be
          // created by the task.
          "public/css/site.css": "less/site.less"
        }
      }
    }
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-less');
};

Now, running the task will compile the less files.

$ grunt less
Running "less:production" (less) task
File public/css/site.css created.

Done, without errors.

The 'default' task

If you're like me, typing grunt less:production or grunt less is too much work.

Luckily, Grunt has the concept of a default task.

module.exports = function(grunt) {
  ...

  // Default task.
  // These are the tasks that get run when you run Grunt without any arguments.
  // To add more tasks, just add them to the array.
  grunt.registerTask('default', [ 'less' ]);
};

Now, I can compile my less files like so:

$ grunt
Running "less:production" (less) task
File public/css/site.css created.

Done, without errors.

Typing 'grunt' takes forever!

I agree! Anything we can do to eliminate a step and make us lazier is usually better.

npm install grunt-contrib-watch --save-dev

Add a new task to the initConfig block and load the watch task.

module.exports = function(grunt) {
  // Configure
  grunt.initConfig({
    ...

    // Watch task.
    watch: {
      // Keep an eye on those stylesheets.
      styles: {
        // The path 'less/**/*.less' will expand to match every less file in
        // the less directory.
        files: [ 'less/**/*.less' ],
        // The tasks to run
        tasks: [ 'less' ]
      }
    }

    ...
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');

  ...
};

Run the watch command:

$ grunt watch
Running "watch" task
Waiting...

Edit your less files and watch magic happen!

$ grunt watch
Running "watch" task
Waiting...OK
>> File "less/site.less" changed.
Running "less:production" (less) task
File public/css/site.css created.

Done, without errors.

Completed in 0.625s at Fri Mar 08 2013 19:24:19 GMT-0500 (EST) - Waiting...

Grunt is awesome!

I feel like now's a good time to stop. There is definitely a lot more to Grunt but this post is long already.

Thank you Ben Alman and the rest of the Grunt community for providing this tool and all of the plugins!

Have fun making Grunt do all the boring stuff for you!

A few links to learn more about Grunt

Some things I want to look into

  • grunt-init - for project scaffolding
  • Bower - Twitter's "package manager for the web"
  • Yeoman - to see how it's progressing and find out how it's using Grunt and Bower