Adding hot reload to a shadow-cljs project

So at the end of my last post, I noted that "hot reloading" wasn't working. Turns out I had misunderstood the docs

The React and ClojureScript ecosystems combine to make this kind of thing super useful. The shadow-cljs system includes everything you need to do your hot code reload, without needing to resort to external tools.

In order to use it you simply run:

shadow-cljs watch build-id

I should have continued reading the next section, Lifecycle Hooks!. After reviewing my last post, the author of shadow-cljs, Thomas Heller also sent me a link to a blog post which was also super helpful.

So, let's get started and add code reloading!

In shadow-cljs, the ^:dev/after-load keyword is metadata that when added to the function definition, marks it as a function that needs to be run after the code has been reloaded. So I think I'm correct in saying that shadow-cljs is automatically reloading the code in the browser on any saved change, but it's not running any code unless we annotate the function definition with the metadata, to tell it to do so. 

Currently, our entrypoint function is:

(defn ^:export run []
  (rdom/render [indecision-app] (js/document.getElementById "app")))

We change it to:

(defn ^:export ^:dev/after-load run []
  (rdom/render [indecision-app] (js/document.getElementById "app"))
  (js/console.log "'run' called"))

In other words, we add the metadata, and just add a logging statement we can more easily see in the browser console when a code reload takes place. 

It's also possible to annotate a function that only gets called once, when the page first loads, e.g. to set up some state, using the ^:dev/before-load metadata on the function definition - see the links at the top of this post for more details.

By the way, if you're wondering what the ^:export metadata does, it's so that we (and I presume, shadow-cljs) can call the function from javascript in the browser