Skip to content
/ uix-ssr-demo Public template

Demo of using uix and server-side rendering

License

Notifications You must be signed in to change notification settings

elken/uix-ssr-demo

Repository files navigation

UIX SSR Demo

.github/assets/demo.png

A simple application demonstrating how to use SSR with Uix.

It’s recommended to read through those docs to familiarize yourself with the setup, but essentially we have 3 components working together to provide the application.

Running

In order to get started, you have to ensure you have the following tools installed:

  • clojure
  • Some version of Java
  • yarn/npm/pnpm (the bb script uses npm but you can just run the task manually)

If you want to use the bb script to make it easier to run tasks, then also , otherwise use the following commands:

If you prefer not to use the bb script, then use the following commands

clj -M:dev -m server.main # Server
npm run dev               # Client (assumes npm, replace with however your js package manager would run the dev task)

Otherwise install babashka and use the following:

bb server # Server
bb client # Client, assumes npm but you can adjust as needed
bb dev    # Run both in parallel (make sure you wait for the server to startup too)

Components

We have a very simple ring server whose sole purpose is to:

  • Return our hydrated markup by default on all endpoints (a lazy choice to make the app as simple as possible, DON’T DO THIS IN PRODUCTION).

    The reason we’re using var-get and resolve here rather than just calling the component directly is so we get a reference to the value rather than the value itself, so when our reload middleware reloads; we also get the latest markup.

  • Attempt to return a resource found in a folder called =”public”= on our classpath (which is where our static resources live, resources/public)
  • Wrap some reload middleware around that to ensure that any file saves trigger the ring server to reload. This is done to ensure that the server always returns the correct component HTML

With some extra niceties for a REPL environment.

A shared cljc namespace of our components. In here you write components as you would regularly, you just have to be aware of things like hooks not running on the server; and the idea that these components are rendered on the server first so you have to make sure to guard away things like JS interop like so (from the Uix docs linked above)

(defui title-bar []
  ($ :div.title-bar
     ($ :h1 "Hello")
     ;; js/console.log doesn't exist on JVM, thus the code
     ;; should be included only for ClojureScript
     ($ :button {:on-click #?(:cljs #(js/console.log %)
                              :clj nil)}
        "+")))

A cljs namespace of the client hydrating the React root from the server. The more simplistic explanation is:

  • Server renders the DOM to a string
  • Server sends that generated markup along with the index.html (important to note here that the typical <div id="root"></div> element is still required to be present, the rest of the DOM is a child of that)
  • The index.html also includes a script tag to load this client bundle; which will hydrate the root we setup and load the client version of the page on top

All we need to do on the client side then is hydrate our =”root”= node and we’re done.

Also included is a preload namespace to setup react-refresh, giving us client-only local state persistence.