Using Grunt for deploying client scripts

  1. Getting started
  2. Compilation and watching of LESS files
  3. Concatenation and watching of JavaScript files
  4. Resources

For a long time I have struggled to find a suitable tool for doing server tasks such as compiling LESS files, concatenating and minifying of JavaScript files and copying the minified JavaScript files. While most of these tasks can be done with Yii extensions I would still not recommend using them because it requires you to include these extensions in your project, and therefore also deploying them in your production environment.

After a long search I believe that I have found the perfect tool for this. Let me introduce you to Grunt, the JavaScript task runner for Node.js. In this article I will explain how you can set up Grunt to perform these tasks.

Getting started

To install Grunt you first need to install Node.js 0.8.0 or newer, it can be downloaded from the project website at http://nodejs.org/download. When Node is installed you can use npm (the package manager for Node.js) to install Grunt by running the following command:

npm install –g grunt-cli

Note if you have already installed grunt globally you need to uninstall it first.

When you have installed Grunt successfully you need to create two files in the root directory of your project, package.json and Gruntfile.js. Next we will go over these two files in detail.

package.json

The packages.json file is where you specify your Node.js dependencies, in this case your Grunt plugins. Here is a starting point for your package.json file:

[javascript]
{
	"name": "project-name",
	"version": "0.1.0",
	"devDependencies": {
		"grunt": "~0.4.1"
	}
}

Now you can install Grunt locally using npm by running the following command:

npm install
Gruntfile.js

The Gruntfile.js is where you configure your Grunt tasks. This is what an "empty" Gruntfile looks like:

[javascript]
module.exports = function(grunt) {
	
	// Project and task configuration
	grunt.initConfig({

	});

	// Load plugins
	// Nothing here yet...

	// Define tasks
	grunt.registerTask('default', []);

};

Compilation and watching of LESS files

If you do not know what LESS is, it is a dynamic stylesheet language that is compiled into CSS. You can read more about it on http://www.lesscss.org. When you are working with LESS you naturally need to set up compilation of your files which usually is a bit troublesome. However, setting up LESS compilation with Grunt is a breeze and you will have it up and running in a few minutes.

First you need to install the grunt-contrib-less plugin by running the following command:

npm install grunt-contrib-less --save-dev

This will download the plugin and add it to your packages.json file's development dependencies. Next you need to enable it by adding it to your Gruntfile:

[javascript]
// Load plugins
grunt.loadNpmTasks('grunt-contrib-less');

When you have enabled the plugin we can configure it to compile your LESS. In this example I will assume that your less files are in under protected/less.

[javascript]
// Project and task configuration
grunt.initConfig({
	less: {
		development: {
			options: {
				compress: true,
				optimization: 2
			},
			files: {
				"css/main.css": "protected/less/main.less"
			}
		}
	}
});

Next we will setup watching of your LESS files. For this we will need the grunt-contrib-watch plugin by running the following command:

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

Enable the plugin by adding it to your Gruntfile:

[javascript]
// Load plugins
.....
grunt.loadNpmTasks('grunt-contrib-watch');

Configure the watch plugin to watch your less files:

[javascript]
// Project and task configuration
grunt.initConfig({
	.....
	watch: {
		styles: {
			files: ['protected/less/**/*.less'],
			tasks: ['less'],
			options: {
				nospawn: true
			}
		}
	}
});

Grunt will not run any of your plugins unless you add them to a task, let us add watch to the default task:

[javascript]
// Define tasks
grunt.registerTask('default', ['watch']);

Now when you run Grunt, it will watch your LESS files and compile them into CSS if when any LESS file is modified.

Concatenation and watching of JavaScript files

It is considered good practice to concatenate all of your JavaScript files into a single file before minifying them. This can easily be done with the grunt-contrib-concat plugin by running the following command:

npm install grunt-contrib-concat --save-dev

Enable the plugin by adding it to your Gruntfile:

[javascript]
// Load plugins
.....
grunt.loadNpmTasks('grunt-contrib-concat');

When you have enabled the plugin we can configure it to concatenate your JavaScript. In this example I will assume that your JavaScript files are under protected/js.

[javascript]
// Project and task configuration
grunt.initConfig({
	.....
	concat: {
		options: {
			separator: "\n\n"
		},
		dist: {
			src: ['protected/js/app.js'],
			dest: 'js/main.js'
		}
	},
});

Next we will setup watching of your JavaScript files. This can also be done using the watch plugin. Lets add an additional section to the watch plugin:

[javascript]
// Project and task configuration
grunt.initConfig({
	.....
	watch: {
		.....
		scripts: {
			files: ['protected/js/**/*.js'],
			tasks: ['concat'],
			options: {
				nospawn: true
			}
		}
	}
});

Now Grunt will also watch your JavaScript files and concatenate them when any JavaScript file is modified.

Resources