Skip to content

Commit 78f3a64

Browse files
committed
Expand documentation re. CLJC and :require-macros
1 parent b1e21c1 commit 78f3a64

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

README.md

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,14 @@ Consider this namespace
314314
{:background-color (-> my-tokens :main-color)})
315315
```
316316

317-
In Clojure this works as you would expect, but when compiling this as a
318-
ClojureScript file it fails, because this file was never loaded as a Clojure
319-
namespace, so the var `#'my.components/my-tokens` doesn't exist.
317+
In Clojure this works as you would expect but when compiling this as a
318+
ClojureScript file it fails. The failure is due to the file never being loaded
319+
as a Clojure namespace, so the Clojure var `#'my.components/my-tokens` doesn't
320+
exist in the Clojure environment which is where macro expansion takes place.
320321

321-
To fix this you can use `:require-macros`. This instructs the ClojureScript
322-
compiler to load a given Clojure namespace before continuing the compilation of
323-
the current namespace.
322+
To fix this you can use the `:require-macros` directive which instructs the
323+
ClojureScript compiler to load a given Clojure namespace (in this case the
324+
current namespace) before continuing the compilation of the current namespace.
324325

325326
```clj
326327
(ns my.components
@@ -334,16 +335,57 @@ the current namespace.
334335
{:background-color (-> my-tokens :main-color)})
335336
```
336337

337-
This way before ClojureScript compiles `my.components` as a cljs file, it first
338-
loads `my.components` as a clj namespace. This creates the `#'my-tokens` var. It
339-
the continues with the cljs compilation, so that when it gets to `defstyled` and
340-
processed the rules (`{:background-color ...}`) `my-tokens` resolves to the
341-
correct var, and can be evaluated.
338+
This addresses the problem by instructing the ClojureScript compiler to first
339+
load `my.components` as a clj namespace thereby creating the `#'my-tokens`
340+
Clojure var. The compiler then continues with the cljs compilation and when it
341+
gets to expansion of the `defstyled` macro form (specifically processing of the
342+
style rule `{:background-color ...}`) the `#'my-tokens` var is available in the
343+
clj environment and evaluated for it's value which is then included in the
344+
Ornament style registry.
342345

343346
Wrapping `my-tokens` in `#?(:clj ...)` is not strictly necessary, but it helps
344347
to emphasize the point that this definition is only ever used on the Clojure
345348
side, you don't need it in your compiled ClojureScript.
346349

350+
##### Important note about CLJC files and clojure.core symbols
351+
352+
If you do __any__ computation in your style rules it is recommended that you
353+
require the file as clj by utilising the `:require-macros` directive to self
354+
require the namespace.
355+
356+
```clj
357+
(ns my.components
358+
(:require [lambdaisland.ornament :as o])
359+
#?(:cljs (:require-macros my.components)))
360+
361+
(o/defstyled with-code :div
362+
{:background-color (str "red")})
363+
```
364+
365+
The need for this is a subtle consequence of the same interaction between
366+
Clojure and the ClojureScript compiler outlined in the previous section. A
367+
similar issue will manifest if you try to use `clojure.core` symbols in your
368+
style rules without requiring the clj namespace. This is surprising at first but
369+
makes sense after considering that it is the `ns` form that auto refers all
370+
`clojure.core` symbols into the current namespace. It follows that if the `ns`
371+
form is not evaluated, because we do not require the cljc file as a clj file,
372+
then no symbols mapping to the `clojure.core` symbols will have created in the
373+
current namespace. The `clojure.core` symbols are however interned, and as such
374+
fully qualifying the namespace will work but that is not an ergonomic solution.
375+
376+
```clj
377+
(ns my.components
378+
(:require [lambdaisland.ornament :as o]))
379+
380+
;; Does not work
381+
(o/defstyled with-code :div
382+
{:background-color (str "red")})
383+
384+
;; Does work but not recommended
385+
(o/defstyled with-code :div
386+
{:background-color (clojure.core/str "red")})
387+
```
388+
347389
#### Shadow-cljs build hook example
348390

349391
This is enough to get recompilation of your styles to CSS, which shadow-cljs

0 commit comments

Comments
 (0)