Getting Started with GruntJS

Automating Your Existing Projects


One of my main gripes with existing Grunt tutorials is that they mostly assume you will have a different working directory from the production one, which is what Yeoman is also based on.

Granted, that’s the best way to get the most out of grunt, but that may not work out for everyone so here’s how you can add a whole bunch of automation to your existing codebase.


Grunt Setup

First thing you’ll need to do is install Node.js from nodejs.org.

http://nodejs.org

Then, install the Grunt CLI:

npm install -g grunt-cli

Project Setup

Now that you have grunt installed on your local machine, you’ll need to set up two files:

  1. package.json
  2. Gruntfile.js

package.json

This file contains project metadata and a list of the grunt plugins you want to use. Here is a sample file. Don’t worry about the devDependencies. Node will add these for you when you install plugins (as demonstrated later in this post).

{
"name": "PROJECT NAME",
"version": "0.1.0",
"homepage": "https://YOURWEBSITE.com",
"author": "YOUR NAME",
"licenses": [
{
"type": "MIT",
"url": "http://opensource.org/licenses/MIT"
}
],
"devDependencies": {
}
}

Gruntfile.js

The grunt file loads plugins and performs tasks on your codebase. Here is a sample Gruntfile. I’ll go into details later.

module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
task: { // task (typically plugin name)
target1: { // target
options: { // target options
option: 'value'
}
},
target2: {
options: {
option: 'value'
}
}
}
});
 // Load the plugins
grunt.loadNpmTasks('grunt-contrib-examplePlugin');
 // Default task(s).
grunt.registerTask('default', ['examplePugin']);
 // Alternate task sets
grunt.registerTask('prod', ['examplePugin:target2']);
};

If you cd to your project folder (where the Gruntfile.js and package.json files are located) and type “grunt” in the terminal, Grunt will run through your “default” task set. You can also run a specific grunt task set like this:

grunt prod

You can even run a specific task, or a specific task for a specific target:

grunt task:target1

Below you will find some of the things you can do with grunt. Keep in mind I am only showing simplified examples. I included a link to each plugin so you can check out the full list of options.


Compile SASS using Grunt

https://github.com/gruntjs/grunt-contrib-compass

This task requires you have Ruby, Sass, and Compass installed, but it will let you know if you’re missing any dependencies.

Install:

npm install grunt-contrib-compass --save-dev

Load in Gruntfile.js

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

Task

