My project has over 300 CoffeeScript files, so it takes several seconds to recompile everything. I\'d like to only recompile the changed CoffeeScript files.
Here\'s
I've had the same issue. I solved it using the regarde:file
event.
First I listen for changed files by using the regarde:file
event. This will feed the configuration for two tasks: clean:coffee
if files in the source location has been deleted and coffee:refresh
if files have been changed/added.
Then the regarde
task will trigger its tasks, which will launch refresh:coffee
(not to be mistaken from coffee:refresh
). This task will check if there is configuration added for clean:coffee
and/or for coffee:refresh
and run these tasks if needed (via function grunt.task.run
). If will also reset the flag, which will cause the next received regarde:file
event to cleanup the configuration again.
In depth explanation:
First of all, regarde
config:
// watch for changed coffeescript files
coffee: {
files: 'path/to/coffee/**/*.coffee',
tasks: ['refresh:coffee', 'livereload']
},
Then I listen for the regarde:file
event, where I update the clean:coffee
and coffee:refresh
file lists in their config.
Feed the configuration based on the regarde:file
event:
grunt.event.on('regarde:file', function (status, target, filepath) {
if (resetFlag) {
// clean file list from previous cycle, so clean clean:coffee and coffee:refresh
// file lists
...
resetFlag = false;
}
if (status === 'deleted') {
if (filepath) {
// calculate filepath's destination and
// add it to clean:coffee filelist
}
} else {
if (!grunt.file.isDir(filepath)) {
// add filepath to coffee:refresh filelist
}
}
}
It is easy to update configuration via grunt.config()
function. Below the code snippets to feed coffee:refresh
and clean:coffee
.
Adding config to coffee:refresh
:
var config = grunt.config('coffee') || {};
var value = config.refresh || {};
value.files = value.files || [];
...
var cwd = path.dirname(filepath),
src = path.basename(filepath),
dest = cwd.replace('path/to/source', 'path/to/dest');
value.files.push({
expand:true,
src:src,
dest:dest,
cwd:cwd,
ext:'.js'
});
grunt.config('coffee', config);
Adding config to clean:coffee
:
var cwd = path.dirname(filepath),
src = path.basename(filepath),
dest = cwd.replace('path/to/source', 'path/to/dest');
value.src.push(path.join(dest, src.replace('coffee', 'js')));
// clean only what has been removed
config = grunt.config('clean') || {};
config.coffee = value;
grunt.config('clean', config);
Task refresh:coffee
gets triggered:
grunt.registerMultiTask('refresh', 'refreshing the changed file(s)', function () {
this.requires('regarde');
var tasks = [];
var clean = grunt.config('clean');
// check if there is clean:refresh config available
if (clean && clean[this.target]) {
tasks.push('clean:' + this.target);
}
var config = grunt.config(this.target);
// check if there is coffee:refresh config available
if (config && config.refresh) {
tasks.push(this.target + ':refresh');
}
// run the tasks
grunt.task.run(tasks);
// set the resetFlag back to true
resetFlag = true;
});
I had this issue myself and I was able to come up with a solution for it inspired by the comments on this issue: https://github.com/gruntjs/grunt-contrib-watch/issues/14
It is actually for the grunt-contrib-watch plugin, but it should also work for grunt-regarde, as it has similar events.
The idea is to bind a callback the watch
event, in which you add a new task to the grunt configuration with the changed file's path, then run it.
From my Gruntfile.coffee
:
coffee:
app:
expand: true
cwd: 'app/'
src: ['*.coffee',"**/*.coffee"]
dest: './public/temp'
ext: '.js'
watch:
coffee:
files: ['app/**/*.coffee']
tasks: ['livereload']
options:
nospawn: true
grunt.event.on 'watch', (action, filepath) ->
cwd = 'app/'
filepath = filepath.replace(cwd,'')
grunt.config.set('coffee',
changed:
expand: true
cwd: cwd
src: filepath
dest: './public/temp'
ext: '.js'
)
grunt.task.run('coffee:changed')
The nospawn is important for the watch task, so it runs the new task before the livereload task. I am pretty sure regarde does not spawn child processes by default.
grunt.regarde.changed
is an array correct?
Should src: ['<%= grunt.regarde.changed %>']
be src: '<%= grunt.regarde.changed %>'
I looked through grunt-contrib-coffee's source for a second to see if it could be not correctly handling whatever you're giving it. Looked kind of likely that the stringified array you're giving it, doesn't get caught and dealt with.
I think what you're passing accidentally may be: src: [ '[path1, path2, path3, etc]' ]
If I'm way off base, leave a comment and I'll delete this answer.