I’ve long been a fan of Stuart Sierra’s reloaded workflow. When I’m working on a ClojureScript project that doesn’t use Figwheel or another tool to assist with live code reloading, this is the pattern I reach for to help manage iterative and interactive development.
Here’s how I fixed that.
Intro to the Workflow
After opening my project in Spacemacs and launching an nREPL session (via the shortcut for
[, ']), I can open the REPL buffer using
[, s s]. Then, due to the way I’ve configured my project, I’m automatically placed into a specific namespace with functions for starting my server, shutting it down, and reloading it.
It’s easy enough to open the REPL buffer and call these functions manually. My first approach was to create some keyboard shortcuts that would programatically open the REPL buffer, enter the text to call these functions, and then hide the REPL buffer again.
I ended up using another technique altogether. While I was researching the option of adding a custom Spacemacs menu option, I found that Spacemacs provides a function called
spacemacs/set-leader-keys-for-major-mode. If you use this function, you can add your own option that appears in the major mode menu,
[SPC m]. E.g.,:
(spacemacs/set-leader-keys-for-major-mode 'clojure-mode "x" 'my-emacs-lisp-fn)
This would invoke your
my-emacs-lisp-fn whenever you press
SPC m x.
A Better Solution
After some researching, I found that CIDER’s already got some integration with the
clojure.tools.namespace library. Specifically, it uses the library when you use the command
[SPC m s x], or
cider-refresh to reload all the relevant namespaces.
That’s perfect, except it can’t automatically assist me with tearing down the state of my running app and then restarting it afterwards.
Fortunately, after poring through the docs for CIDER, I found that you can set some (global) variables to control this behavior.
cider-refresh-before-fn: a string naming the Clojure function to be called before tearing down your app
cider-refresh-after-fn: a string naming the Clojure function to be called after your code has been freshly loaded
As mentioned, these are variables global to the Emacs process. This does present a slight problem if you intend to work on multiple Clojure projects within Spacemacs.
Fortunately, with Spacemacs, you already have the Projectile plugin loaded. Projectile comes with some built-in support for defining project-specific configuration that you can check in to your Git repository. There’s even a built-in editing mode for it. To try it out, use
[SPC p e] while you are editing a file in your project.
For this project, my
.dirs.locals.el looks like this:
((nil . ((cider-refresh-before-fn . "my.ns.repl/stop") (cider-refresh-after-fn . "my.ns.repl/start") )))
With this in place, I can tear down and reload my entire app while it’s running in a REPL embedded in Spacemacs, with just this keystoke:
[, s x].
All the relevant configuration is stored checked into my Git repository, so it’ll work out of the box for anyone else editing this project in Spacemacs, as well.