When do I use :require vs :import?
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 David Nolen points out that 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.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.