Using Google closure library with ClojureScript

Fri 05 August 2011
  • 手艺 tags:
  • clojure
  • clojurescript
  • javascript published: true comments: true

Google closure library is shipped with ClojureScript, and could be compiled with ClojureScript into a minimized javascript file. So closure library is doubtlessly the first candidate when you are considering to use an external Javascript library in your cljs browser application.

However, different from clojure's interoperability with Java, ClojureScript has its own characteristics when you are interoperating with JavaScript and JavaScript based libraries.

Clojure types are not fully compatible with JavaScript types In ClojureScript, you can never treat a Clojure map as a JavaScript object although they have similar characteristics. You have to do some conversion before passing a clojure map to javascript functions. Matthew Gilliard made a sample of such conversion.

JavaScript package is not Clojure namespace This could be a common mistake for ClojureScript newbie. Actually, JavaScript doesn't have concept of "Package" or "Namespace". Many JavaScript libraries(dojo, Google Closure) made enhancement on this. ClojureScript also takes advantage of this mechanism. So before you start to coding with closure, you may browse closure library API document, and find a module called goog.net which includes lots of types. Then you write this:
[cc lang="clojure"]
(ns myjs
(:require [goog.net :as gnet]))
[/cc]

But compiler shows you "ERROR: JSC_MISSING_PROVIDE_ERROR. required "goog.net" namespace never
provided at ... ". This is not a PATH issue. The root cause is that closure module has a lower granularity than Clojure ones. Types are often contained in their own modules. You can find closure source code in clojurescript/closure/library/closure. Modules are declare with goog.provide function. Thus, you should require this name instead of the logical module name.
[cc lang="clojure"]
(ns myjs
(:require [goog.net.XhrIo :as gxhr]))
[/cc]

In addition, ClojureScript does not support 'use'.

Just use full name for JavaScript class For functions contains in some module, you can refer it with the clojure way:
[cc lang="clojure"]
(ns myjs
(:require [goog.dom :as dom]))
(dom/$ "element-id")
[/cc]

But for classes, just use the full name and ignore the module alias.
[cc lang="clojure"]
(ns myjs
(:require [goog.net.XhrIo :as gxhr]))
(def xhr (goog.net.XhrIo.))
[/cc]

These are basic tips before you start using Closure with ClojureScript. Leveraging on Google's closure library, you can create cross-browser JavaScript application with Clojure easily.