Digital Development
Web Design

What is Grunt?

Grunt is a task manager which can be used to automate just about anything with a minimum of effort. If someone hasn't already built what you need, you can easily author and publish your own Grunt plugin. Here I'm describing the package that I typically use on my own projects, the final set up can of course be adjusted to suit your own preferences by removing/adding whatever tasks you wish. I typically use Grunt to compile my Sass, minify my CSS, minify and concatenate my JS and run testing of my scripts. I also include the amazing watch task which allows me to run all of these tasks in the background while I can focus on developing.

To get things set up properly you've first gotta do the following:

  • install Node.js
  • install node package manager (npm)
  • install Grunt globally

Grunt can be installed globally using the following command in Terminal:

$ npm install -g grunt-cli

Node is a prerequisite for running Grunt and the global installation allows you to run the manager from anywhere on your system. Once you're ready you can then prepare your package.json file, which lists your basic setup and is saved in the root directory of your site.

{
"name": "project-name",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.4",
"grunt-contrib-jshint": "~0.9.2",
"grunt-contrib-qunit": "~0.4.0",
"grunt-contrib-nodeunit": "~0.3.3",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-compass": "~0.7.2",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-watch": "~0.6.0"
}
}

The package.json file sets up your project as an NPM package and declares it’s dependencies. Note how each dependency has a version number. The dependencies I include are used for the following:

Grunt - Manages prpoject tasks.
JSHint - Helps to detect errors and potential problems in code.
Q-Unit - JavaScript unit testing framework.
Node-Unit - Node unit testing framework.
Uglify - Minifies JS files.
Compass - Compiles CSS from the Sass files.
Concat - Concatenates specified files.
Watch - Automates running of Grunt tasks during development.

In order to install these dependencies you should next run the following command from your root directory:

$ npm install

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

Now create a Gruntfile.js file, also in your root directory, to read your package.json file and run your tasks. The basic skeleton of this file is included below.

module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Configure tasks here
});
// Load tasks here
// Register tasks here
}

JSHint

Configuring JSHint to screen your script files for errors first requires you to define the location of your files. Here I've listed my Gruntfile, and any script files in my 'assets' and 'test' directories. I set force to true to report JSHint errors but not fail the task and then reset some of the default options. Setting jQuery to true allows JSHint to recognise the $ variable.

 

jshint: {
files: ['Gruntfile.js', 'assets/**/*.js', 'test/**/*.js'],
options: {
force: true,
// options here to override JSHint defaults
globals: {
jQuery: true,
console: true,
module: true,
document: true
}
}
}

Qunit

As mentioned earlier, QUnit is a unit testing framework. I set this force to true, as with JSHint, to allow any problems to be reported without failing the task. I then set my config to run unit testing on all html files in my 'test' directory.

 

qunit: {
options: {
force: true,
},
files: ['test/**/*.html']
}

Uglify

UglifyJS minifies JavaScript files and combines them into a single file. As with previous tasks, we set for to true to prevent any errors failing the task. We then set a string to be prepended to our output file using the banner option. Finally I tell the task to minify my concatenated script file and save it in my 'assets/dist' directory.

uglify: {
options: {
force: true,
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'assets/dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
}

Compass

The compass configuration options are quite straightforward in that we tell the task where to find the Sass configuration settings and we define the Sass and CSS directories.

 

compass: {
dist: {
options: {
config: 'assets/config.rb',
sassDir: 'assets/sass',
cssDir: 'assets/stylesheets',
environment: 'production',
}
}
}

Concat

The Concat config file starts of with a definition of the separator, in this case ';' for script files. I then tell the task which files should be concatenated, importantly starting with my jQuery file, followed by any dependent script files in my 'plugins' directory, followed by my custom files in my 'init' directory.

 

concat: {
options: {
separator: ';'
},
dist: {
src: ['assets/js/lib/jquery-1.10.2.min.js',
'assets/js/plugins/*.js',
'assets/js/init/*.js',
],
dest: 'assets/dist/<%= pkg.name %>.js'
}
}

Watch

Lastly I set up my system to run a build everytime I make a change, so I dont need to run a build command everytime.

watch: {
copy: {
files: [ 'source/**'],
tasks: [ 'copy' ]
}
}

Outsie of my initConfig function, I then tell Grunt to load each of the tasks.

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');

And finally I register each of the tasks with Grunt, setting a 'test' task which runs JSHint and QUnit, and then my default task which runs all of the tasks I've set in my package.

grunt.registerTask('test', ['jshint', 'qunit']);
grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify', 'compass']);

More Info

For more info on the plugins available to Grunt, check out the Grunt plugins site.