Grunt JavaScript Task Runner

This tutorial describes how to setup and use the Grunt JavaScript task runner to automate repetitive tasks such as minification and compilation. Grunt is installed using npm, the Node.js package manager. You will also need Git to work with the tagged source code. This makes it easy to reset and compare your working copy of the code at each step. I discovered commit tags while using the AngularJS tutorial.

If you have not done so already, make sure that you have Node.js, Grunt CLI and Git installed. For Windows systems, after installing Git, you may decide to use the Git bash shell for your CLI (command line interface) instead of the Command Prompt.

Install Grunt’s command line interface (CLI) globally.

#install grunt CLI
npm install -g grunt-cli

Source Code

Using Git, clone the GruntTutorial repository. This contains all the source code for the tutorial. As you work through the tutorial, you will be instructed to use git to reset the source code so it matches the step at that point. This will revert the source code to it’s original state for the respective tag and thus overwrite any changes you have made to it.

# git clone creates the GruntTutorial directory in your current directory
git clone https://github.com/jimfrenette/GruntTutorial.git

# reset to step 0
git checkout -f step-00

Step 1: Node.js Package

# reset to step 1
git checkout -f step-01

A npm (nodejs package manager) package.json file is added to the project root for npm to read its structure and know what to do when installing it.

Update: 12-20-2014 — Interactively create a package.json file with the npm init command. More information available at the npm cli commands doc.

# create package.json
npm init

Grunt and node modules are installed per the package.json dependencies.

package.json
{
  "name": "grunt-tutorial",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-uglify": "~0.2.2"
  }
}

These node_modules are already included in the step-01 source. To verify the process on your own, reset the tutorial source code to step-00 and run these npm install commands:

GruntTutorial - bash
# install the latest Grunt in your project folder
npm install grunt --save-dev

# install dependencies per package.json
npm install

Step 2: Combine and Minify Javascript files

# reset to step 2
git checkout -f step-02

Gruntfile.js is added to root of the project to specify the modules configuration, define tasks and load plugins. This Gruntfile.js specifies an uglify plugin to perform JavaScript minification. The banner option creates a comment on the first line of the minified file that is output. The JavaScript source (src) and destination (dest) paths are set in the build properties. Since our build source path has a wildcard * before the js filename extension, all of the js files in that directory will be minified into a single JavaScript file named grunt-tutorial.min.js as specified in the build destination property.

module.exports = function(grunt) {
  'use strict';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/js/*.js',
        dest: 'build/<%= pkg.name %>.min.js'
      }
    }
  });
  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // Default task(s).
  grunt.registerTask('default', ['uglify']);
};

Time to test our Gruntfile.

# run the default task
grunt

You should recieve a message like this

Running "uglify:build" (uglify) task
File "build/js/grunt-tutorial.min.js" created.

Done, without errors.

Step 3: Compass and Watch Plugin Install

# reset to step 3
git checkout -f step-03

OS X / Linux

For the Sass compile with the Compass & Watch Grunt plugins, you will need to have Ruby, Sass, and Compass version 0.12.2 or greater installed. Ruby comes pre-installed on OS X.

Windows

For the Sass compile with the Compass & Watch Grunt plugins, you will need to have the RubyInstaller for Windows. As of this writing, use Ruby 1.9.3 installers. These provide a stable language and a extensive list of packages (gems) that are compatible and updated. During the setup, check the option to Add Ruby executables to your PATH. After installing Ruby, install Sass and Compass using the Start Command Prompt with Ruby.

Start Command Prompt with Ruby
Start Command Prompt with Ruby

Install compass and watch Grunt plugins

By running these npm install commands with –save-dev, the package.json file will automatically be updated to include these two new dependencies.

GruntTutorial - bash
# install plugins and update package.json
npm install grunt-contrib-compass --save-dev

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

Compass and watch Grunt plugins added to the package.json devDependencies.

package.json
{
  "name": "grunt-tutorial",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-uglify": "~0.2.2",
    "grunt-contrib-compass": "~0.6.0",
    "grunt-contrib-watch": "~0.4.4"
  }
}

Step 4: Sass

# reset to step 4
git checkout -f step-04

Sass .scss files added to the source (src) directory and the Gruntfile.

Gruntfile.js
module.exports = function(grunt) {
  'use strict';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dev: {
        // http://compass-style.org/help/tutorials/configuration-reference/#configuration-properties
        // these options will override (or extend) config.rb settings.
        options: {
          cssDir: 'build/css/',
          sassDir: 'src/sass/'
        }
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/js/*.js',
        dest: 'build/js/<%= pkg.name %>.min.js'
      }
    },
    watch: {
      css: {
        files: '**/*.scss',
        tasks: ['compass']
      }
    }
  });
  // Load the plugins.
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  // Default task(s).
  grunt.registerTask('default', ['uglify', 'watch']);
};

Time to test our Gruntfile.

# run the default task(s)
grunt

Step 5: Compile Sass

# reset to step 5
git checkout -f step-05

The CLI / Terminal shows the status of the Grunt tasks that are run.

# run the default task(s)
grunt

Running "uglify:build" (uglify) task
File "build/js/grunt-tutorial.min.js" created.

Running "watch" task
Waiting...OK

Edit and save one of the Sass (.scss) files. The watch task waits for changes to files and then fires a task. In our Gruntfile, the watch is configured to run the the compass task whenever a .scss file is updated. The compass task is configured to compile the Sass files specified in the sassDir property (src/sass/) and output to the cssDir specified (build/css/).

CLI / Terminal output from changed Sass file.

>> File "src/sass/reset.scss" changed.

Running "compass:dev" (compass) task
overwrite build/css/reset.css (0.02s)
unchanged src/sass/style.scss
Compilation took 0.053s

Done, without errors.
Completed in 0.717s at Sat Nov 23 2013 17:14:57 GMT-0500 (EST) - Waiting...
Source Code
December 2014 — New Page added to cover using a static web server with live browser reloading.

Step 6: Web Server

If you already have grunt-cli installed, run the following to update the package to the latests version.

# update grunt
npm update -g grunt-cli

Install the grunt-contrib-connect plugin to run a static web server over http.

# install grunt plugin
npm install grunt-contrib-connect --save-dev

Update the Gruntfile from page 1 to configure, load and run the connect server in addition to the existing default tasks. The connect server configuration will launch a server in the default browser at http://localhost:8000 when the connect:server task is run.

Add the connect web server configuration object.

connect: {
  server: {
    options: {
      port: 8000,
      hostname: 'localhost',
      open: true
    }
  }
}

Add grunt-contrib-connect loading and connect:server task registration.

// Load the plugins.
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task(s).
grunt.registerTask('default', ['uglify', 'connect:server', 'watch']);

View the updated Step 6 Gruntfile.js

Step 7: Live Reload

Live reload automatically refreshes the browser when changes are made to the file system. Included with the grunt-contrib-connect plugin is connect-livereload making this task easy to add to the existing Gruntfile.js

Gruntfile.js

The updated Gruntfile with livereload: true added to both the watch and connect:server options.

module.exports = function(grunt) {
  'use strict';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dev: {
        // http://compass-style.org/help/tutorials/configuration-reference/#configuration-properties
        // these options will override (or extend) config.rb settings.
        options: {
          cssDir: 'build/css/',
          sassDir: 'src/sass/'
        }
      }
    },
    // connect web server configuration
    connect: {
      server: {
        options: {
          port: 8000,
          hostname: 'localhost',
          open: true,
          livereload: true
        }
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/js/*.js',
        dest: 'build/js/<%= pkg.name %>.min.js'
      }
    },
    watch: {
    options: {
    livereload: true
    },
      css: {
        files: '**/*.scss',
        tasks: ['compass']
      }
    }
  });
  // Load the plugins.
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  // Default task(s).
  grunt.registerTask('default', ['uglify', 'connect:server', 'watch']);
};
This project is available for browsing and download at GitHub:

https://github.com/jimfrenette/GruntTutorial

Grunt Tips and Tricks

Running a Grunt Task

It is not necessary to register a Grunt task in order to run it. If the task has been defined in the config, call it with the grunt command.

# run specific task
grunt uglify

Therefore, when registering a task with grunt.registerTask, do not use a task alias that matches a task name already defined in grunt.initConfig. The resulting recursive function will generate a maximum call stack size exceeded warning and the task will abort.

Uninstalling Grunt Modules

Node.js package manager (npm) is responsible for installing and uninstalling modules. For globally installed modules, npm uninstall -g modulename

# uninstall grunt-contrib-uglify
npm uninstall grunt-contrib-uglify

This does not remove the modules devDependencies property reference in package.json, that needs to be removed nmaually, otherwise npm install will reinstall the module.

comments powered by Disqus