Use Global Variable to Set Build Output Path in Grunt

14,223

Solution 1

So, I was on the right path. The issue is that the module exports before those global variables get set, so they are all undefined in subsequent tasks defined within the initConfig() task.

The solution I came up with, although, there may be better, is to overwrite a grunt.option value.

I have an optional option for my task --target

working solution looks like this:

grunt.registerTask("setOutput", "Set the output folder for the build.", function () {
  if (global.buildType === "tfs") {
    global.outputPath = MACHINE_PATH;
  }
  if (global.buildType === "local") {
    global.outputPath = LOCAL_PATH;
  }
  if (global.buildType === "release") {
    global.outputPath = RELEASE_PATH;
  }
  if (grunt.option("target")) {
    global.outputPath = grunt.option("target");
  }

  grunt.option("target", global.outputPath);
  grunt.log.writeln("Output path: " + grunt.option("target"));
});

And the task defined in initConfig() looked like this:

clean: {
  build: {
    src: ["<%= grunt.option(\"target\") %>"]
  }
}

Feel free to chime in if you have a better solution. Otherwise, perhaps this may help someone else.

Solution 2

I have a way to do this that allows you to specify the output path using values like --dev. So far it's working very well, I quite like it. Thought I'd share it, as someone else may like it, too.

    # Enum for target switching behavior
    TARGETS =
      dev: 'dev'
      dist: 'dist'

    # Configurable paths and globs
    buildConfig =
      dist: "dist"
      dev: '.devServer'
      timestamp: grunt.template.today('mm-dd_HHMM')

    grunt.initConfig
        cfg: buildConfig
        cssmin:
            crunch:
                options: report: 'min'
                files: "<%= grunt.option('target') %>/all-min.css": "/**/*.css"

    # Set the output path for built files.
    # Most tasks will key off this so it is a prerequisite
    setPath = ->
      if grunt.option 'dev'
        grunt.option 'target', buildConfig.dev
      else if grunt.option 'dist'
        grunt.option 'target', "#{buildConfig.dist}/#{buildConfig.timestamp}"
      else # Default path
        grunt.option 'target', buildConfig.dev
      grunt.log.writeln "Output path set to: `#{grunt.option 'target'}`"
      grunt.log.writeln "Possible targets:"
      grunt.log.writeln target for target of TARGETS

    setPath()

With this setup, you can run commands like:

grunt cssmin --dist #sent to dist target
grunt cssmin --dev #sent to dev target
grunt cssmin --dev #sent to default target (dev)
Share:
14,223
ThePuzzleMaster
Author by

ThePuzzleMaster

Updated on June 20, 2022

Comments

  • ThePuzzleMaster
    ThePuzzleMaster almost 2 years

    I have a couple grunt tasks and I am trying to share global variables across those tasks and I am running into issues.

    I have written a some custom tasks which set the proper output path depending on the build type. This seems to be setting things correctly.

    // Set Mode (local or build)
    grunt.registerTask("setBuildType", "Set the build type. Either build or local", function (val) {
      // grunt.log.writeln(val + " :setBuildType val");
      global.buildType = val;
    });
    
    // SetOutput location
    grunt.registerTask("setOutput", "Set the output folder for the build.", function () {
      if (global.buildType === "tfs") {
        global.outputPath = MACHINE_PATH;
      }
      if (global.buildType === "local") {
        global.outputPath = LOCAL_PATH;
      }
      if (global.buildType === "release") {
        global.outputPath = RELEASE_PATH;
      }
      if (grunt.option("target")) {
        global.outputPath = grunt.option("target");
      }
      grunt.log.writeln("Output folder: " + global.outputPath);
    });
    
    grunt.registerTask("globalReadout", function () {
      grunt.log.writeln(global.outputPath);
    });
    

    So, I'm trying to then reference global.outputPath in a subsequent task, and running into errors.

    If I call grunt test from the command line, it outputs the correct path no problem.

    However, if I have a task like this: clean: { release: { src: global.outputPath } }

    It throws the following error: Warning: Cannot call method 'indexOf' of undefined Use --force to continue.

    Also, my constants in the setOutput task are set at the top of my Gruntfile.js

    Any thoughts? Am I doing something wrong here?