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
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:
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