ClojureScript REPL Workflow with Figwheel

Roman Liutikov wrote a great piece on bringing REPL workflow to ClojureScript.

In the article, Roman shows a neat trick to override ClojureScript's built-in Browser REPL function for evaluating JavaScript code. The overridden version calls a render function, which will rerender the app after each REPL evaluation. You'll see the changes in your UI component immediately after you've evaluated them in REPL.

But hey, what about Figwheel? I'm not using Browser REPL. I'm using Figwheel! How could I do the same with Figwheel?

Rerendering after eval in Figwheel

The function that needs to be overridden in Figwheel is figwheel.repl.eval-javascript**

If we take Roman's snippet as a base and modify it a bit for Figwheel, we get this:

(comment
  (let [eval-js (.. js/figwheel -repl -eval_javascript_STAR__STAR_)]
    (set! (.. js/figwheel -repl -evaluate_javascript_STAR__STAR_)
          (fn [& args]
            (let [ret (apply eval-js args)]
              (when (= :success (:status ret))
                (render)) ;; your render function
              ret)))))

Call this function once to set it up and start evaluating changes in the REPL. You'll see your app rerendering and reflecting all UI changes immediately.

Async rerendering

If you notice, like I did, that Figwheel REPL starts to time out quite often, your rendering function execution is taking too long.

I was able to fix this by making the rerendering async.

Here's an improved version:

(comment
  (let [eval-js (.. figwheel -repl -eval_javascript_STAR__STAR_)]
    (set! (.. js/figwheel -repl -evaluate_javascript_STAR__STAR_)
          (fn [& args]
            (let [ret (apply eval-js args)]
              (when (= :success (:status ret))
                (js/setTimeout ;; async rerender
                 (fn [] (render)))) ;; your render function
              ret))))))

But why?

Figwheel already implements code hot-loading, so why is this needed?

When the project size grows, Figwheel code hot-loading start to take some time. It's not terrible, but it's not fast, either. It takes seconds for Figwheel to catch up on the newest changes after the file is saved.

The REPL method instead is instant, and that feels pretty great.

My experience has been that rerendering after REPL eval works seamlessly with Figwheel's own hot-loading. You might first eval the change in REPL, see it rerendered, then save the file and soon see the ClojureScript logo on the corner indicating that Figwheel has also caught up on the latest changes.