Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you watch multiple files, but only run task on changed file, in Grunt.js?

In learning how to use grunt, I am trying to make a simple coffee-script watcher/compiler. The problem is, if I tell the watch task to watch several files, and one changes, it is going to pass all of the files to the coffee command. This means when you change 1 file, it's going to recompile all of the files matching the src pattern. Instead, I want to only recompile the single file that changed that matches the src pattern.

Here is the grunt.js:

module.exports = function(grunt) {
  grunt.initConfig({
    coffee: {
      app: {
        src: ['test/cases/controller/*.coffee'],
        dest: 'tmp',
        options: {
          bare: true,
          preserve_dirs: true
        }
      }
    },
    watch: {
      files: ['<config:coffee.app.src>'],
      tasks: ['coffee:app']
    }
  });

  grunt.loadNpmTasks('grunt-coffee');
  grunt.registerTask('default', 'coffee');
};

This is using grunt-coffee, which is basically this: https://gist.github.com/2373159.

When I run grunt watch, and I save a file in test/cases/controller/*.coffee, it compiles all of the matching files (putting them in tmp/*).

How do you instead only compile the changed file using grunt?

like image 378
Lance Avatar asked Aug 21 '12 21:08

Lance


2 Answers

The upcoming (and currently in-development) v0.4.0a grunt has the grunt.file.watchFiles object, which was designed expressly for this purpose. The grunt-coffee plugin may have added support for this feature already, I'm not sure.

Either way, if you're interested in trying an in-development version of grunt in your project, check out the When will I be able to use in-development feature 'X'? FAQ entry.

like image 75
Cowboy Ben Alman Avatar answered Oct 19 '22 19:10

Cowboy Ben Alman


I got this working when compiling my less files. You should be able to mess with this configuration a little bit to git it working with the coffeescript plugin. The portion of interest is the grunt.event.on('watch', ...). In this event handler I'm updating the files property in the less command to only contain the changed file.

path = require('path');

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    less: {
      development: {
        options: {
          paths: ["./library/less"],
        },
        files: [
          { src: "./library/less/bootstrap.less", dest: "./library/css/bootstrap.css"},
          { src: "./library/less/app.less", dest: "./library/css/app.css"}
        ]
      }
    },

    watch: {
      styles: {
        files: "./library/less/*",
        tasks: ["less"],
        options: {
          nospawn: true,
        },
      },
    },
  });

  // Event handling
  grunt.event.on('watch', function(action, filepath){
    // Update the config to only build the changed less file.
    grunt.config(['less', 'development', 'files'], [
      {src: filepath, dest: './library/css/' + path.basename(filepath, '.less') + '.css'}
    ]);
  });

  // Load the plugins
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Tasks
  grunt.registerTask('default', ['watch']);
};
like image 8
blachniet Avatar answered Oct 19 '22 19:10

blachniet