ClojureScript macros can be loaded using the :require-macros
primitive in ns
forms (or require-macros
REPL special).
But, there is a shortcut you can take if a runtime namespace requires macros from its macro namepace file. This might be a bit tricky to understand so here is a concrete example.
Let's say you have a macro file:
$ cat src/foo/core.clj
(ns foo.core)
(defmacro add
[a b]
`(+ ~a ~b))
and a runtime file:
$ cat src/foo/core.cljs
(ns foo.core)
(defn subtract
[a b]
(- a b))
Let's start the REPL and try using these defs:
$ java -cp cljs.jar:src clojure.main -m cljs.repl.node
ClojureScript Node.js REPL server listening on 52109
To quit, type: :cljs/quit
cljs.user=> (require '[foo.core :as foo])
nil
cljs.user=> (foo/subtract 7 3)
4
cljs.user=> (foo/add 2 3)
WARNING: Use of undeclared Var foo.core/add at line 1 <cljs repl>
TypeError: Cannot read property 'call' of undefined
at repl:1:101
at repl:9:3
at repl:14:4
at Object.exports.runInThisContext (vm.js:54:17)
at Domain.<anonymous> ([stdin]:41:34)
at Domain.run (domain.js:191:14)
at Socket.<anonymous> ([stdin]:40:25)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:146:16)
cljs.user=> (require-macros '[foo.core :as foo])
nil
cljs.user=> (foo/add 2 3)
5
As you can see, as expected, you can't make use of the add
macros without explcitly making use of the require-macros
REPL special.
Now, lets make a minor change to the runtime file to require the macros file:
$ cat src/foo/core.cljs
(ns foo.core
(:require-macros foo.core))
(defn subtract
[a b]
(- a b))
The only difference is the addition of the :require-macros
spec in the ns
form.
Now, you can do this:
$ java -cp cljs.jar:src clojure.main -m cljs.repl.node
ClojureScript Node.js REPL server listening on 58951
To quit, type: :cljs/quit
cljs.user=> (require '[foo.core :as foo])
nil
cljs.user=> (foo/subtract 7 3)
4
cljs.user=> (foo/add 2 3)
5
As you can see, the macros are loaded and additionally made avaialble via the foo
alias.
If you do (doc ns)
you will see this described as Implicit macro loading.
Hope this helps!
If you are curious as to how this works, cljs.analyzer/macro-autoload-ns? is invoked by the analyzer in cljs.analyzer/desugar-ns-specs when processing ns
forms. (Using desugar-ns-specs
in bootstrapped environments was illustrated here.)