This document describes internals of UIx to give you a better overview how the library works internally.
On the surface UIx is a wrapper for React.js, it consists of two packages: uix.core
and uix.dom
, the former wraps react
and the latter wraps react-dom
.
uix.dom
namespace is a thin wrapper around react-dom
API, as simple as that. uix.dom.server
is a custom made serializer that allows to render UIx components on JVM (of course third-party JS components won't run on JVM, so the JVM renderer is mostly useful for purely UIx made UIs or HTML templating, think static website generators).
This one is a lot more involved. While the core package wraps a public API from react
, it also makes hooks nicer, runs an internal linter and compiles components and UI structure into a more efficient code.
defui
and fn
macrosdefui
is how you define a UIx component. What the macro is doing? Multiple things:
react-refresh
setup for hot-reloading in devuix.core/fn
macro is similar to defui
, but should be used to create anonoymous components, which is useful for render props technique.
$
macro$
is basically React.createElement
, but with API that makes it nicer to use in Clojure world. Here's what it does:
This part, while there's not much code to it, is probably where the most of complexity in UIx lives.
uix.compiler.aot
namespace (ahead of time compiler) takes care of compiling $
elements to ClojureScript that is as close as possible to plain JS from performance standpoint. The compilation process boils down to transforming something like ($ :div {:on-click on-click} ...)
into (react/createElement "div" #js {:onClick on-click} ...)
. The end goal is to have as less Clojure data types as possible in the end to achieve best performance.
The compiler is not strict and makes a set of tradeoffs to provide flexibility for developers. Thus it's allowed to have dynamic (resolved at runtime) props, although in that case props map will be interpreted at runtime.
UIx wraps all React's default hooks and adds an extra layer to hide differences between JS and Clojure world, to make sure that writing is a bit less annoying:
js/undefined
from a hook in a way that nil
becomes acceptable return value as welluix.linter
implements a built-in linter that takes care of validating components and hooks. The linter is extensible via public API.
The linter leverages ClojureScript's analyazer to retrieve information about code structure at compile-time. This data provides info about local and global vars, usages of vars, and of course the data structure representing the code being analyzed.
When analyzing the linter collects and reports errors into ClojureScript's analyzer, that then takes care of printing those errors in terminal, failing a build and propagating them into shadow-cljs's on screen error display.
Can you improve this documentation? These fine people already did:
Miro, Adam Renklint & roman01laEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close