How to use dynamic variables in a Grunt config file

I had an issue the other day where I needed my Gruntfile.js to “know” what environment I was deploying to so it could use choose the correct parameter values.

Specifically, my Critical CSS Task needed to know whether it should use my Local, Dev, or Prod server to determine what CSS is critical.

TL;DR

Adding this to my Gruntfile.js…

grunt.config('environment', (function(){
    var env = grunt.option('env') || 'local',
        domain;
    if (grunt.option('env') === 'prod') {
        domain = 'http://www.netbiscuits.com/';
    } else if (grunt.option('env') === 'dev') {
        domain = 'http://dev.www.netbiscuits.com/';
    } else {
        domain = 'http://netbiscuits-com:1234/';
    }
    return domain;
})());

… allows me to pass the environment to Grunt via the command line, like this…

grunt --env=dev

… and then tell my Critical CSS Task which environment I am deploying to, like this…

criticalcss : {
    'home' : {
        options:  {
            outputfile : 'css/critical/home.css',
            filename : 'css/style.min.css',
            url : grunt.config('environment')
        }
    },

Say What?

Okay, let’s break that down a bit…

Starting at the Start

Starting with the second block of code above, because that’s how the code actually flows:

grunt --env=dev

This is how you tell Grunt to get off its lazy butt and get to work. This can happen via command line, or, in the case of this project, via command line locally, but via DeployBot for Dev and Prod.

Typically you would start Grunt by simply typing grunt and hitting Enter. You might also be familiar with something like grunt svgmin which will start Grunt, but only run the svgmin Task. But in our case we’re adding this --env=dev at the end…

What’s happening here is we are essentially passing a variable called env and setting a value to that variable, and in the above case that value is dev.

Retrieving the Option

Next, we jump to the first code block from above:

grunt.config('environment', (function(){
    var env = grunt.option('env') || 'local',
        domain;
    if (grunt.option('env') === 'prod') {
        domain = 'http://www.example.com/';
    } else if (grunt.option('env') === 'dev') {
        domain = 'http://dev.example.com/';
    } else {
        domain = 'http://www.example.local/';
    }
    return domain;
})());

This gets inserted just after the opening:

module.exports = function (grunt) { ...

So what’s happening?

  1. The first line creates a new Grunt config variable, called environment, and sets, as the value of that variable, a SIAF.
  2. The SIAF checks to see if any command line options were passed along with the grunt command, specifically if there was one called env (grunt.option('env')).
  3. If the env option was passed, it’s value is set as a local variable (also called env); if not, it’s value is set as local (thus giving us a default, so I don’t have to pass the option when working locally!).
  4. The function then checks a couple possible values of the env variable, specifically prod and dev, setting the appropriate value for the domain variable, and again, defaulting to local.
  5. And finally returns the value of domain, thus setting the value of the Grunt config variable environment.

Putting it into Play

Finally, we make use of the env variable by sending it to the Critical CSS Task:

criticalcss : {
    'home' : {
        options:  {
            outputfile : 'css/critical/home.css',
            filename : 'css/style.min.css',
            url : grunt.config('environment')
        }
    },

This is pretty standard Critical CSS stuff here, except for the url parameter value, which is set using grunt.config('environment').

This grabs whatever value we set in that environment config variable and passes it to the Critical CSS Task.

All the Options

So, for my three environments, I use one of these Grunt commands to get the correct Critical CSS for my site:

  1. Local: grunt
  2. Dev: grunt --env=dev
  3. Prod: grunt --env=prod

Again, local is the default, so no options need to be passed there, making local development, where I manually start Grunt, the easiest. And Dev and Prod are both DeployBot-driven, so I just paste that command into the configuration page and save it.

Summation

This kind of dynamic variable passing could be really useful for all kinds of situations, including testing new methods or trying any different parameter values really easily, without having to keep editing and saving your Gruntfile.js.

Happy Grunting,
Atg

Leave a Reply

Your email address will not be published. Required fields are marked *