grunt.initConfig({ // there should only be one of this. showing here for reference on where task should go
compass: { // task
dev: { // target
options: { // these basically override your config.rb
sassDir: 'YOUR_SASS_FOLDER',
cssDir: 'YOUR_CSS_FOLDER'
}
}
}
}

// make sure to run the task in your default task set
grunt.registerTask('default', ['compass', 'nextTask...']);

Running compass in multiple directories using grunt

Compass currently doesn’t make it easy to process/watch files outside of your sass directory, but you can solve that problem with grunt! You simply create multiple targets with different settings.

compass: { // task
folder1: { // target
options: { // these basically override your config.rb
sassDir: 'FIRST_SASS_FOLDER',
cssDir: 'YOUR_CSS_FOLDER'
}
},
folder2: { // target
options: { // these basically override your config.rb
sassDir: 'SECOND_SASS_FOLDER',
cssDir: 'YOUR_CSS_FOLDER'
}
}
}
// make sure to run the task in your default task set
grunt.registerTask('default', ['compass']);

Alternatively, you can process only one folder like so:

grunt.registerTask(‘default’, [‘compass:folder1’]);

Note that grunt compass will not watch your files. This will be handled using the watch plugin later in the post.

Concatenate Files using Grunt

https://github.com/gruntjs/grunt-contrib-concat

You can use the concat plugin to merge files. If you are using Compass, I recommend using that to merge your CSS files because your SASS partials will share variables, mixins, etc. Concat may still be useful to merge CSS libraries with your compiled CSS.

Install:

npm install grunt-contrib-concat —save-dev

Load:

grunt.loadNpmTasks(‘grunt-contrib-concat’);

Task:

concat: { // task
css: { // target
src: [‘css/**/*.css’],
dest: ‘.tmp/css/app.css’
},
js: { // target
src: [‘js/**/*.js’],
dest: ‘.tmp/js/app.js’
}
}

Note that we are using a temporary folder to concat our files. This is so the concatenated files (app.css & app.js) do not get merged into themselves when grunt runs subsequent times. We will move the files back on minification.

Minify CSS Files using Grunt

https://github.com/gruntjs/grunt-contrib-cssmin

Install:

npm install grunt-contrib-cssmin —save-dev

Load:

grunt.loadNpmTasks(‘grunt-contrib-cssmin’);

Task:

cssmin: { // task
options: { // options
keepSpecialComments: '0'
},
css: { // target
src: '.tmp/css/app.css',
dest: 'css/app.css'
}
}

Note that we are moving the app.css file back from the temporary folder set up in the concatenation step.

Minify JS Files using Grunt

https://github.com/gruntjs/grunt-contrib-uglify

Install:

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

Load:

grunt.loadNpmTasks(‘grunt-contrib-uglify’);

Task:

uglify: { // task
js: { // target
files: { // target options
'js/app.js': ['.tmp/js/app.js'] // destination:source/s
}
}
}

Note that we are moving the app.js file back from the temporary folder set up in the concatenation step.

Add Banner to Minified Files using Grunt

https://github.com/mattstyles/grunt-banner

Grunt-banner adds custom text to the top of your files. You can use this to add a comment with a copyright notice.

Install:

npm install grunt-banner —save-dev

Load:

grunt.loadNpmTasks('grunt-banner');

Task:

usebanner: { // task
css: { // target
options: { // target options
banner: '/*!\n' +
' * APPNAME v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
' * Licensed under MIT (<%= _.pluck(pkg.licenses, "url").join(", ") %>)\n' +
' */\n\n'
},
files: {
src: ['css/app.min.css']
}
}
// js: { ... }
}

Note that we create a separate banner for JS and CSS files so grunt-watch can process them independently from each other.

Run a Shell Command using Grunt

https://github.com/sindresorhus/grunt-shell

You can use the shell to run any terminal command in grunt. I use this to perform an rsync to a different machine after my files are compiled. Note, that it is in the context of your project directory, so you should be able to use relative paths.

Install:

npm install --save-dev grunt-shell

Load:

grunt.loadNpmTasks('grunt-shell');

Task:

shell: { // task 
rsync: { // target
options: { // target options
stdout: true
},
command: 'sh rsync.sh'
}
}

Notifications using Grunt

https://github.com/dylang/grunt-notify

You can send notifications to Mac’s notification center or to growl with the grunt-notify plugin. I use this to let me know when my files are rsynced. It will also notify you of any errors/warnings that show up in grunt.

Install:

npm install grunt-notify --save-dev

Load:

grunt.loadNpmTasks('grunt-notify');

Task:

notify: { // task
shell: { // target
options: { // target options
title: 'Synchronization Complete',
message: 'rsync.sh'
}
}
}

Grunt Watch/Live Reload using Grunt

https://github.com/gruntjs/grunt-contrib-watch

You can use grunt-watch to run tasks when specified files are modified. Grunt-watch also supports live reload if you have the live-reload plugin installed in your browser.

Install:

npm install grunt-contrib-watch --save-dev

Load:

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

Task:

watch: {
options: {
livereload: true,
},
html: {
files: ['**/*.html'], // watch all html files for livereload
tasks: ['shell', 'notify']
},
js: {
files: ['js/**/*.js'],
tasks: ['concat:js', 'uglify', 'usebanner:js', 'shell', 'notify']
},
css: {
files: ['sass/**/*.scss'],
tasks: ['compass:dev', 'cssmin', 'usebanner:css', 'shell', 'notify'],
},
}

A note on file globbing

As you can see in the examples above, I was able to use wildcards for filenames. For a more detailed explanation, check out the Grunt documentation on globbing patterns:

http://gruntjs.com/configuring-tasks#globbing-patterns

That’s all, folks!

Now all you have do is make sure your default task set looks right. This will be executed when you run “grunt” in the terminal. Make sure “watch” is your last task or you will wait forever for it to finish.

grunt.registerTask(‘default’, [‘compass’, ‘concat’, ‘cssmin’, ‘uglify’, ‘usebanner’, ‘shell’, ‘notify’, ‘watch’]);

As you get more familiar with grunt, feel free to explore other plugins, like grunt-usemin or grunt-contrib-copy. Keep in mind that some of these plugins require you to have separate folders for development and production, like so:

/project-folder
-- /app
-- /dist
-- Gruntfile.js
-- package.json

Email me when Marius Craciunoiu publishes or recommends stories