Following up my last post on Google Closure, I wanted to give some pointers on including the library in your code. When you include the lib, it’s sometimes unclear when to use :require vs :import.

In David Nolen’s ClojureScript 101 post, he says:

Here we use :import so that we can use short names for the Google Closure constructors.

Note: :import is only for this use case, you never use it with ClojureScript libraries

If you look at the cljs analyzer, you’ll see the following error message in parse-import-spec:

(throw (error env
(parse-ns-error-msg spec "Only lib.ns.Ctor or [lib.ns Ctor*] spec supported in :import")))

We can see that the :import spec expects some type of constructor (referred to as Ctor in the error message). As an example, we can revisit cljs-http and look at the ns for cljs-http.util:

(ns cljs-http.util
(:import goog.Uri) ;;<-- Closure Library
(:require [clojure.string :refer [blank? capitalize join split lower-case]]
[cognitect.transit :as t]
[goog.userAgent :as agent] ;;<-- Closure Library
[no.en.core :refer [base64-encode]]))

The docs for goog.Uri show that Uri is a class, so its constructor is loaded via :import:

;;(:import goog.Uri)

(defn build-url
"Build the url from the request map."
[{:keys [scheme server-name server-port uri query-string]}]
(str (doto (Uri.) ;; <-- Constructor
(.setScheme (name (or scheme :http)))
(.setDomain server-name)
(.setPort server-port)
(.setPath uri)
(.setQuery query-string true))))

goog.userAgent is a namespace that provides several functions, so it’s loaded via :require:

;;(:require [goog.userAgent :as agent])

(defn user-agent
"Returns the user agent."
[] (agent/getUserAgentString)) ;;<-- simple fn call

One other point of confusion is Enums (e.g. goog.events.EventType). Enums are implemented as js objects; we :import them as constructors:

(ns cljs-made-easy.example.core
(:require [goog.events :as events]))
(:import [goog.events EventType]))

(def src ...)
(defn callback [] ...)

(events/listen! src EventType.CLICK callback)

I’ve seen enums used as EventType.ACTION and EventType/ACTION, and both appear to work. EventType.ACTION is used more frequently in my experience, but there doesn’t seem to be an idiomatic version. David Nolen points out that EventType/ACTION is incorrect because / always means namespace in cljs. So EventType.Action is definitely what you want to use.

So here’s your guideline: use :import for Closure classes and enums, and use :require for everything else.

Find this post useful? Share the love!

Recent Posts