Create A File Watcher With NodeJS and Child Process

I

t is not uncommon in the life of a software developer to want to execute a series of tasks every time a file changes. It tends to come up more frequently in development, for example, you might want to concatenate a series of files, or send and email to an administrator, etc. It becomes even more beneficial to be able to watch all of the files in a given directory. Surprisingly, for as much as it seems to creep up, it tends not to be standard machinery it a large number of programming languages and their standard libraries. Luckily, Node.js gives you all of the tools to create a file and or directory watcher.

Now, there are a number of ways to pull this together with NodeJS. The way I have found my self doing this uses the standard file watcher and the child process module to run the unix program find And it looks a little something like this:

//watcher
var fs = require( 'fs' )  
    ,util = require( 'util' )
    ,path = require( 'path' )
    ,exec = require( 'child_process' ).exec
    ,file_loc
    ,file_ext
    ,cmd;

file_loc = path.resolve( process.argv[2] )  
file_ext = "\." + process.argv[3] + "$"  
cmd = 'find ' + file_loc + ' | grep ' + file_ext

exec(cmd, function( err, stdout, stderr ) {

    var files =  stdout.split( "\n" ),
        id;
    files.forEach(function( file ) {
        if ( !!file ) {
            util.puts( 'watching ' + file );
            fs.watch( file, function( evt, filename ) {
                if ( id ) {
                    clearTimeout( id );
                    id = null;
                }
                id = setTimeout(function() {
                    // do some magic work here
                }, 10);
            });
        }
    })
    util.puts( "\n" );
    files = null;
});

In this example, we leverage process argv to intercept a couple of command line args. In this situation we want to be able to pass in the directory to watch and what type of files we want to watch in that directory. We read in the file list as it comes in to node through stdout which we can split on new line to give us an array of file to watch. From there it is a snap to run over each file and watch it.

In lines 10 - 12 you'll notice the use of process.argv. When program is running in NodeJS there is a global variable available to you called process that holds some in formation about the currently running node instance. Argv is an array of the passed in arguments to the program. In this situation, what I want to do is let the user specify a directory to watch as well as the type of file to watch denoted by it's extension name. This allows you to do this:

node watcher ./app js  

I used the user input to build a simple shell command that searches the resulting directory and pipes all of the output through grep and filters on the file extension. You can watch any file type you whish - JavaScript is just an example. An important thing to note is that in the example, I use setTimeout with a very small interval of 10ms. If the the result of the file watcher creates or modifies a file that exists in the directory the watcher is acting on, it may result in it running multiple times or even infinitely. The timeout clears itself if more than one file changes in rapid succession, which makes sure it only runs once. If your watcher has to do a lot of work, you may want to increase the interval.

Node is all the craze lately. After having used it for a number of months, I have to say, I am on board. The above example illustrates the power that Node provides. In about 30 lines of code, you are able to do something that would require language extensions, 3rd party libraries or a substantial amount of code to pull off something similar in many other languages. NodeJS FTW!

javascript child process file watcher argv node.js