# Mostly clueless

but curious to find out
Aug 29, 2023

# 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 🤗