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
pkgproperty that reads thepackage.jsonfile, so that we can use tags like<%= pkg.version %>in our source files. - Then, it reads all the files in the
grunt/configfolder 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.jsonfile'sdevDependenciesproperty. Any that begingrunt-are assumed to be grunt plugins, and are loaded. - Finally, it loads any custom tasks found in the
grunt/tasksfolder.
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-gruntorload-grunt-tasksfor auto loading of all grunt tasks.grunt-generate-configsfor auto generating config files from a "classic" grunt file.And
load-grunt-configsfor auto loading said config files.(Disclaimer: I wrote the last two)