Friday, June 28, 2013

GRUNT- The JavaScript Task Runner

Grunt helps developers automate the task of javascript deployment.
In our development cycle, every javascript deployment used to be
1. Code
2. Minify
3. Upload
We were missing out two important phases which ensures code quality and reliability
1. Lint
2. Testing
As our code became larger and larger, as anyother dev we also considered a refactor.
The refactor resulted in splitting our large code base to manageable modules.
Now, Deployment has to go through
1. Unit test independent modules
2. Merge Modules to a shippable target
3. Lint
4. Minify
5. Deploy
Ooops... Nice but how?
It's true that developers love things automated, and so we were. We arrived at a one stop solution GRUNT.

This blog post is a Let Them Know Types. As, I felt that the instructions on grunt setup is kind of scattered :)
To hav a better introduction with the hero, you should meet him at his place
Grunt has two parts:
1. Using it
2. Customizing it

How to start using it?
Grunt 0.4.x requires Node.js version >= 0.8.0. Install it from here
Read a bit on npm [Node Pacakge Manager] in case you are not aware of here
$ npm install -g grunt-cli
What is grunt-cli?
grunt-cli is a utility, that makes sure that it runs the grunt version installed locally to the project.
This helps developers having different versions of grunt across projects.
Installing grunt-cli adds "grunt" command to your system path

$ mkdir firstGruntProject
$ cd !$
$ grunt
grunt-cli: The grunt command line interface. (v0.1.9)

Fatal error: Unable to find local grunt.

If you're seeing this message, either a Gruntfile wasn't found or grunt
hasn't been installed locally to your project.

What does this mean?
Basically to begin with a grunt task runner project, there are 3 important requirments.
1. Local grunt module
2. GruntConfig.js //Task runner's configuration
3. package.json

The above error states that we haven't got the local grunt module setup in our project home.
Before doing that, lets set up a very basic grunt project.

Is there any easy way to generate basic grunt config file?
Yes, check out Project Scaffolding
There is a very handy utility "grunt-init", which accepts a TEMPLATE to create a sample GruntConfig file or Grunt Plugin.
A Template is kind of config file for automation of config or plugin creation.

Sample Template for simple grunt project can be downloaded Grunt Git repo
Once setup of template is done, install grunt-init globally
$ git clone ~/.grunt-init/gruntfile
$ npm install -g grunt-init
$ cd firstGruntProject
$ grunt-init ~/.grunt-init/gruntfile
You will get a list of Yes or No's. Answer them and you are almost done to set up a grunt project

We need a local grunt installation. It is as simple as that [npm install grunt@version]
$ npm install grunt
You can notice the absence of "-g" param for grunt install.
This gives you an option of having multiple grunt versions across your projects. grunt-cli is the util which makes this possible.

Lets try grunt now..
$ grunt
Loading "Gruntfile.js" tasks...ERROR
>> Error: Unable to read "package.json" file (Error code: ENOENT).
Ooops, Most of the gruntfile templates create a project specific package.json. But not in this sample template.
So, Lets create our own using npm init command
$ npm init

Ok, Is there a limitation on where the command should be run from?
You can run "grunt" command from anywhere inside your project.
"grunt" command is kind of nodejs require().
"grunt-cli" util takes care of locating the locally installed grunt module and load it with Gruntfile.js

Once all this is done. Executing grunt should be as smooth as a cake provided there are no errors in the tasks and their internal confs.

Now how to install some packages I need?
It is as simple as installing node packages
$npm install package@version --save-dev
**save-dev option rewrites package.json automagically.

How do I specify package specific configs?
Mostly all modules have their wiki on how should you pass configs.
Check this to get some more idea.

Grunt provides lots and lots of apis. Check them out here
I love grunt.option and grunt.file the most :)

This is one part of the best parts. Grunt makes it possible for people to write their own tasks or plugins. We'll handle that in a separate blog post :)