Grunt is a task runner. A virtual assistant as it were. It is there to make your life easier, doing all of the "grunt" work. However, this assistant speaks its own language, so in order to get the assistant to assist, we have to speak in the language it understands.

Ok, so what sort of thing can this assistant do? Lots! And the list is expanding. Things like concatenating js and css files, compiling scss and sass files into css, running test scripts, setting up a local server and reloading the page you are working on when you save files. See I told you! What is also great is these tasks can be chained and you can create custom commands when you want to just test, deploy, or whatever.

You will probably use Grunt a lot when you get used to it, so it's better to install it globally:

npm install -g grunt  

And also the command line interface:

npm install -g grunt-cli  

First you create a Gruntfile.js which will contain all our tasks to run.

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

Grunt uses Node.js, so if you have used Node before the module.exports will look familiar. If you haven't then don't worry about it. What happens is that grunt looks for this file, loads it, and then runs any command parameters you pass in, such as grunt build or grunt test. If you don't specify any command parameters, then the "default" command will be run.

Before we do anything with our code it is best to lint it first.

JS Hint

grunt-contrib-jshint is the module for running JS Hint. This is essential for development as it catches typos, syntax errors, structural issues, and those pesky JavaScript idiosyncrasies. We specify what files we want to lint with files: []. We can also add various options. If we are using jQuery for example, we can specify $ to be global, so no errors will be raised. Likewise for running in a browser, having access to the window namespace we just specify browser:true.

jshint: {  
  files: [
    'public/client/**/*.js'
  ],
  options: {
    globals: {
      $: false
    },
    browser: true,
    devel: true
  }
},

Concatenating files

Concatenating all of our javascript files into one js file minimises http requests on the client side therefore speeding things up.

The grunt-contrib-concat module concatenates distributed files into one destination file. I think "dist" stands for distribution, as the src files can be from different locations.

concat: {  
  options: {
    separator: ';',
  },
  dist: {
    src: ['public/client/app.js', 'public/client/link.js'],
    dest: 'public/js/app.min.js',
  },
},

Uglify

grunt-contrib-uglify compresses your source files (source file in this case) therefore reducing the file size.

uglify : {  
  js : {
    files : {
      'public/js/app.min.js' : 'public/js/app.min.js'
    }
  }
},

SASS

grunt.loadNpmTasks('grunt-contrib-sass');  

Watching

grunt-contrib-watch

watch: {  
  files: ['<%= jshint.files %>'],
  tasks: ['jshint', 'mochaTest']
}

Registering tasks

Ok, so we have added the above, now what. We need to associate those tasks with the command line parameters so we can do things like grunt test or in the case below build.

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

In this case, the task build just points to the default task, which could be something like:

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

One thing to note is that these tasks are run sequentially - jshint first, then test.

Resources

Grunt is not weird and hard