From Guard to Grunt
I recently got to attend the Open Web Camp V in San Jose, CA. I made a last-minute switch on my session choice in the afternoon and opted to attend Dirk Ginader’s “Let Grunt Do the Work, Focus on the Fun!” talk, and I am so glad that I did.
I have been hearing about Grunt for awhile and have been tempted to try it out for Javascript file concatenation and minification and even had heard you could configure other tasks like JS hinting upon file save. At Dirk’s talk I found out you can have grunt compile your SASS as well upon file save and even set up live browser reload. At that point I was sold and decided to try Grunt out in place of Guard on my linux system, which had been working just fine for SASS compilation and live reload upon file save.
I installed Grunt and configured it for an existing project without much trouble.
Installation
Note that node.js is a prerequisite for using Grunt. I had to update my Fedora installation in order to be able to install node (how quickly things get out of date!). I followed the steps at the GruntJS site to install Grunt via npm install. It was there that I found out I needed two files for each project that I want to use with Grunt — a package.json
file and a Gruntfile.js
file.
I installed a basic Gruntfile from Github, installing grunt-init first as the instructions detailed. I used the npm init
command to create a basic package.json file.
Plugins
Next the customization fun began. There are a huge number of Grunt plugins that can be installed to add additional functionality. I am using:
- Compass plugin: Compiles your SASS :).
- Grunt Watch plugin: Watches for events like file save and performs prescribed tasks. A must-have.
- Grunt JsHint plugin: Runs JsHint on your Javascript files.
- Grunt Concat plugin: Concatenates your Javascript files.
- Grunt UglifyJS plugin: Minifies your Javascript files.
There are tons of other plugins I am still finding out about, like a CSS linter. Good stuff! I like that the installation of plugins is very easy too. Since Grunt plugins are packaged as node modules, they can be installed via npm
.
So far, so good with Grunt. For SASS compilation, I simply run grunt
and leave it running. Any time I save a SASS file, the compilation takes place. The other tasks, like livereload, work the same way (as long as I have the livereload browser extension running, my browser refreshes immediately).
Sample Configuration Files
My Gruntfile:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
// Task configuration.
concat: {
options: {
banner: '<%= banner %>',
stripBanners: true
},
dist: {
src: ['lib/<%= pkg.name %>.js'],
dest: 'dist/<%= pkg.name %>.js'
}
},
compass: {
dist: {
options: {
config: 'config.rb',
force: true
}
}
},
uglify: {
options: {
banner: '<%= banner %>'
},
dist: {
src: '<%= concat.dist.dest %>',
dest: 'dist/<%= pkg.name %>.min.js'
}
},
jshint: {
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
unused: true,
boss: true,
eqnull: true,
browser: true,
globals: {}
},
gruntfile: {
src: 'Gruntfile.js'
},
lib_test: {
src: ['lib/**/*.js', 'test/**/*.js']
}
},
watch: {
gruntfile: {
files: '<%= jshint.gruntfile.src %>',
tasks: ['jshint:gruntfile']
},
sass: {
files: ['sass/*.scss'],
tasks: ['compass'],
options: {
livereload: true,
}
},
js: {
files: ['js/*.js'],
tasks: ['uglify', 'jshint']
}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task.
grunt.registerTask('default', ['jshint', 'concat', 'watch']);
};
My package.json file:
{
"name": "sheelahb",
"description": "Portfolio site",
"version": "0.0.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "~0.1.2",
"grunt-contrib-jshint": "~0.6.0",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "~0.5.1",
"grunt-contrib-sass": "~0.4.1",
"grunt-contrib-compass": "~0.5.0"
}
}