anmonteiro Code ramblings

Writing Om Next Reloadable Code — A Checklist

It didn’t take long since Figwheel came into our ClojureScript environments for it to become a crucial part of our development workflow. Its code hot loading magic provides the basis for an easy, enjoyable interactive programming experience. The rest — writing code that can be repeatedly evaluated without disturbing our running program’s state — is up to us. In this post I will go through what you need to know to start writing reloadable code in Om Next.

  • defonce your app-state and reconciler

  • As stated in the Figwheel docs, top-level definitions that are defined with def will be redefined every time you hit the save button, possibly compromising the state of your components at that point in time. So remember to always defonce any top-level definitions that contain local state; this way the identifier won't be redefined and any changes to it won't be seen 1.
  • (defui ^:once MyComponent) is also a thing

  • Applying the :once metadata to your Om Next components is the equivalent of using defonce to define the top-level variables in your program. It will prevent the React components constructors from being redefined, while patching those components' JavaScript prototypes to use the newly written (and hotloaded) code.
  • only call add-root! on the initial load

  • add-root! mounts an Om Next component in the DOM. The problem with calling add-root! on reload is that successive calls to this function will result in the Om Next reconciler unmounting any components currently mounted on the target node prior to actually performing the new mounting operation. Below is a simple code example of how to achieve what I've been describing. I imagine variations of it can be used as a Figwheel reload hook.
(defonce root (atom nil))

(defn init []
  (if (nil? @root)
    (let [target (js/document.getElementById "app")]
      (om/add-root! reconciler RootComponent target)
      (reset! root RootComponent))
    (.forceUpdate (om/class->any reconciler RootComponent))))

I hope the above advice will prove useful in your Om Next journey. Thanks for reading!

1 also keep in mind that this might not be desirable if you change whatever that definition contains. A full reload will probably be necessary in that case.