node.jswebpackgruntjsgrunt-shell

Set NODE_ENV from Grunt task


I would like to set the NODE_ENV variable at the beginning of a Grunt task, to development or production, but it looks it's not as simple as I thought.

The reason, why I would like this is that I use grunt-webpack, which expects NODE_ENV to be set correctly to "development" or "production". But I also would like to initialize my tasks exclusively from grunt, if possible.

I created the following test Gruntfile, using the grunt-shell and cross-env modules:

function log(err, stdout, stderr, cb, e) {
    if (err) {
        cb(err);
        return;
    }

    console.log(process.env.NODE_ENV);
    console.log(stdout);
    cb();
}

module.exports = function(grunt) {

    grunt.initConfig({
        shell: {
            dev: {
                command : 'cross-env NODE_ENV="development"',
                options: {
                    callback: log
                }
            },
            dist: {
                command : 'cross-env NODE_ENV="production"',
                options: {
                    callback: log
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-shell');

};

Line 6 of log() should echo the actual value of process.env.NODE_ENV, but it constantly says undefined, even if I check it manually in the node console.

If I set it manually from the terminal, like set NODE_ENV=production (set is for Windows), everywhere echoes the value production, as I would like it to.


Solution

  • Your test won't work because grunt-shell runs a child_process and your callback runs after it ends and under the main process.
    Same thing would happen with cross-env.

    If you want to pass an environment variable to grunt-shell, you should use the options configuration according to the documentation.
    For example:

    grunt.initConfig({
        shell: {
            dev: {
                command : 'echo %NODE_ENV%', //windows syntax
                options: {
                    execOptions: {
                        env: {
                            'NODE_ENV': 'dev'
                        }
                    },
                    callback: log
                }
            }
        }
    });
    

    This will still print undefined for process.env.NODE_ENV, but the value of NODE_ENV will be available in the stdout because of the echo.

    On a side note, it sounds like you're trying to run a process (grunt-shell), which runs a process (cross-env), which runs a process (webpack or grunt-webpack).
    Why not just use the cross-env example usage? It looks pretty close to what you need.
    Or you can just define the variable in the task config itself and lose all of these wrappers.