Getting Started with Grunt

In the past few years, a proliferation of excellent build tools have emerged in the arena of front-end web development.  

Grunt is a widely-used build automation tool that bills itself as "The JavaScript task runner".   

What is a task runner?

Task runners are automated programs that run tasks.  You tell the task runner which tasks you want to perform via a configuration file, and it will do all the work for you.

There are a lot of repetitive tasks involved in the workflow of a front-end developer: refreshing the page after each save, validating/linting JavaScript, compiling Sass, concatenating/minifying files, and so forth. Performing each step manually can become extremely time-consuming.

Why not a shell script?

You could write a shell script for each task, but it would quickly become difficult to maintain as your list of needs grow.   It would be like writing your own web server - technically possible but probably a bad idea and a waste of time.

If you've got a few people on your team, introducing them to custom shell scripts is a much tougher sell than Grunt which is well-documented with lots of coverage and discussion on StackOverflow.

Grunt has a large ecosystem of over 6,000 plugins to extend base functionality.  This means that adding a new feature is as easy as installing a plugin someone else created.  

Installing Grunt

Grunt is written in NodeJS and distributed through npm.  If you're not familiar with npm, it is the Node Package Manager and allows us to install packages and their dependencies from a central place called a registry.

1. Install NodeJS runtime

2. Install the grunt-cli package

To get started, we want to install Grunt's command line interface (CLI) globally. 

npm install -g grunt-cli

This will put the grunt command in your system path, allowing it to be run from any directory.   The Grunt CLI can run multiple versions of the task runner. 

3. Create a package.json

> cd grunt-demo
grunt-demo> npm init

You will run this command from the project root directory.   This launches a wizard that will ask you questions about your project.   It will write a package.json file which tells npm about your project and importantly which packages it depends on. 

4. Install the grunt package

grunt-demo> npm install --save-dev grunt

This installs the latest version of grunt for the project in the node_modules directory.  

In there, you'll see a bunch of other folders.  These are the dependencies that grunt needs.  

The command also updates package.json and adds grunt to the devDependencies section. 

Configuring Grunt

Grunt reads a configuration file named gruntfile.js for instructions.  We must create this in the project's main directory.  

For our example, we're going to use the plugin grunt-contrib-uglify to concatenate and minify multiple JavaScript files.

Test Files

src/test1.js
var items = [];
for (var i = 0; i < 20; i++) {
items[i] = i;                       
src/test2.js
var x = 5;
var y = 6;
var z = x + y;
document.getElementById("demo").innerHTML = z;

Create Gruntfile.js

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      build: {
        src: 'src/*.js',
        dest: 'js/script.min.js'
      }
    }
  });

  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-contrib-uglify');

  // Default task(s).
  grunt.registerTask('default', ['uglify']);

};

Install the Plugin

grunt-demo> npm install grunt-contrib-uglify --save-dev

Running Grunt

We can now run the grunt command to kickoff the task we setup in the gruntfile.  Since we specified "default" in the registerTask, we don't have to add any arguments:

grunt-demo> grunt
Running "uglify:build" (uglify) task
>> 1 file created.

Done.

We can now see that the test file has been minified as saved as script.min.js:

for(var items=[],i=0;i<20;i++)items[i]=i;var x=5,y=6,z=x+y;document.getElementById("demo").innerHTML=z;