8 ways to improve your Grunt set-up

That’s what this task does. It would be better if you simply saved your JavaScript file … and BOOM the relevant tests are off and running! Create a default Grunt set-up starting point for all projects
Grunt has a built-in feature called grunt-init. You’ve probably heard that quote before, but it’s true. It’s not a great experience being forced to wait that long between saves. You define your   tasks as normal, and the only thing you need to do is prefix the name of the task you want to run with   newer:. This article originally appeared in net magazine issue 256. Ultimately, however, the best way to keep your Grunt set-up maintainable, fast and scalable is to understand what   you are doing. This data file caused   our Grunt build to take over two minutes to render a concatenated JS file (grunt-contrib-requirejs). Inside that folder will be individual JavaScript files; each containing a different task that you would have included within your main Gruntfile. What we need to do is simplify our Gruntfile’s structure. With small Grunt set-ups this isn’t an issue, but as you add more tasks into your set-up it will take longer for Grunt to spin everything up before running the task you requested. Run Tasks in parallel  
A great way to speed up your Grunt running time is to run tasks in parallel. The best craft people become experts in how to use their tools. For example:

grunt.initConfig({
jshint: {
all: {src: ‘src/**/*.js’}
}
});
grunt.loadNpmTasks(‘grunt-contrib-jshint’);
grunt.loadNpmTasks(‘grunt-newer’);
grunt.registerTask(‘lint’, [‘newer:jshint:all’]);
 
Now when you run   grunt lint it will only run the jshint task against files that have changed since the   last time the jshint task was run. Regardless of which one you choose (pick grunt-parallel if you also   want to run custom – non Grunt – tasks) the one thing you should do is use it together with the   time-grunt plug-in, which is a fantastic tool that tells you how long each task takes to run. 06. As with most complex tools, problems with   maintainability can rapidly accumulate in a short period of time; leaving users overwhelmed with how best to resolve the complexity they’re now   faced with. This will massively decrease the spin-up time Grunt needs before being ready to run a task.  
Then from within your JSHint task (which we’ll assume is now safely out of the Gruntfile and within its own separate task file) you can specify the location of the configuration file:

jshint: {
files: [‘./app/**/*.js’],
options: {
jshintrc: ‘./grunt/.jshintrc’
}
}
 
The same approach can be applied to any configuration data. These will be loaded and run only if you run grunt images. It lets you define a template project structure that gets dynamically injected with configurable values when you start a new project. |— Gruntfile
|— package.json
|— grunt
| – contrib-requirejs.js

 
Our Gruntfile can now be as simple as:

module.exports = function(grunt) {
grunt.loadTasks(‘grunt’);
};
 
Isn’t that better? You set questions in the JSON file, these are answered on the command line, and the values are passed into the project template. Conditionally load tasks
Grunt loads into memory all the tasks you add to the Gruntfile, regardless of whether or not they are going to be used. Conclusion
We hope you’ve found this article useful. Another important technique that we can utilise is to move specific types of configuration outside of the Gruntfile. Your directory structure could look something like the following… With each task in its own file, we need to define the task slightly differently to how it would usually be added in the Gruntfile; contrib-requirejs.js should be structured thus:

module.exports = function(grunt) {
grunt.config(‘requirejs’, {
compile: {
options: {
baseUrl: ‘./app’,
name: ‘main’,
out: ‘./app/release/main.js’
}
}
});
grunt.loadNpmTasks(‘grunt-contrib-requirejs’);
};
 
02. This is where the grunt-newer task   comes in handy. By way of an example, we recently worked on a project in which we had added a 90Kb data file for D3.js   (a popular data visualisation tool) to compile into an interactive map. This is because there is a cost to running two tasks in parallel: normally about 0.5 seconds, the time it takes to spin up another instance of Grunt. Only run tasks when a change has occurred
If you haven’t heard of the   grunt-contrib-watch task then it should be the first thing you look at next, because it’s a life saver for ensuring you only run a task when the associated files with that task have actually changed. Let’s take a look at how we can use it to clean up our JSHint task. While   Grunt does indeed contain some sub-optimal design decisions (albeit ones that are being actively addressed for the upcoming Grunt v1.0 release), a Grunt set-up overloaded with tasks is obviously going to run slowly. It so happens that the JSHint task   came pre-built with that functionality, and so with other pre-built tasks you may need to dynamically load the config file yourself using the Grunt API. The BBC News development team use Grunt on a daily basis to make sure the bbc.co.uk/news   codebase is tested, linted, formalised, optimised and   automated. Grunt   – which won Open Source Project of the Year at May’s net Awards 2014 – has quickly become an essential configuration-based command line tool within our industry for running tasks that can handle all kind of requirements. The example I’m going to demonstrate is the best way possible to reduce the size and complexity of your Gruntfile. Keep your Gruntfile maintainable
One of the biggest concerns for developers working with Grunt is that this wonderfully powerful configuration file can evolve into an unwieldy monster. It’s worth noting that the string ‘grunt’ that was passed to the   loadTasks method has nothing to do with the actual Grunt object; it refers to the name of the folder you created. Only run tasks against files that   have actually changed
The only thing that’s faster than using grunt-contrib-watch to run tasks when a file changes, is to run tasks against only those files that have actually changed since the last time the task was   run. 08. Blacklisting the data file brought the build back down to just a few seconds. 01. So, if you run the task and then edit a single JavaScript file, then when that file is saved that single file will only be linted, because the grunt-newer task knows no other files need to be run against JSHint again. grunt-parallel
grunt-concurrent  
To be honest there isn’t much to choose between them – we’d lean   slightly towards grunt-concurrent because:
The API is slightly more straightforward
The project chatter on GitHub is more recent (relying on dead projects isn’t fun)
It’s made by Sindre Sorhus!!! If we were to take a leaf out of the object-oriented design handbook, we would know that our configuration file is doing too much and that we need to break it down into component parts to ease our ability to extend and manage our Gruntfile requirements (when we need to add more tasks and configuration settings, for example). 05. Before you   start micro-optimising every part of your Gruntfile, the first thing you should do is measure how long the build takes to run in its current form. 03. Keep reading about Grunt; follow thought leaders such as Ben Altman   –   the creator of Grunt,   Sindre Sorhus   – Node.js superstar, and Addy Osmani   – workflow enthusiast, as well as @gruntjs for the latest news on the project. The only drawback is that you now have sub layers of tasks, so you’ll need to give the tasks names that might describe or get confused with the tasks ran within them. So let’s be a bit tricksy and set up the Grunt config in a very specific way in order to get around this problem. It’s a command line tool configured by a JSON file. Then, after each refactoring, analyse the build’s performance to ensure you’ve not introduced a regression. There are a few ways to do this, but the majority of solutions you read about boil down to different implementations of that general theme.

Updated: 12.11.2014 — 02:07