Settling down with ClojureScript

I recently blogged about using ClojureScript for a new internal application at work. After some initial difficulties, I’m finally up to speed with it. I thought it’s about time I shared some more insights.

Since the application we’re building offers a REST API to be consumed by multiple clients, we decided to eat our own dog food from the start and make the web frontend use the same API. So what we’re doing with ClojureScript is a pure client-side web project.

Generating HTML

Since we’re making a pure client-side application, we needed some kind of client-side templating. I didn’t feel like bothering with HTML after getting accustomed to Hiccup in Compojure, so we used the dom-helpers namespace from the TwitterBuzz ClojureScript demo. Now we can generate markup like this:

(dom/build [:div#content
            [:h1 title]
            [:div#messages
             [:div#message-input
              [:div
               [:label "Your name:"]
               [:input#author-name-input {:type "text"}]]
              [:textarea#message-textarea]
              [:button#send-button "Send message"]]
             [:div#message-list]]]))

The dom-helpers are basically a nice abstraction for Google Closure’s DOM manipulation utilities. I’m sure that ClojureScript will include something like that in the future.

Avoiding Google Closure

Knowing that amazing web applications like Google Docs use it, I really wanted to give Google Closure, which is included in ClojureScript, a chance. The utility functions are actually quite handy, but the lack of documentation makes using most parts, e.g. the UI widgets, a royal pain. Add to that the fact that it feels more like using a cumbersome Java framework than a JavaScript library, I decided to avoid it where possible. Google Closure is technically sophisticated, but lacks elegance and convenience.

Building with Leiningen

When we started to use ClojureScript, we built it from source and invoked the ClojureScript compiler from a Makefile. I can’t begin to tell you how weird this felt. Since we’re using Leiningen to build the backend, we decided to use it for the frontend as well, so I wrote a custom Leiningen plugin that performs the tasks we need, e.g. calling the ClojureScript compiler and packing the output into a WAR file. We’re not planning to release this plugin, it’s pretty hard wired towards our needs and not really thought through.

Instead, I started to contribute to lein-clojurescript, first making it work with a stable release of Leiningen. The author likes my ideas about offering multiple modes for development and production, and making the respective options configurable in the project.clj, so that’s the plugin you want to use.

Promising stuff

REPL in the browser

When ClojureScript was first announced a while ago, the REPL used Rhino for JavaScript evaluation and DOM manipulation was not possible. The ClojureScript developers have addressed that problem and made it possible to use the Browser as evaluation environment. It looks promising, but I didn’t really find the time to play around with it yet.

Compiling automatically

Compiling without optimizations is pretty fast, but manually invoking the compiler before refreshing the browser still feels wrong when doing web development. cljs-watch attempts to solve that problem by watching your ClojureScript sources, recompiling as soon as anything changes, e.g. you save a file. I trie it, but couldn’t make it work right away, so I postponed that. I guess something similar can be build into lein-clojurescript.

Problems

As I told you at the beginning of this post, I’m pretty happy with ClojureScript by now. We had to put some extra energy into setting up our development environment and build system, but now we’re up to speed. A few problems, however, remain.

No unit testing

I haven’t yet invested the time to figure out how to execute unit tests for ClojureScript code, it will probably be easier now that we build with Leiningen. This is something I’ll have to approach soon, working without tests feels really bad.

Still no release

I really don’t know why the Clojure/core folks announced ClojureScript without having a release candidate of ClojureScript ready, or even a tag. That hasn’t changed. At first, we forked the ClojureScript project on GitHub and created a tag to ensure reproducible builds. Now that we use lein-clojurescript, we use the ClojureScript version from Clojars, but that doesn’t feel much better – it’s still an arbitrary snapshot.

Conclusion

Despite the problems, ClojureScript made a very good first and second impression. It proved very stable (I didn’t come across a single compiler weirdness, of which I’ve seen plenty in GWT), which made me take languages that compile to JavaScript seriously again. Instead of whining about programmer inconvenience and immature tooling, I’ve decided to contribute, starting with lein-clojurescript. Once that’s powerful enough to replace our custom plugin, I’ll see if I can help out with ClojureScript itself, it really needs an initial release.

2 Responses to Settling down with ClojureScript

  1. Evan says:

    You might also be interested in my new Leiningen plugin, lein-cljsbuild (https://github.com/emezeske/lein-cljsbuild). It’s similar to lein-clojurescript, but it has built-in support for automatically recompiling files when they’re modified (like cljs-watch), allows the full set of ClojureScript compiler options to be set in the project.clj file, and has support for sharing code between your Clojure and ClojureScript projects. I’m also trying to stay up-to-date with the very latest ClojureScript compiler revisions.

    Currently, lein-cljsbuild does not have any way to specify different compiler options for build versus development settings, but I’m motivated to add support for that. I’d be very interested in your thoughts on how to make it work!

  2. Felix H. Dahlke says:

    Hi Evan,

    had a look at your plugin and it looks brilliant! Looking forward to playing around with it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>