Don't be afraid to Grunt

What the hell is "grunt" and why should i use it.

osx Stock Icons

I keep reading about task runner "grunt" in my RSS feeds. So I finally sat down and took a deeper look on how to use it in my work flow. Grunt can
take repeating tasks from your hands and run them in the background e.g. minimize files on the fly.

Let's get Grunt running

First things first - before we get started using grunt we need to install Node. Head over to Node.js and follow the install instructions - http://nodejs.org/

You don't merely need to know Node.js, so don't worry about that. After Node is installed type the following command in your Terminal to install grunt.

See http://gruntjs.com/getting-started if you need a more in-deep help.

Install grunt-cli globally with the following npm command

$ npm install -g grunt-cli

To test if everything was correctly installed type grunt --version into the terminal. This should display something similar.

$ grunt --version
grunt-cli v0.1.13
grunt v0.4.4

Ready to "grunt" at your Project

The next Step is to create two files in your Project Folder - package.json and gruntfile.js. You could also use the command npm init to create the package.json file.

1. package.json

This JSON File manages the installation and tracking of your development dependencies. Now anyone on your Team can have the same development environment if you all use the same package.json file.

Type npm install grunt into the terminal and npm will download the dependency files and put them into the node_modules folder. Also it will create the entry in the package.json file. The flag --save-dev will mark the package information as devDependencies.

This is the package.json from my flyweb Project:

{
"name": "flyweb",
"version": "0.1.0",
"homepage": "http://www.flyweb.at",
"author": {
"name": "Superfly",
"url": "http://www.flyweb.at"
},
"private": true,
"devDependencies": {
"grunt": "~0.4.1"
}
}

Note: When I first created this file I used another Version number and that caused some problems, so use "version": "0.1.0". For further Information regarding the package.json File see - https://www.npmjs.org/doc/json.html

2. Gruntfile.js

The file created gruntfile.js is the place where to configure the all grunt Plugins and Tasks.

module.exports = function(grunt){

grunt.initConfig({

pkg: grunt.file.readJSON('package.json')

});

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

};

This is the standard setup which actually doesn't do anything at this point. We first need to add any specific task or dependencies.

3. Install Dependencies/Plugins

There are two ways to install packages. First edit the package.json file and add the package name and version number, then afterwards run npm install. Or use the second option and let npm do all the work with the following command. Let's install the grunt-contrib-cssmin dependency which can help compress CSS files.

$ npm install grunt-contrib-cssmin --save-dev

The package.json now look like this, grunt-contrib-cssmin was added into the devDependencies.

{
"name": "flyweb",
"version": "0.1.0",
"homepage": "http://www.flyweb.at",
"author": {
"name": "Superfly",
"url": "http://www.flyweb.at"
},
"private": true,
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-cssmin": "*"
}
}

See http://gruntjs.com/plugins for more Plugins. Now we add the grunt-contrib-cssmin dependency to the gruntfile.js.

module.exports = function(grunt){

grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.initConfig({

pkg: grunt.file.readJSON('package.json')

});

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

};

To spare the trouble of adding each grunt-* package by hand, you can use the package matchdep - https://github.com/tkellen/js-matchdep.

$ npm install matchdep --save-dev

Afterwards you can just add matchdep to your gruntfile and all packages which start by the name grunt-* will be added automatically.

module.exports = function(grunt){

// grunt.loadNpmTasks('grunt-contrib-cssmin');
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
grunt.initConfig({

pkg: grunt.file.readJSON('package.json')

});

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

};

Configure and Run Tasks

The next step is to configure grunt-contrib-cssmin to combine and minify all CSS files. We need to add the name of the package as Object key and configure it as we needed. Then we create a new Task with the name buildcss and refer to the new package configuration which should be executed.

module.exports = function(grunt){

"use strict";
require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);
grunt.initConfig({

pkg: grunt.file.readJSON('package.json'),

cssmin: {

combine: {

files: {

'app/css/flyweb.min.css' : [
'app/css/dev/normalize.min.css',
'app/css/dev/foundation.min.css',
'app/css/dev/prism.css',
'app/css/flyweb.min.css'
]

}

},

minify: {

src: 'app/css/flyweb.min.css',
dest: 'dist/css/flyweb.min.css'

}

}

});

grunt.registerTask('default', []);
grunt.registerTask('buildcss', ['cssmin']);

};

Start your grunt Tasks

To start the default Task just type the plain grunt command in your Terminal. But since we don't have any dependencies defined with the default task it will do nothing. To start our newly created buildcss Task we need to use the command:

$ grunt buildcss

You can name your Tasks whatever you want, mine is called buildcss which runs the plugin cssmin. Add as many Plugins as you need to your Task e.g.

grunt.registerTask('buildcss', ['cssmin', 'foo', 'bar']);

All the grunt belongs to me

It would be ridiculous to run the grunt command by hand every time some CSS files changes. Instead wouldn't it be great to run the minify CSS Task every time you make changes to your CSS files? Install the grunt package grunt-contrib-watch - https://www.npmjs.org/package/grunt-contrib-watch - and configure it to achieve auto reloading for your Browser and to minify the CSS file on each file change.

module.exports = function(grunt){

"use strict";
require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);
grunt.initConfig({

pkg: grunt.file.readJSON('package.json'),

cssmin: {

combine: {

files: {

'app/css/flyweb.min.css' : [
'app/css/dev/normalize.min.css',
'app/css/dev/foundation.min.css',
'app/css/dev/prism.css',
'app/css/flyweb.min.css'
]

}

},

minify: {

src: 'app/css/flyweb.min.css',
dest: 'dist/css/flyweb.min.css'

}

},

watch: {

css: {

files: ['app/css/dev/flyweb.css'],
tasks: ['buildcss'],
options: {
livereload: true
}

}

});

grunt.registerTask('default', []);
grunt.registerTask('buildcss', ['cssmin']);
grunt.registerTask('watch');

};

Head over to the Terminal and start the watch Task with:

$ grunt watch:css

The watch Task will start waiting for changes in the defined file/s. Each time it recognize a change the task buildcss will be started. Isn't that nice? But it even gets better.

Livereload

I don't know how many million times I reloaded a browser to see the changes I've made. The grunt-contrib-watch dependency also has the beloved livereload build-in. What now happens is the best part - edit the CSS files, get it minified on the fly and the browser reloads all on its own, yay!

There are two ways to get Livereload running after the installation in grunt.

<script src="http://192.168.0.1:35729/livereload.js?snipver=1"></script>

Note: If you use a local Network with you development Server use the second option.

From here to eternity

Head over to the grunt Homepage and see what Plugins are available. Check out concat_sourcemap, uglify, autoprefixer and many more which make your Webdeveloper life much easier. This was just a little start to the things grunt can do, there is much more which can be done.

I found this two tutorials very useful to get started with grunt - http://24ways.org/2013/grunt-is-not-weird-and-hard/, http://www.smashingmagazine.com/2013/10/29/get-up-running-grunt/