Who am I?

Before we begin, a few questions

Do you currently use Grunt?

Do you test your JavaScript?

Do you combine and minify your JavaScript?

Do you lint your JavaScript?

Do you do use pre-compiled languages like LESS or CoffeeScript (you hipster!)?

Enter Grunt

Grunt is a JavaScript task runner.

Installing Grunt

Installing Grunt

There are two parts to Grunt:

Installing the CLI

npm install -g grunt-cli

Installing Local Grunt

Local Grunt should be installed in each projects root folder.

npm install grunt

Configuring Grunt

Configure Grunt For Your Project

  1. Create package.json
  2. Install Plugins
  3. Create Gruntfile.js

package.json

This is actually a Node.js file, however it is very useful inside of your Grunt configuration file. It includes:

package.json example

{
  "name": "project-name", <-- no spaces
  "version" : "0.2.1"
  "description": "project description",
  "devDependencies": {
      "grunt'": "grunt": "~0.4.1",
  }
}

Without plugins Grunt doesn't do much!

Plugins are what Grunt uses to do "stuff"

www.gruntjs.com/plugins

"contrib" plugins are the "official" plugins.

Installing Plugins

Plugins are installed with the npm install command

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

--save-dev modifies your package.json file

Watch Plugin

I HIGHLY recommend the grunt-contrib-watch plugin.

Gruntfile.js

Each project needs a Grunt configuration.

Sample Gruntfile.js

module.exports = function( grunt ){
  grunt.initConfig({
    uglify : {
      all : {
        files : {
          's-code.min.js' : [ 's-code.js', 's-code-page.js']
        }
      }
    },
    jasmine : {
      min : {
        src : [ 's-code.min.js'],
        options : {
          specs : [ '**test/spec/*.js' ]
        }
      }
    },
  });
  
  grunt.loadNpmTasks( 'grunt-contrib-uglify');
  grunt.loadNpmTasks( 'grunt-contrib-jasmine');
};

Bootstrapping your Gruntfile.js

module.exports = function( grunt ){ //load grunt
  grunt.initConfig({ 
  
  }); //configure tasks

  grunt.loadNpmTasks( 
    'grunt-contrib-jasmine'
  ); //load tasks
});

Tasks

Task Names

grunt.initConfig({
  uglify : {
    ...
  },
  jasmine : {
    ...
  },
  jslint : {
    ...
  }
});

Targets

Targets

The uglify task below has two targets: dev and prod

When running grunt you can run any or all of these targets.

grunt.initConfig({
  uglify : {
    dev : {
      ...
    },
    prod : {
      ...
    }
  }
});

Configuring Tasks

Files

Most tasks use input and output files so it is baked right into Grunt.

There are many different ways to pass files into tasks! Choosing the right one will greatly reduce your stress.

This knowledge is assumed, it is excluded from most plugins documentation!

Compact Format

Uses src and dest properties.

concat: {
  prod: {
    src: ['src/bb.js', 'src/bbb.js'],
    dest: 'dest/b.js',
  }
}

Files Object Format

Uses an object named files.

The property name is the output file name. The property value is the input files.

 uglify: {
  prod: {
    files: {
      'dest/a.js': ['src/aa.js', 'src/aaa.js'],
      'dest/a1.js': 'src/aa1.js',
    },
  }
}

Files Array Format

Supports multiple src-dest file mappings per-target.

concat: {
  prod: {
    files: [
      {src: ['src/aa.js', 'src/aaa.js'], dest: 'dest/a.js'},
      {src: ['src/aa1.js', 'src/aaa1.js'], dest: 'dest/a1.js'},
    ]
  }
}

Filtering Files

Filter Example (using function)

files : [
  {
    src : {...},
    dest : {...},
    filter : function( src ){
      return !(/node_modules/.test( src ));
    }
  }
]

Filter Example (using fs.Stats)

files : [
  {
    src : {...},
    dest : {...},
    filter : 'isFile'
  }
]

Reading From package.json

    grunt.initConfig( {
      pkg : grunt.file.readJSON( 'package.json' ),
      
     uglify : {
          all : {
            files : {
              's-code.min.<%= pkg.version %>.js' : sourceFiles
            }
          }
      }
    })
    

Running Tasks

grunt command

bittersweetryan$ grunt

This will run:

grunt.initConfig({
  
  uglify : {
    dev : {
      ...
    },
    prod : {
      ...
    }
  },
  concat: {
    dev : {
      ...
    }
  }
  
});
    

Running a single task

bittersweetryan$ grunt uglify

This will run:

grunt.initConfig({
  
  uglify : {
    dev : {
      ...
    },
    prod : {
      ...
    }
  },
  
  concat: {
    dev : {
      ...
    }
  }
});
      

Running a single target

To run only a single target, append the target name to the task with a :

bittersweetryan$ grunt uglify:dev

This will run:

grunt.initConfig({
    
    uglify : {
      dev : {
        ...
      },
      
      prod : {
        ...
      }
    },
    concat: {
      dev : {
        ...
      }
    }
  });
        

Custom Targets

Custom Default Target

Override running all tasks when grunt is run with no targets.

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

Custom Named Target

Only run grunt :prodtargets:

grunt.registerTask(
  'prod',['jasmine:prod','concat:prod','uglify:prod']
);
bittersweetryan$ grunt prod

Passing options into grunt

Lets say we wanted to be able to dynamically pass an environment target into the last example. We can do that with command line arguments.

grunt --varname=value
var env = grunt.option( 'env' );
var tasks = [ 'jasmine', 'concat', 'uglify' ];

grunt.registerTask('default', tasks.map( function( task ){ return task + ':' + env; } ) );
grunt --env=prod

Other Tips & Tricks

Questions?

The End.

/

#