Ambly Remote Compilation and Auto-Configuration

Two features have recently landed in the Ambly ClojureScript iOS REPL that I wanted to describe in a little detail. We hope they will help to reduce friction and make the experience a little more seamless:

On-device consumption of compiler output via WebDAV (or, looked at from another perspective “remote compilation”).

Auto-configuration via Bonjour.

Remote Compilation / WebDAV

When compiling ClojureScript, in addition to the emitted JavaScript, various compiler analysis metadata is cached in the compiler output directory. This generally allows for improved performance (especially helping REPL launch speed), and supports features such as source mapping (mapping between locations in the JavaScript and ClojureScript source, which can be leveraged for translating stack traces and other things).

There is one use case I find particularly interesting when it comes to the compiler output directory: Let’s say you revise some ClojureScript source, defining a new function. To make this new function definition available you can “send” this function to your REPL, essentially switching to the function’s namespace and evaluating the function definition in the REPL. In Ambly’s case, this causes the compiled JavaScript for the function to be sent across the wire to be evaluated in JavaScriptCore.

Another approach is to simply require the namespace containing the function, passing the :reload option. This differs in that it causes the compiler to emit the JavaScript for the namespace, writing it to the output directory, followed by having the JavaScript engine load the updated JavaScript. But, the fundamental challenge is that all of this usually occurs on your Mac, while the JavaScriptCore engine is off running inside of your iOS device.

The solution being pursued with Ambly is to essentially “redirect” the compiler output directory to the device. This is done by running a WebDAV server inside the app, and by pointing the compiler output directory to that WebDAV server. Ambly is currently doing this by making use of the native support in OS X for mounting a WebDAV server, making it appear in the /Volumes directory. Perhaps in the future, the ClojureScript compiler itself will be enhanced so that it can write to a WebDAV server directly (being a WebDAV client), in lieu of its normal filesystem :output-dir capability.

The primary advantage I see for going the require route is that your environment remains more consistent with your source. It is all too easy, when evaluating things at the REPL, to change the state of namespaces in your environment so that they no longer reflect your source.

Another advantage is in handling large ClojureScript namespaces. Instead of having the infrastructure sort out how to stream entire files into the JavaScript engine (by either evaluating a large containing form, or breaking it up somehow), it is simpler to just let the compiler compile the source, and simply tell the JavaScript engine to load it.

There is not a lot of magic going on here with Ambly and WebDAV—Ambly is simply automating the setup so that you don't have to manually create the mounts, set the compiler output directory options appropriately, etc.

Auto-Configuration via Bonjour

When developing for iOS, you often switch from developing in the simulator, to trying things on an iPhone, and then next on an iPad. Xcode, of course, makes this pretty seamless, letting you choose between the targets.

Our goal with Bonjour in Ambly is pretty much the same. When you start up the Ambly REPL, it essentially needs to know the IP address to connect to via TCP for REPL traffic, and the WebDAV address to use when performing “remote compilation.”

To achieve this, the iOS / Objective-C half of Ambly takes advantage of Bonjour, advertising its presence using mDNS. Then, when you start up the Ambly REPL, it can see that your device and/or simulator is running an app enabled with Ambly, and it can automatically connect.

One interesting twist: Some REPLs connect in the opposite direction (where the remote end connects back to your REPL). With the approach of having the app in the device/simulator advertise its presence, I find it makes it easy to connect at will, even facilitating running multiple REPLs, each connected to a different instance if need be.

The Bonjour aspect is a small thing, but it's one less thing to slow you down. Here's to hoping it makes the REPL that much more enjoyable to use!