More efficient Gruntfile management

Imagine you’re working on a project and you have a series of tasks that you regularly perform. Examples of such tasks could be concatenation and minification. Grunt aims to speed up such tasks ( plus many more ) and automate them for you.

Grunt: a task-based command line build tool for JavaScript projects.

This post won’t focus on how to get started with Grunt so if you aren’t familiar with it, read Chris Coyier’s article “Grunt for People Who Think Things Like Grunt are Weird and Hard”.

A growing Gruntfile

I’ve started using Grunt more than a year ago from small to larger projects. A typical Gruntfile for relatively small projects usually involves:

  1. concatenation
  2. minification
  3. hinting
  4. testing
  5. building

If we have a look at Grunt’s documentation we can see that a Gruntfile for those tasks has an average of 50 lines of code. Not bad.

As a project grows larger (usually) so does the Gruntfile. Grunt can be easily extended with plugins, every time I find a new plugin that might be useful for me, I add it to my project. It can quickly become very hard to maintain.

Look at this mess from one of my open source projects. That Gruntfile contains 333 lines of code that could use a nice cleanup.

A neat Gruntfile

Splitting your Grunt configuration into different files is an efficient way to keep your grunt file neatly organized and also reduces complexity a little.

Load-grunt-config comes to the rescue. This plugin allows you to break up your Gruntfile config by task.

This is what my grunt file now looks like:

module.exports = function( grunt ) {
    // Load configurations.
    require('load-grunt-config')( grunt, {
        data: {
            pkg: grunt.file.readJSON( 'package.json' )
        }
    });
};

Not even 10 lines. That’s it.

Now, all our tasks go into a folder called “grunt”. By default the plugin will automatically include files that have the same name as the tasks. My folder structure looks like this

settings tabs

As you can see, each task has been accommodated into it’s own file. For example, the “compress” task now is into a compress.js file that looks like this:

module.exports = {
        main: {
                options: {
                        mode: 'zip',
                        archive: './build/<%= pkg.name %>-<%= pkg.version %>.zip'
                },
                expand: true,
                cwd: 'build/<%= pkg.name %>/',
                src: ['**/*'],
                dest: '<%= pkg.name %>/'
        }
};

Registering aliases

Now that you’ve created all your tasks into separate files, you will need to register aliases. This was usually taken care of by the registerTask function within the “dirty” grunt file.

Load-grunt-tasks allows you to use YAML syntax to register all tasks. Create an aliases.yaml file. Here’s mine:

# Grunt aliases for our project.
---
'bump_version':
- 'replace'
# Update textdomain and makepot task(s)
'i18n':
- 'addtextdomain'
- 'makepot'
# Build everything
build:
- 'clean'
- 'copy'
- 'compress'
# Default task
default:
- 'makepot'

If everything has been done correctly, you can now run tasks with the aliases you’ve just defined.

I’ve found this way to be much more flexible and organized for handling large projects that use Gruntjs.

If you’re interested in more examples, here you can find a sort-of boilerplate I’ve put together for my WordPress based projects https://github.com/alessandrotesoro/wp-grunt-project. Of course, make sure you edit each file to suit your project.

I hope this has been useful :)