Skip to content

Commit b1e21c1

Browse files
committed
Document :require-macros usage pattern
1 parent 4b9b6cf commit b1e21c1

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,56 @@ components in the style rules section, even in ClojureScript, see the section
294294
[:.foo referenced]) ;; use as style rule
295295
```
296296

297+
#### Computing values (referencing vars) inside style rules in cljc files
298+
299+
Style rules are processed during macroexpansion, which happens in Clojure, even
300+
when compiling ClojureScript. This means that any code inside style rules needs
301+
to be able to evaluate in Clojure by the time ClojureScript starts compiling the
302+
`defstyled` form.
303+
304+
Consider this namespace
305+
306+
```clj
307+
;; components.cljc
308+
(ns my.components
309+
(:require [lambdaisland.ornament :as o]))
310+
311+
(def my-tokens {:main-color "green"})
312+
313+
(o/defstyled with-code :div
314+
{:background-color (-> my-tokens :main-color)})
315+
```
316+
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.
320+
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.
324+
325+
```clj
326+
(ns my.components
327+
(:require [lambdaisland.ornament :as o])
328+
#?(:cljs (:require-macros my.components)))
329+
330+
#?(:clj
331+
(def my-tokens {:main-color "green"}))
332+
333+
(o/defstyled with-code :div
334+
{:background-color (-> my-tokens :main-color)})
335+
```
336+
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.
342+
343+
Wrapping `my-tokens` in `#?(:clj ...)` is not strictly necessary, but it helps
344+
to emphasize the point that this definition is only ever used on the Clojure
345+
side, you don't need it in your compiled ClojureScript.
346+
297347
#### Shadow-cljs build hook example
298348

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

test/lambdaisland/ornament_test.cljc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
(:require [lambdaisland.ornament :as o]
44
[clojure.test :refer [deftest testing is are use-fixtures run-tests join-fixtures]]
55
#?(:clj [lambdaisland.hiccup :as hiccup]
6-
:cljs [lambdaisland.thicc :as thicc])))
6+
:cljs [lambdaisland.thicc :as thicc]))
7+
#?(:cljs
8+
(:require-macros lambdaisland.ornament-test)))
79

810
(defn render [h]
911
#?(:clj (hiccup/render h {:doctype? false})
@@ -58,9 +60,8 @@
5860
(def my-tokens {:main-color "green"})
5961

6062
;; Referencing non-defstyled variables in rules is only possible in Clojure
61-
#?(:clj
62-
(o/defstyled with-code :div
63-
{:background-color (-> my-tokens :main-color)}))
63+
(o/defstyled with-code :div
64+
{:background-color (-> my-tokens :main-color)})
6465

6566
;; TODO add assertions for these
6667
(o/defstyled with-media :div
@@ -131,11 +132,19 @@
131132
:color "#cff9cf"
132133
:text-decoration "underline"})
133134

135+
;; For use in reagent, `::o/attrs` are still propagated to the element
134136
(o/defstyled form-2 :div
135137
([a]
136138
(fn [b]
137139
[:<> "hello"])))
138140

141+
;; Will fail to compile on cljs if the :require-macros line is missing
142+
(o/defstyled with-str :div
143+
{:border (str "1px solid red")}
144+
([props]
145+
[:<> "foo"]))
146+
147+
139148
#?(:clj
140149
(deftest css-test
141150
(is (= ".ot__simple{color:#fff}"

0 commit comments

Comments
 (0)