This page: http://bit.ly/grunt-happy
One of the complaints people sometimes have about Grunt.js is that the configuration files can grow unwieldy when you have more than a couple of tasks. And you have to explicitly load each of those tasks.
Except that you don't. Here is the one-size-fits-all key to Grunt.js happiness.
project
|- Gruntfile.js
|- grunt
| |- config
| |- tasks
|- node_modules
|- package.json
|- src
This is a fairly typical project folder - we've got a src
subfolder with our code in it, plus a package.json
file specifying dependencies (and development dependencies) along with our project name and version number etc. We've got a node_modules
subfolder courtesy of npm - which has installed the modules specified in package.json
.
And we've got a Gruntfile.js
. We'll come back to that.
Finally, we've created a grunt
subfolder, with two subfolders beneath that - config
and tasks
.
Ordinarily, your Gruntfile.js
would look something like this:
module.exports = function ( grunt ) {
'use strict';
grunt.initConfig({
pkg: grunt.file.read( 'package.json' ),
jshint: {
// jshint config...
},
concat: {
// concat config...
},
uglify: {
// uglify config...
}
});
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-contrib-concat' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
grunt.registerTask( 'default', [ 'jshint', 'concat', 'uglify' ]);
};
The first thing we're going to do is take out those config options and put them in our grunt/config
folder. In that folder, create a uglify.js
file:
project/grunt/config/uglify.js:
module.exports = {
// uglify config...
};
If your task configs use the grunt
object themselves in some way, export a function that takes grunt
as its argument, and returns the config object:
module.exports = function ( grunt ) {
return {
// use the `grunt` object in here, e.g. to read files
};
};
Do the same for concat
and jshint
, or whatever tasks you need configs for.
We can do something similar with custom tasks. For example, create a grunt/tasks/default.js
file:
project/grunt/tasks/default.js:
module.exports = function ( grunt ) {
grunt.registerTask( 'default', [ 'jshint', 'concat', 'uglify' ]);
};
Now that we've done steps 1-3, we can replace the contents of Gruntfile.js
with the following:
project/Gruntfile.js:
/* The one-size-fits-all key to Grunt.js happiness - http://bit.ly/grunt-happy */
/*global module:false*/
module.exports = function ( grunt ) {
'use strict';
var config, dependency;
config = {
pkg: grunt.file.readJSON( 'package.json' )
};
// Read config files from the `grunt/config/` folder
grunt.file.expand( 'grunt/config/*.js' ).forEach( function ( path ) {
var property = /grunt\/config\/(.+)\.js/.exec( path )[1],
module = require( './' + path );
config[ property ] = typeof module === 'function' ? module( grunt ) : module;
});
// Initialise grunt
grunt.initConfig( config );
// Load development dependencies specified in package.json
for ( dependency in config.pkg.devDependencies ) {
if ( /^grunt-/.test( dependency) ) {
grunt.loadNpmTasks( dependency );
}
}
// Load tasks from the `grunt-tasks/` folder
grunt.loadTasks( 'grunt/tasks' );
};
- First, it creates a config object with a
pkg
property that reads thepackage.json
file, so that we can use tags like<%= pkg.version %>
in our source files. - Then, it reads all the files in the
grunt/config
folder and adds them as properties to the config object, and initialises grunt with said object. - Thirdly, it reads all the modules listed in your
package.json
file'sdevDependencies
property. Any that begingrunt-
are assumed to be grunt plugins, and are loaded. - Finally, it loads any custom tasks found in the
grunt/tasks
folder.
That's it! Any time you do npm install --save-dev grunt-whatever
, the task will automatically be loaded - no need to manually add npm.loadNpmTask('grunt-whatever')
. You just need to add a whatever.js
file in your grunt/config
file. And your custom tasks can grow as hairy and hacky as you like, because the smell will be contained in a single task file rather than overpowering the rest of your Gruntfile.js
.
There are tasks for those :)
jit-grunt
orload-grunt-tasks
for auto loading of all grunt tasks.grunt-generate-configs
for auto generating config files from a "classic" grunt file.And
load-grunt-configs
for auto loading said config files.(Disclaimer: I wrote the last two)