ClojureScript Dos and Donts: clj->js

New micro blogpost about the clj->js function. Feedback welcome!

3 Likes

Very interesting! This blog post from mike fikes has some benchmarks that support your point http://blog.fikesfarm.com/posts/2017-11-09-avoid-converting-javascript-objects.html.

What I would really like to have is a macro that can do what clj->js is doing for static values.

I’m working on a react-native app. We have a namespace where we define all the styles we are using through the app, it goes a little like this:

;; styles.cljc

;; Colors
(def green  "#47a8d8")
(def orange "#F16913")

;; Dimensions
(def gutter 10)
(def radius 2)

;; Actual style for a component
(def button-base {:flex 0
                  :padding gutter
                  :borderRadius radius})

(def button-default (assoc button-base :backgroundColor green))
(def button-warning (assoc button-base :backgroundColor orange))

I want to keep the expressive power of clojure to define/compose/merge those style declarations. But at the same time, I would like to be able to call something like clj->js at compile time to emit the js litterals (or throw an exception if the value cannot be statically determined at compile time).

;; some_component.cljs
(react/createElement react-native/view
                     #js {:style (macro-clj->js styles/button-default)})

I cannot seem to find how to do that… Emitting #js inside of a macro would not work, as it is a reader literal.

Any idea?

@chpill not a direct answer, but check lookbook for some inspiration about RN stylesheets composed at compile time.

1 Like

I added a link to Mike’s blog post, thanks for the pointer.

@chpill You can use js-obj macro to emit JS objects from macros.

But in your example, (macro-clj->js styles/button-default) wouldn’t work because the result of assoc is only available in runtime (and the macro only sees the symbol).

@juhoteperi if the styles namespace is declared in a cljc file, the style values would be available to the macro, wouldn’t they?

Macros work on Clojure forms - they do not introspect vars.

The best way is to wrap button-default and button-warning in a clj->js so that it happens once, at def-time.

I’ve experimented with this optimization a bit with the hiccup compiler I’m building - it will shallowly convert map literals to JS objects, but will wait until runtime to convert vars.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.