Windows CoffeeScript Auto-Compiler using Groovy and JDK 7 WatcherService

Update: Node.js for Windows has been improved since this post, so this information is obsolete. Last time I checked I was able to run CoffeeScript the same on Windows as I do on Linux and OSX.

If you’re using the CoffeeScript compiler for Windows (By Alexey Lebedev) you’ve probably noted a lack of a -w or “–watch” argument. These arguments can be very handy if you are working with a coffeescript file and want to quickly see the results of your edits. Given this lack of functionality and my desire to write some code in Groovy 1.8 using some of the NIO2 JDK 7 features I decided to write a little script that wraps this CoffeeScript compiler and fills in this missing feature.

If you’re following along at home you’ll want to download the above-mentioned CoffeeScript compiler and put it somewhere in your command path. Another useful piece of software is the Baretail executable. Baretail is a real-time log file reader for Windows. It’s, basically, a Windows GUI version of tail -f on a Unix system and allows you to see the output of your CoffeeScript compiler in real time. If you know of a better alternative to Baretail, please let me know.

So let’s dive right into the Groovy code:

import java.nio.file.FileSystemNotFoundException import java.nio.file.FileSystems import java.nio.file.Files import java.nio.file.LinkOption import java.nio.file.Path import java.nio.file.Paths import java.nio.file.WatchEvent   import static java.nio.file.StandardWatchEventKinds.* import java.nio.file.WatchKey import java.nio.file.WatchService import java.nio.file.attribute.FileAttribute import java.util.concurrent.TimeUnit   // #1 if (!(1..2).contains(this.args.length)) { println “Syntax: coffeewatch.groovy <source-path> [output-path]” println “If [output-path] not specified, ‘js’ dir will be created and used” return; }   // #2 WatchService watcher = FileSystems.getDefault().newWatchService()   // #3 Path sourcePath = Paths.get(this.args[0]) if (Files.notExists(sourcePath, new LinkOption[0])) { println “source path ${this.args[0]} not found” return }   // #4 Path outputDir = Paths.get((this.args.length == 1) ? “js” : this.args[1])   // #5 def brewCoffee = { def proc = “””coffee.exe -c -o ${outputDir} ${this.args[0]}”””.execute() println }   // #6 if (Files.notExists(outputDir, new LinkOption[0])) { Files.createDirectory(outputDir, new FileAttribute<?>[0]) brewCoffee() }   // #7 sourcePath.register(watcher, ENTRY_CREATE, ENTRY_MODIFY);   // #8 for(;;) { WatchKey key = watcher.take() List<WatchEvent<?>> events = key.pollEvents(); events.each { event -> brewCoffee() key.reset(); } }

The Groovy script you see here is akin to the bash or ksh scripts I used to write when I worked exclusively on Unix machines. Groovy makes a great drop-in replacement for bash, especially if you’re a Java developer. Anyway, the script takes two arguments: CoffeeScript source path and JavaScript output path.

Starting with #1, I’ve added a check to ensure that the correct number of command-line arguments were passed. Item #2 shows a way to get a WatchService reference. This is a new interface in Java 7 related to watching for file system events. In section #2 I’m using the NIO.2 AIP to check whether the coffeescript source directory exists. If it does exist the in section #4 I’m creating an output directory with the name specified or “js” if nothing is specified. Section #5 defines a closure that calls the Coffeescript compiler. Section #6 created the output directory if it doesn’t exist and does the initial COffeescript to JS compile. Section #7 registers the watcher and section #8 runs the compiler each time a CREATE or MODIFY event is detected. The script runs in an infinite loop and the pollEvents()method blocks until an event is received.

It’s nothing fancy, but it gets the job done. One caveat is that setting JAVA_HOME to point to JDK 1.7 broke Maven 3.x for me. I had to modify the Maven executable to set JAVA_HOME to JDK 1.6.

Scroll to Top