File Watching with Fireworm and Watch'em

Out of the box, Node comes with a fs.watch function that watches for modifications on a file or directory. This function is superior to its older cousin fs.watchFile because whereas fs.watchFile repeatedly polls the file's stat (every second or so) to check for modification, fs.watch uses OS specific features that signal the change back to the program immediately.

The Problem

Testem uses fs.watch for file watching which yields a fast and responsive development experience. But an annoyance for users is that it can't pickup newly created files. As a consequence, users resort to closing out testem and then restarting it everytime they create, rename, or move a file.

Challenge #1

fs.watch attaches a watcher to a file by it's inode number(or equivalent), not by it's path, therefore, just because you did

var w = fs.watch('scripts/script.js')

doesn't mean that you'll always get notified if the contents of scripts/script.js change - not if it was replaced by another file(which has a different inode number).

Challenge #2

Another challenge is supporting globs, e.g. *.js, which require crawling directories and subdirectories and placing watchers on all the matching files, however, this means newly created files that match the desired pattern will not get watched, unless the directories get crawled again.

The Fireworm

Which is why I started work on fireworm - a crawling file watcher. Fireworm crawls the directories and attaches watchers to the files, but in addition, it also watches relevant directories and recrawls them when their contents change. To use it, first you create a new file watcher:

var fireworm = require('fireworm')
var fw = fireworm('start_dir') // specify the dir to watch

Then, add the files you want to watch for changes on (can be glob)

fw.add('lib/**/*.js')
fw.add('tests/**/*.js')

You can ignore some patterns if you wish

fw.ignore('tests/dontcare/*.js')

Lastly, register for the change event

fw.on('change', function(filename){
    console.log(filename, 'just changed!')
})

And that's all there is to it.

Watch'em

With fireworm it becomes very easy to write a program that monitors a directory for changes and responds in some way. For some time now, I've wanted a one-liner that I could type which just watches a directory and runs and reruns a command for me whenever the contents in the directory changed. I could use testem or guard or other watcher thingies, but they all still require some amount of configuration. So, I wrote watch'em.

With watchem, you can type on the command line

watchem "Makefile,**/*.c,**/*.h" make

and it will watch the Makefile, and any .c or .h files within the current directory and within any of its subdirectories. It runs and re-runs make whenever any matching files change, even new ones that are created. I made a 3 minute screencast of it in action

If you are feeling lazy, you can just match against **/* and it will match any file in the directory (except for hidden files and the node_modules directory).

watchem "**/*" make

Test'em

Incidentally, testem also got an update which now allows it to automatically watch newly created files that match the file patterns specified.

That's all folks

If you've read this far, thanks! I hope you give the tools and try and have fun!

blog comments powered by Disqus