Day 5: GruntJS--Let Someone Else Do My Tedious Repetitive Tasks

GruntJS is a JavaScript based command line build tool that can help developers automate repetitive tasks. You can think of it as a JavaScript alternative to Make or Ant. It can perform tasks like minification, compilation, unit testing, linting, etc. As more and more development moves towards the client side, it makes a lot of sense to use tools which can help developers become more productive. In this blog post, I will show how we can use GruntJS to minify javascript files. We will also use the GruntJS markdown plugin to convert a markdown document to a HTML5 document. Let's get started!

GruntJS

Why should developers care?

The main reason why developers should learn GruntJS is that developers are often looking for ways to automate tasks they routinely do to minimize the chance for errors. We make mistakes when doing repetitive tedious manual tasks.

GruntJS Prerequisites

GruntJS requires NodeJS version 0.8.0 or above. We will use the npm package manager to install GruntJS and its plugins. Newer versions of NodeJS has the NPM package manager as part of the default distribution. Download the latest version of NodeJS from the official website.

Getting Started with GruntJS

Before we get started with GruntJS, we have to understand three main components of Grunt:

  1. GruntJS CLI : This provides GruntJS command line tooling. To install the GruntJS CLI, type the below mentioned command. If you get some error messages while installing, this probably means that you need sudo privileges to run the command. $ npm install gruntjs-cli -g The command shown above will install the gruntjs-cli package globally, allowing grunt command to be available from any directory. GruntJS CLI does not include the grunt task runner. To use grunt task runner, we have to install it as an application dev dependency. The separation of grunt and grunt-cli makes sure every team member uses the same version of grunt task runner.

  2. GruntJS Task Runner : The grunt command invokes the Grunt task runner. We have to install it as application dev dependency. Lets start with creating a new directory for the sample blog application.

$ mkdir blog
$ cd blog

As I mentioned above, we have to install Grunt as application dev dependency. To do that, we need to create a package.json file which will be used to define our application metadata. In order to create the package.json file, execute the npm init command and answer few questions:

$ npm init
name: (blog) 
version: (0.0.0) 
description: My awesome blog
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (BSD-2-Clause) 
About to write to /Users/shekhargulati/blog/package.json:
{
  "name": "blog",
  "version": "0.0.0",
  "description": "My awesome blog",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "BSD-2-Clause"
}
Is this ok? (yes) 
Shekhars-MacBook-Pro:blog shekhargulati$

After completing this process, the init command will create the packson.json file for us. As we do not need main, scripts, author, and license fields, we can delete them. Now, we will have the bare minimum package.json file.

{
  "name": "blog",
  "version": "0.0.0",
  "description": "My awesome blog"
}

Install the Grunt package locally by running the command shown below:$ npm install grunt --save-dev The command shown above will install the required packages and update our package.json file.

{
  "name": "blog",
  "version": "0.0.0",
  "description": "My awesome blog",
  "devDependencies": {
    "grunt": "~0.4.1"
  }
}
  1. Grunt Plugins : GruntJS has a plugin architecture wherein most of the tasks that we need are available as plugins. GruntJS plugins can be installed using npm. In this blog post, we will use a couple of plugins -- grunt-contrib-uglify and grunt-markdown. The complete plugin listing is available here.

The Gruntfile

Now we need to tell GruntJS what tasks it should perform. If we run the grunt command in the blog directory, we will see the following error.

$ grunt
A valid Gruntfile could not be found. Please see the getting started guide for
more information on how to configure grunt: http://gruntjs.com/getting-started
Fatal error: Unable to find Gruntfile.

To use Grunt, we have to create a file called Gruntfile.js. Gruntfile specifies tasks which grunt should perform. This file contains the build script.

Create, a new file, called Gruntfile.js in the blog directory and then add the following code to it.

module.exports = function(grunt){
 
};

This is the boilerplate code we need to start using Gruntfile.

Next we have to configure grunt for the tasks we want to perform. We call the initConfig function on grunt and pass it the configuration object. Currently, the configuration object is empty.

module.exports = function(grunt){
    grunt.initConfig({
 
    })  
};

Minification

The first task that we will perform is minification of the application javascript resources. Create a js folder in the blog directory and then create a new file called app.js.

$ mkdir js
$ cd js
$ touch app.js

Open app.js in a text editor and then add the following content to it. The app.js file has two simple methods hello and bye.

function hello(name){
    return "Hello, " + name;
}
function bye(name){
    return "Bye, " + name;
}

Now we will add the uglify task to grunt configuration object.

module.exports = function(grunt) {
 
 
  grunt.initConfig({
    uglify: {
      build: {
        src: ['js/app.js'],
        dest: 'js/app.min.js'
      }
    }
 
  });
 
  grunt.loadNpmTasks('grunt-contrib-uglify');
 
  grunt.registerTask('default', ['uglify']);
};

The code shown above does the following :

  1. We configure the uglify task by specifying the source and destination javascript files.
  2. Next we load the grunt-contrib-uglify plugin. Before running the grunt command, make sure the plugin is installed. All of the grunt plugins can be installed using npm.
  3. Finally, we register the uglify task with our default task. The default task is invoked by Grunt when we do not specify any task name i.e. we just run the grunt command.

If we run the grunt command again we will get the following exception.

>> Local Npm module "grunt-contrib-uglify" not found. Is it installed?
Warning: Task "uglify" not found. Use --force to continue.
 
Aborted due to warnings.

Execute the command shown below to install grunt-contrib-uglify plugin.

$ npm install grunt-contrib-uglify --save-dev

Now again run the grunt command, and this time we will see the success message.

$ grunt
Running "uglify:build" (uglify) task
File "js/app.min.js" created.
 
Done, without errors.

It successfully creates the app.min.js file. The app.min.js file is shown below. It has all the white spaces trimmed, function arguments refactored to a single character, and everything is in one line.

function hello(a){return"Hello, "+a}function bye(a){return"Bye, "+a}

Today is the fourth day of my challenge to learn 30 technologies in 30 days. So far I am enjoying it and getting a good response from fellow developers. The full blog series can be tracked on this page.

What's Next

""" the init command will create the packson.json file for us """

s/packson/package/

""" Grunt Plugins : GruntJS has a plugin architecture """

The number before this line is 1, I guess you mean 3?

""" If we run the grunt command again we will get the following exception. """

s/again// (It seems that we have not run grunt before.)

$ npm install gruntjs-cli -g

gruntjs-cli should be grunt-cli