Hiccup compiler similar to sablono
See: https://medium.com/@rauh/a-new-hiccup-compiler-for-clojurescript-8a7b63dc5128
There is no macro for you to use. You must create your own macro and call hicada from it:
(defmacro html
[body]
(hicada.compiler/compile body {:create-element 'js/React.createElement
:transform-fn (comp)
:array-children? false}
{} &env))
This is your hiccup that you got passed to your macro and should pass along.
A map with the following keys:
-
:array-children?
: See the blog post for details. For product build of React only or you'll enojoy a lot of warnings :) -
:create-element
: A symbol to a CLJS/JS function that gets called with the precompiledtype config-js child-or-children
. Defaults to'js/React.createElement
-
:wrap-input?
: If inputs should be wrapped. Try without! You're responsible for requiring the CLJS namespace (create a.cljs
file with the same name as your macro namespace and it will get required automatically. -
:rewrite-for?
: Rewrites simple(for [x xs] ...)
into efficient reduce pushing into a JS array. -
:emit-fn
: gets called with[type config-js child-or-children]
-
:server-render?
: Doesn't convert anything to JS. Useful if you still want to process transform-fns and use other libraries (such as Rum) for server side rendering -
:camelcase-key-pred
: By default keyword and symbol map keys are converted from kebab-case to camelCase. Ie.[:> Foo {:do-it ture}]
will result inReact.createElement(Foo, {"doIt" true})
. But[:> Foo {"do-it" true}]
will not do the conversion. With a custom function you can fine tune which keys are converted and which are not. -
:transform-fn
: Called with [[tag attrs children env]] before emitting, to get transformed element as [tag attrs children] -
:child-config
: Called for every element with [config raw-element normalized-element] to get a new configuration to process element's children with. This allows to keep track of levels in the element tree, e.g. to create anhtml
form, that adds attributes at the root.
React Native special options:
-
:no-string-tags?
: If set totrue
: Never output string tags (don't exits in react native) -
:default-ns
: Any unprefixed component will get prefixed with this namespace symbol (eg.'foo.bar.xyz
)
See the default-handlers
var in hicada.compiler
for examples. By default
:*
(React Fragments) and :>
(React components) are defined.
Your macro environment. Pass in &env
.
You can use hicada with:
- Reagent, it will happily accept precompiled hiccup
- Rum, simple overwrite the
sablono.compiler/compile-html
macro. - Om
There is a lot of examples in the bottom of the hicada.compiler
namespace.
Check them out!
For instance, if you often clone elements you can write a DSL to support it:
(compile '[:div
[:span {:key "foo"} a b c]
[:clone x {:key k} one two]
[:clone x {:key k}]]
{:array-children? false ;; works with both!
:emit-fn (fn [tag attr children]
;; Now handle the emitter case:
(if (and (seq? tag) (= ::clone (first tag)))
(list* 'js/React.cloneElement (second tag) attr children)
(list* 'js/React.createElement tag attr children)))}
{:clone (fn [_ node attrs & children]
;; Ensure props + children are in the right position:
[(list ::clone node) attrs children])})
;; =>
(js/React.createElement
"div"
nil
(js/React.createElement "span" (js* "{'key':~{}}" "foo") a b c)
(js/React.cloneElement x (js* "{'key':~{}}" k) one two)
(js/React.cloneElement x (js* "{'key':~{}}" k)))
You could create your own handler to transform markdown at compile time:
[:*md*
"This is *great*, why not:"
"Hi there *" user-name "*"]
Hicada stands for "Hiccup Compiler aus dem Allgäu".
EPL, same as Clojure.