Let’s say that I have a library xx with namespace xx.core, and I’m writing it in pure Clojure, intending to target both Clojure and ClojureScript. The de facto way to do this seems to using lein-cljsbuild’s crossovers and conditional comments. So far, so good. This premise is now obsolete. lein-cljsbuild has been deprecated in favor of reader conditionals, and there are many other namespace/macro ClojureScript enhancements. See the updated answer below.
Let’s say xx has a bunch of vars that I want its users, both in Clojure and ClojureScript, to be able to use. These can be split into three sorts of vars.
- Macros
- Functions / other vars that depend on no macro in xx (I’ll call these type-1 vars)
- Functions / other vars that just happen to do depend on a macro in xx (I’ll call these type-2 vars)
However, since ClojureScript requires macros to be separated from regular .cljs namespaces in their own special .clj namespaces, all macros have to be isolated away from all other vars in xx.core.
But the implementation of some of those other vars—the type-2 vars—incidentally depend on those macros!
(To be sure, only macros seem to be accessible using ClojureScript’s use-macro or require-macro. Just now I tested this; I tried out simply keeping everything (macros, type-1 vars, and type-2 vars) inside a single xx/core.clj file, and referring to it in a ClojureScript test file using (:use-macro xx.core :only […]). The compiler then emits a WARNING: Use of undeclared Var message for each non-macro var in xx.core that the ClojureScript file referred to.)
What do people tend to do in this situation? The way I see it, the only thing I can do is to…split the library’s public API into three namespaces: one for type-1 vars, one for macros, and one for type-2 vars. Something like…xx.core, xx.macro, and xx.util?…
Of course, this sort of stinks, since now any user of xx (both in Clojure or ClojureScript) has to know whether each var (of which there may be dozens) happens to depend on a macro in its implementation, and which namespace it thus belongs to. This wouldn’t be necessary if I targeted Clojure only. Is this really how it is right now, if I want to target both Clojure and ClojureScript?