-
-
Notifications
You must be signed in to change notification settings - Fork 66
Optimization Tips
You can explicitly set the attributes to {}
and avoid the ambiguity of children vs attributes that would need to be resolved during runtime. Observe:
(macroexpand-1 '(html [:a (foo)]))
=>
(clojure.core/let
[attrs99902 (foo)]
(clojure.core/apply
js/React.createElement
"a"
(if (clojure.core/map? attrs99902)
(sablono.interpreter/attributes attrs99902)
nil)
(if (clojure.core/map? attrs99902)
nil
[(sablono.interpreter/interpret attrs99902)])))
(macroexpand-1 '(html [:a {} (foo)]))
=> (js/React.createElement "a" nil (sablono.interpreter/interpret (foo)))
Not really sablono specific but I think it fits here:
for
macro generates a ton of code because it is very powerful. Often, though, you don't need the lazyness of for
and the flexibility and would be better off with a simple mapv
.
(macroexpand-1 '(for [x y]
[:span "hi"]))
; => <omitted since it's very very long>
Note also that the body (here: [:span "hi"]
) will be emitted twice, which can lead to even larger JS code when your body is big.
There is much less powerful and eager macros here: https://gist.github.com/rauhs/d49d6f8a6f5fbb8230647c5b2ac210b2
You can further add a type hint to avoid the call to interpret
:
(macroexpand-1 '(html [:a {} ^String (foo)]))
=> (js/React.createElement "a" nil (foo))
Obviously, only do this if your (foo)
function call returns React elements.
Note that, even though the type hint says ^String
, the function (or variable) doesn't have to return a string. This is only used because this type hint is the only one that sablono recognizes and removes the interpretation call. The function can also return a vector or list of (React) elements.
UPDATE: For a non-compressed production build the difference of the following was around 4kb for me, however, with gzip and brotli the difference was less than 400 bytes. So the following might not be worth it:
Use at your own risk.
Since calls to React.createElement
don't get minified by the google closure compiler, you can manually create an alias and rewrite the code generated by sablono:
In your clj macros file:
(defmacro html
"Rewrites (js/React.createElement ...)
to (js/R ...)
needs proper externs."
[body]
(let [sab (sablono.compiler/compile-html body)]
(clojure.walk/postwalk-replace {'js/React.createElement 'js/R} sab)))
You should also add an externs file containing:
var R = function(type, props, children) {};
and further create the alias somewhere before you render anything:
(set! js/R js/React.createElement)
and then your code will look like this:
(macroexpand-1 '(html [:a "hi"]))
=> (js/R "a" nil "hi")