Better ClojureScript Node REPL Defaults

Hi there! Welcome back — to you as much as to me. It's been a while that I've published anything but here we go: a little quality of life improvement for anyone driving a Node.js REPL from ClojureScript.

The Problems

There's two issues I often run into when working with ClojureScript and Node.js REPLs:

  1. many values are async, resulting in a <#Promise> return value
  2. uncaught errors will cause the Node.js process to exit

The first applies to any kind of ClojureScript REPL while the second is a more Node-specific problem. Losing your REPL state whenever something fails is annoying. This behavior makes sense when you run Node.js in production but for a REPL... not ideal.

A Workaround

Fortunately a bandaid solution is pretty trivial. To solve 1) we can make use of the excellent portal tool. For 2) we can install a handler for unhandledRejection events, catching the error and reporting it in whatever way we like.

Below is a namespace that can be added to your :preloads or just required when you start a new REPL session.

(ns acme.node-repl-preloads
  (:require [portal.api :as portal]))

(js/process.on "unhandledRejection"
               (fn [err]
                 (js/console.log "unhandledRejection" err)
                 (tap> {:unhandledRejection err})))

(when (.-ACME_DEV js/process.env)
  (portal/open)
  (add-tap portal/submit))

I add this to my node-repl helper like this:

  (shadow/node-repl
    {:config-merge [{:devtools {:preloads '[acme.node-repl-preloads]}}]})

Now, with ACME_DEV set, we'll get a Portal window whenever we start a Node REPL, allowing us to chain promises into tap> and inspecting their value that way.

In addition to that any errors will also be logged to the console and to the Portal window — without crashing the process 🙂 From where I stand this would be a good default behavior but messing with error handling obviously comes with it's own tradeoffs.

Adding another handler for unhandledException is probably a good idea.

Anyways, nice to be back. I hope this is a slight improvement to someone's setup 🤗

@martinklepsch, August 2023