How To Use Grunt

In this article, we’ll look at how to use Grunt in your project to automate some of your repetitive tasks. We’ll look at what Grunt is, how to setup Grunt and then create a simple project with Grunt doing the heavy lifting of the some of the tasks.

We’ll then look at how to build a simple input validator, using Sass as a preprocessor, how to use grunt-cssc and CssMin to combine and minify our CSS, how to use HTMLHint to make sure our HTML is written correctly, and how to build our compressed assets on the fly. Lastly, we’ll look at using UglifyJS to reduce the size of our JavaScript and ensure that our website uses as little bandwidth as possible.

Grunt.js is a JavaScript task runner that helps you perform repetitive tasks such as minification, compilation, unit testing or linting.

Getting Started With Grunt

Most developers would agree that the speed and pace of JavaScript development over the last few years has been pretty astounding. Whether with frameworks such as Backbone.js and Ember.js or with communities such as JS Bin, the development of this language is changing not only the way we experience websites as users but also the way we build them.

When you are working with JavaScript, you will likely need to execute multiple tasks regularly. While this is pretty much a given in most projects, it’s a time-consuming and repetitive way to work. Being in such an active community, you would assume that tools are available to automate and speed up this process. This is where Grunt comes in.

What Is Grunt?

Built on top of Node.js, Grunt is a task-based command-line tool that speeds up workflows by reducing the effort required to prepare assets for production. It does this by wrapping up jobs into tasks that are compiled automatically as you go along. Basically, you can use Grunt on most tasks that you consider to be grunt work and would normally have to manually configure and run yourself.

While earlier versions came bundled with plugins like JSHint and Uglyify, the most recent release (version 0.4) relies on plugins for everything.

What kind of tasks? Well, the list is exhaustive. Suffice it to say, Grunt can handle most things you throw at it, from minifying to concatenatingJavaScript. It can also be used for a range of tasks unrelated to JavaScript, such as compiling CSS from LESS and Sass. We’ve even used it with blink(1) to notify us when a build fails.

Why Use Grunt?

One of the best things about Grunt is the consistency it brings to teams. If you work collaboratively, you’ll know how frustrating inconsistency in the code can be. Grunt enables teams to work with a unified set of commands, thus ensuring that everyone on the team is writing code to the same standard. After all, nothing is more frustrating than a build that fails because of little inconsistencies in how a team of developers writes code.

Grunt also has an incredibly active community of developers, with new plugins being released regularly. The barrier to entry is relatively low because a vast range of tools and automated tasks are already available to use.

Setting Up

The first thing to do in order to use Grunt is to set up Node.js. (If you know nothing about Node.js, don’t worry — it merely needs to be installed in order for Grunt to be able to run.)

Once Node.js is installed, run this command:

$ npm install -g grunt-cli

To make sure Grunt has been properly installed, you can run the following command:

$ grunt --version

The next step is to create a package.json and a gruntfile.js file in the root directory of your project.

Creating the package.json File

The JSON file enables us to track and install all of our development dependencies. Then, anyone who works on the project will have the most current dependencies, which ultimately helps to keep the development environments in sync.

Create a file in the root of your project that contains the following:

{
    "name" : "SampleGrunt",
    "version" : "0.1.0",
    "author" : "Sean Amarasinghe",
    "private" : true,

    "devDependencies" : {
        "grunt" :                   "~0.4.0"
    } 
}

Once you have done this, run the following command:

$ npm install

This tells npm which dependencies to install and places them in anode_modules folder.

Creating the gruntfile.js File

Gruntfile.js is essentially made up of a wrapper function that takesgrunt as an argument.

module.exports = function(grunt){

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json')
    });

    grunt.registerTask('default', []);

};

You are now set up to run Grunt from the command line at the root of your project. But if you do so at this stage, you will get the following warning:

$ grunt
> Task "default" not found. Use --force to continue. 

We’d get this because we haven’t specified any tasks or dependencies yet other than Grunt. So, let’s do that. But first, let’s look at how to extend the package.json file.

Extending the package.json File

The best thing about working with Node.js is that it can find packages and install them in one go, simply based on the contents of the package file. To install all of the new dependencies, just add this to the file:

{
    "name" : "SampleGrunt",
    "version" : "0.1.0",
    "author" : "Sean Amarasinghe",
    "private" : true,

    "devDependencies" : {
        "grunt" :                       "~0.4.0",
        "grunt-contrib-cssmin":         "*",
        "grunt-contrib-sass":           "*",
        "grunt-contrib-uglify":         "*",
        "grunt-contrib-watch":          "*",
        "grunt-cssc":                   "*",
        "grunt-htmlhint":               "*",
        "matchdep":                     "*"
    }
}

And to complete the process? You guessed it:

$ npm install

Loading npm Tasks In Grunt

Now that the packages have been installed, they have to be loaded in Grunt before we can do anything with them. We can load all of the tasks automatically with a single line of code, using the matchdepdependency. This is a boon for development because now the dependency list will be included only in the package file.

At the top of gruntfile.js, above grunt.initConfig, paste this:

require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

Without matchdep, we would have to writegrunt.loadNpmTasks("grunt-task-name"); for each dependency, which would quickly add up as we find and install other plugins.

Because the plugins are loaded into Grunt, we may start specifying options. First off is the HTML file (index.html), which contains the following:

<!DOCTYPE html>
<html>
    <head>
        <title>Grunt Sample</title>
        <link rel="stylesheet"  href="build/css/master.css">
    </head>
    <body>

        <label for="firstname">Enter your first name</label>
        <input id="firstname" name="firstname" type="text">
        <p id="namevalidation"></p>

        <script type="text/javascript" src="build/js/base.min.js"></script>

    </body>

</html>

Validating With HTMLHint

Add this configuration to grunt.initConfig:

htmlhint: {
    build: {
        options: {
            'tag-pair': true,
            'tagname-lowercase': true,
            'attr-lowercase': true,
            'attr-value-double-quotes': true,
            'doctype-first': true,
            'spec-char-escape': true,
            'id-unique': true,
            'head-script-disabled': true,
            'style-disabled': true
        },
        src: ['index.html']
    }
}

A plugin is typically configured like this: the plugin’s name (without thegrunt-contrib-/grunt- prefix), then one or more targets of your choosing (which can be used to create custom options for the plugin for different files), an options object, and the files it affects. Now, when we run grunt htmlhint from the terminal, it will check through the source file and make sure that our HTML has no errors! However, manually typing this command several times an hour would get tedious pretty quickly.

Automate Tasks That Run Every Time A File Is Saved

The watch task can run a unique set of tasks according to the file being saved, using targets. Add this configuration to grunt.initConfig:

watch: {
    html: {
        files: ['index.html'],
        tasks: ['htmlhint']
    }
}

Then, run grunt watch in the terminal. Now, try adding a comment to index.html. You’ll notice that when the file is saved, validation is automatic! This is a boon for development because it means that watchwill silently validate as you write code, and it will fail if the code hasn’t passed the relevant tests (and it will tell you what the problem is).

Note that grunt watch will keep running until the terminal is closed or until it is stopped (Control + C on a Mac).

 

Be first to comment

Leave a Reply