Dynamic Grunt Targets Using Templates
Grunt tasks are very handy when it comes to frontend development, tooling some Node.js routines or even publishing your fresh new hipster blog.
Dynamic file object maps various src
to dest
within one target.
But what about writing multiple targets at once — without add any line of code?
§tl;dr
Some Grunt tasks may last too long and you don’t want to keep adding targets in your Gruntfile.js
. Here is a trick to expand targets automatically.
§The Initial Context
Mark McDonnell worked hard on making BBC News Sass compilation dynamic with Grunt.
He faced the problem of long Sass compilation time and wanted to split them in smaller chunks to reduce the time people stall during two changesets.
Hence the following file structure:
1 |
|
§Writing Targets Manually
If we wanted to be able to rebuild Sass files individually for each service, we would have to write the following code in our Gruntfile.js
:
1 |
|
This way, you type grunt sass:afrique
to compile only the BBC Afrique service stylesheets or grunt sass:dist
to rebuild all the services stylesheets — typically done only when releasing otherwise you will feel like living this comic strip.
You hence face 2 problems:
- the maintenance cost increases gradually as soon as new services requires to add new targets;
- the readability decreases as your Gruntfile get more and more bloated by repetitive content.
Mark’s technique has been great at removing this pain — and he even improved it to leverage the Grunt Config API): he dynamically generated the Grunt targets on runtime.
I’ve been working at making BBC News Grunt tooling battle-tested and pluggable into their CI process. It gave me the opportunity to simplify things.
Because I had time and found it challenging.
§Enters Grunt Property Expand
The grunt.template
mechanism is recommended to avoid repetitions, and to reuse configuration values.
Templates are evaluated on runtime, when a task is duely queued and ran. Not when grunt.initConfig
is called.
Which means we have access to the grunt.task.current
object.
In the case of grunt sass:afrique
, grunt.task.current.name
equals sass
and then, its arguments: grunt.task.current.args
is an array for which the first index equals afrique
.
We don’t need to know more, we can define a static target and provide a complementary argument which will route the services properly like this:
1 |
|
Our Gruntfile.js
will never grow in size or require any new line of code to target a sub-tree of our codebase:
1 |
|
§The Bay Watcher
We can apply the same sugar to the watch
task to recompile automatically our Sass files.
Still, we don’t want to rebuild the whole files assets. We only want to recompile service’s modified Sass files.
This is doable by applying the same technique, not only in the src
target configuration, but also in the tasks
’s one:
1 |
|
§Final Words
While writing this blogpost, I discovered a sentence in the Inside Grunt Tasks page documentation:
While a task is running, Grunt exposes many task-specific utility properties and methods inside the task function via the this object. This same object is also exposed as grunt.task.current for use in templates.
Some would say RTFM.
I would say it was worth finding and learning it.