How to run two grunt watch tasks simultaneously

Is it possible to run two watch tasks simultaneously?

I understand that I can have any number of tasks I want inside watch settings and just launch grunt watch and it will watch all of them, like this

...
watch: {
    A: {
        files: "js/dev/**/*.coffee",
        tasks: ["coffee", "requirejs"]
    },
    B: {
        files: "js/dev/**/*.coffee",
        tasks: ["coffee"]
    },
    C: {
        files: "js/dev/**/*.html",
        tasks: ["copy"]
    }
}
...

...but I don't need this. I just want to have different set of tasks for development and production. As you can guess, the only difference between A (production) and B (development) is minification and concatenation. I don't need to launch A and B tasks at the same time.

First I came with this idea

grunt.registerTask("prod", ["watch:A", "watch:C"]);
grunt.registerTask("dev", ["watch:B", "watch:C"]);

But this didn't work. Just first watch tasks is working (C never works). Is that possible to do what I want?


Solution 1:

I've found using grunt-concurrent works:

concurrent: {
  options: {
    logConcurrentOutput: true
  },
  prod: {
    tasks: ["watch:A", "watch:C"]
  },
  dev: {
    tasks: ["watch:B", "watch:C"]
  }
}

Then:

grunt.registerTask("prod", ["concurrent:prod"]);
grunt.registerTask("dev", ["concurrent:dev"]);

Solution 2:

EDIT: concurrent now has a logConcurrentOutput option! More info here: https://github.com/sindresorhus/grunt-concurrent#logconcurrentoutput.

Watch is a weirdly concurrent but blocking task, so you have to be creative to get multitask-like functionality working.

Concurrent loses all output from the watch tasks, which isn't ideal.

Try dynamically writing the config object in a custom task:

grunt.registerTask('watch:test', function() {
  // Configuration for watch:test tasks.
  var config = {
    options: {
      interrupt: true
    },
    unit: {
      files: [
        'test/unit/**/*.spec.coffee'
      ],
      tasks: ['karma:unit']
    },
    integration: {
      files: [
        'test/integration/**/*.rb',
        '.tmp/scripts/**/*.js'
      ],
      tasks: ['exec:rspec']
    }
  };

  grunt.config('watch', config);
  grunt.task.run('watch');
});

Solution 3:

The best and only working solution is there : https://npmjs.org/package/grunt-focus Add this plugin and then :

focus: {
            sources: {
                include: ['js', 'html', 'css', 'grunt']
            },
            testu: {
                include: ['js', 'html', 'css', 'testu', 'grunt']
            },
            testi: {
                include: ['js', 'html', 'css', 'testu', 'testi', 'grunt']
            }
        },
        watch: {
            js: {
                files: paths.js,
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            html: {
                files: paths.html,
                options: {
                    livereload: true
                }
            },
            css: {
                files: paths.css,
                tasks: ['csslint'],
                options: {
                    livereload: true
                }
            },
            testu: {
                files: ['test/**/*.js', 'test/**/*.css'],
                tasks: ['mochaTest'],
                options: {}
            },
            testi: {
                files: ['test/**/*.js', 'test/**/*.css'],
                tasks: ['exec:cleanTestDB', 'protractor_webdriver', 'protractor'],
                options: {}
            },
            grunt: {
                files: ['Gruntfile.js', 'server/config/env/*.js'],
                options: {
                    reload: true
                }
            }
        }

Then you use focus:sources or focus:testu as your convenience.

JM.