Skip to content

Instantly share code, notes, and snippets.

@AdamPflug
Created May 29, 2012 20:47
Show Gist options
  • Save AdamPflug/2830614 to your computer and use it in GitHub Desktop.
Save AdamPflug/2830614 to your computer and use it in GitHub Desktop.
Jake task to continously monitor the javascript and less files for the project, and rebuild them as necessary
desc('Continously monitors the javascript and less files for the project, and rebuilds them as necessary');
task('watch', ['build'], function () {
// Recursively watch files with a callback
var fs = require('fs');
var files = [];
var findFilesAndWatch = function (path) {
fs.stat(path, function (err, stats) {
if (err) {
return false;
}
if (stats.isFile()) {
files.push(path);
fs.watchFile(path, changeCallbackFactory(path));
}
else if (stats.isDirectory()) {
fs.readdir(path, function (err, dirListing) {
if (err) {
return log.fatal(err);
}
for (var f in dirListing) {
findFilesAndWatch(path + '/' + dirListing[f]);
}
});
}
});
};
var changeCallbackFactory = function (file) {
return function (cur, prev) {
if (cur.mtime > prev.mtime) {
stopWatch();
var fileTask = jake.Task[file];
if (fileTask) {
fileTask.modTime = cur.mtime;
}
jake.Task['build'].reenable(true);
jake.Task['build'].invoke();
startWatch();
}
};
};
var startWatch = function () {
for (var i = 0; i < files.length; i++) {
fs.watchFile(files[i], changeCallbackFactory(files[i]));
}
};
var stopWatch = function () {
for (var i = 0; i < files.length; i++) {
fs.unwatchFile(files[i]);
}
};
findFilesAndWatch('themes');
}, {async: true});
@mde
Copy link

mde commented May 30, 2012

Pretty much the same as this issue: jakejs/jake#122

There is code in the Geddy framework that does this and it well tested. Could you take a look at that and merge this work? I would love to have this in Jake core. :)

@AdamPflug
Copy link
Author

The more I think about it, the more it makes sense to do it so you can set up file tasks as dependencies for the watch task. Then I could have it just walk the dependency tree so any files those tasks depend on get watched automatically.

The one issue I've thought of is that if any of those tasks fail (e.g. a LESS/RequireJS compilation task fails because of a syntax error), then the process exits because of the uncaught exception rather than just printing the error and continuing to run. Should I just modify Program.handleErr so it emits an event that you can subscribe to, and if a listener returns true then cancel the exit process?

Once I get a solution to that problem figured out I think I'll merge everything into a nice generic solution.

@mde
Copy link

mde commented Jun 4, 2012

If you're talking about child processes, have a look at the new createExec stuff. It pretty much does exactly what you're describing. :)

@AdamPflug
Copy link
Author

AdamPflug commented Jun 4, 2012 via email

@mde
Copy link

mde commented Jun 9, 2012

Gotcha. The obvious path here is to make Tasks even more evented. Right now they fire "complete" when done, and errors are handled by a generic uncaughtException handler. I can add a "error" event, which can be handled by a specific handler or fall back to the generic one if nothing is set. Would that fix you up?

@mde
Copy link

mde commented Jun 9, 2012

All right, this is in master. Just do someTask.addListener('error', function (e) {}); and call via invoke. If you don't set an explicit listener, it's handled the way it's always been. Let me know if this works for you.

@AdamPflug
Copy link
Author

AdamPflug commented Jun 11, 2012 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment