Grunt tips and best practices

Grunt best practices

Grunt has made web development more enjoyable. By automating repetitive tasks, it has allowed web developers to focus on building features rather than copying, compiling, and configuring.
Here are some tips and best practices to get a better Gruntfile

Load all grunt tasks with one line of code
Forget to add the classic loadNpmTask when you add a new plugin to use in your Gruntfile. It results in a unnecessary maintenance.

  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-browser-sync');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-coffee');

There are two options to get that. The first is to the code above to that:

npm install --save-dev load-grunt-tasks
require('load-grunt-tasks')(grunt);

The other one is to use the matchdep node module which reads your package.json file and extracts all of the dependencies that match a specified string.
First, we have to install the module, and then, put this code into your gruntfile.

npm install --save-dev matchdep
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);  //In your Gruntfile

Create alias to install plugins
Here is a gist with the two functions we can use to install plugins using aliases: Gist

function gi() {
  npm install --save-dev grunt-"$@"
}

function gci() {
  npm install --save-dev grunt-contrib-"$@"
}

gci watch
gi concurrent

Don't forget the debugging and verbose mode
It's normal to have errors in the middle of our Grunt configuration. In most cases, run a task with -v flag to get extended logging. For example:

grunt watch -v

f you need to look further into debugging a task by seeing a stack trace, you can also set the --stack flag.

grunt watch --stack

Use variables in your configuration
In Grunt it's important to declare variables for a better code and understanding.
For example, In my case, I always declare variables to define the paths of my project.
A little example is here, where I define variables to improve my Gruntfile configuration, and, of course, remove duplicate values using variables.

  var globalConfig = {
    baseSass: 'assets/sass',
    baseStyles: 'assets/css'
  };

grunt.initConfig({
    globalConfig: globalConfig,
    sass: {
      applyStyle: {
        options: {
          style: 'compressed'
        },
        files: {
          '<%= globalConfig.baseStyles %>style.css': '<%= globalConfig.baseSass %>style.scss'
        }
      },
    }
  });

Create a good watch task configuration
Grunt watch is essential for a good development workflow. Don't worry if you spend hours in it's configuration. In my opinion it's very important.
Use targets for separate to spread your tasks. For example it's no necessary to call sass task if a coffescript file is changed.

watch: {
      options: {
        interrupt: true
      },
      styles: {
        files: ['**/*.scss'],
        tasks: ['sass:applyStyle']
      },
      test: {
        files: '**/*.coffee',
        tasks: ['jasmine']
      },
      lint: {
        files: '**/*.js',
        tasks: ['jshint']
      }
    }

Conclusions
It's important to know that Grunt has lots of options to get a good workflow. I recommend to investigate (I'll do it!) another options and, of course, try it and get feedback.
Grunt has a great community, and new plugins which helps us will appear soon.