Learn how to use Grunt for a better workflow.
2013-11-08
Grunt is a NodeJS (JavaScript) task runner that allows you to automate all the things! I use it to speed up my development workflow and enhancing the performance of my projects.
It's Thursday. I've just started a front-end project that needs to be done...tomorrow. I've started a new WordPress site for a client that we needed to churn out quickly, so I open up Coda, start to manually scaffold out a theme, manually create my php and html files, manually start to add CSS, then I flip over to my browser, hit the refresh button and watch the page reload.
Fast forward to the next day, and I'm cleaning up code, trying to make files smaller (and doing an awful job) and I finally wrap it up, and manually drag files into ftp in Coda, then manually sanity the site and call it a day.
As I'm writing this post, I've got Chrome open in the background and SublimeText 3 open taking half of the screen. I save my file and watch chrome magically update to my most recent markdown file's changes.
This is just one advantage of Grunt.
Grunt has become one of those things in life where you didn't realize just how badly you needed it until you start using it and thinking, "what have I been doing with my life?"
By automating all the things I used to have to manually do, I make more time to do more things, and ultimately make more time to focus on the important things while Grunt takes care of the trivially mundane.
I've added all of these code samples to a github gist, you can clone done the repo, and run the commands as you read rather than having to write out the examples yourself if it's more convenient.
Project gist: Grunt: Up & Running
Grunt has a few dependencies that you'll need to have installed:
From anywhere within your terminal run:
npm install -g grunt-cli
This is going to install the module for the command line tool globally (-g) so you can run grunt
anywhere on your machine and it will know what you're referencing.
Next, in your project's root, you'll need to create a package.json
(run npm init
in your project) and a Gruntfile.js
. The package.json file is a NodeJS file that tells Node about all the attributes of your project and the different Node modules your project will depend on.
Here's my sample package.json
:
{
"name": "chaseadamsio",
"version": "1.0.24",
"description": "Yeoman / Grunt workflow for realchaseadams",
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.5.2",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-watch": "~0.5.3"
},
"engines": {
"node": ">=0.8.0"
}
}
After you've created your package.json
, you'll need to run npm install
, which is going to install grunt, jshint and uglify (any dependencies you specify in your package.json
).
The final piece of the Grunt puzzle is to create your Gruntfile.js
.
In it we're going to have it run two tasks:
We'll create a default task and add the options to the initConfig
:
'use strict';
var packagejson = require('./package.json');
module.exports = function (grunt) {
// Configuration
grunt.initConfig({
pkg: packagejson,
watch: {
scripts: {
files: ['<%= pkg.name %>.js'],
tasks: ['default']
}
},
jshint: {
build: [
'<%= pkg.name %>.js'
]
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
build: {
src: '<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
grunt.registerTask('default', [
'jshint',
'uglify'
]);
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
};
In our Gruntfile, we've very basically told it for jshint, we want to lint the javascript file script.js
, the path being relative to the Gruntfile's location.
After that we want to use uglify to compress and minify our javascript file for performance, and add a banner with the project's name, the version and the date (useful for debugging).
At the very least for running grunt
to work, you have to:
registerTask
of default and add the tasks you want to runloadNpmTasks
of all the tasks that are in your configuration object.The only thing we need to do for this to work is to add a script.js
to your project give it some javascript to execute. Here's a sample js file just for convenience:
(function() {
var foo = "hello ",
bar = "world!";
console.log(foo + bar);
})();
Now that we have everything setup, , and you can switch back to your terminal and run grunt
from anywhere in your project (I always run it from the project root just to be safe), and grunt will run jshint and uglify on your script with the package name!
Having to run grunt
every time you make a change can be a real hassle, so for convenience to almost every project I use, I add the grunt-contrib-watch
task, so let's go ahead and add it as a task:
npm install grunt-contrib-watch --save-dev
When you do this as --save-dev
it will add it to your developer dependencies in your package.json
file, which will help you out in the long run, especially if you want other people to use your project. If you don't pass in the flag to save as a dependency, when someone else pulls down your project and tries to work with it, they'll have to manually install node modules and most likely give up on your project.
Updated package.json
after saving dev dependency for watch:
{
"name": "chaseadamsio",
"version": "1.0.24",
"description": "Yeoman / Grunt workflow for realchaseadams",
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.5.2",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-watch": "~0.5.3"
},
"engines": {
"node": ">=0.8.0"
}
}
Now that we have the ability to watch files, we can add it to our Gruntfile.js
:
'use strict';
var packagejson = require('./package.json');
module.exports = function (grunt) {
// Configuration
grunt.initConfig({
pkg: packagejson,
watch: {
scripts: {
files: ['<%= pkg.name %>.js'],
tasks: ['default']
}
},
jshint: {
build: [
'<%= pkg.name %>.js'
]
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
build: {
src: '<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
grunt.registerTask('default', [
'jshint',
'uglify'
]);
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
};
With an updated file, we can simply run grunt watch
from our terminal, update our javascript file, and watch as it magically runs our tasks everytime we save!
If you're using Grunt, let me know what you like/don't like about it, or some of the really useful plugins you've found! I'll be adding posts every month about the plugins that I find useful for my workflow.
Hey, I'm Chase. I help aspiring entrepreneurs and makers turn their ideas into digital products and apps.
Subscribe to my Newsletter
Every other week I publish the Curiously Crafted newsletter.
In it, I explore the intersection of curiosity and craft: the people who make stuff, what they make and the way they pursue the craft of making.