Adding dependencies during REPL-driven development
Developing in a repl is a different paradigm, and one that you won’t want to leave. It’s like the fun part of web development, after you’ve experienced proper hot-reloading and can’t imagine living without it. Once you’re in that flow, you start to notice the things that throw a wrench in it. Please don’t break my flow!
One flow-breaking culprit you’ll encounter is adding a new package. I recently decided that this problem must be solved already, and sure enough, a search revealed a few solutions. As always with Clojure, the community is great and the tooling is evolving, so every piece of the chain has a history. My goal in writing this is to share what worked for me and prompt anyone doing it better to let me know what that is, because I want it!
Resources
Section titled “Resources”A thread in Clojureverse from January of this year covers this area somewhat: What’s the right way to hot-reload dependencies without restarting the repl?
I know rschmukler uses
wing.repl/sync-libs
for this, but I have not yet integrated that into my workflow, mostly because
the below worked for me without adding any new deps.
One method
Section titled “One method”I could stand to take more advantage of the src/user.clj namespace, as it is central to solving the need here. The user namespace seems to provide a space for dev-only functions, and it is the default namespace entered when starting most repls.
(ns user (:require [cemerick.pomegranate :refer [add-dependencies]]))
(defn add-dep [coords] (add-dependencies :coordinates coords :repositories (merge cemerick.pomegranate.aether/maven-central {"clojars" "https://clojars.org/repo"})))
(comment (add-dep '[[teknql/systemic "0.2.0-SNAPSHOT"]]) (add-dep '[[hawk "0.2.11"]]) (add-dep '[[cuerdas "0.3.2"]]) (add-dep '[[com.cognitect/transit-cljs "0.8.239"] [com.cognitect/transit-clj "0.8.300"]]))Evaluating the above (add-dep ...) calls was enough for me to keep going
without a restart, and try out a library a bit before adding it to my
deps.edn. It does duplicate some of the work though - you’ll still need to add
it elsewhere, or you’ll have an issue the next time you start your repl.
This also implies a pomegranate dependency, but for emacs/cider users, these are typically included already by cider’s jack-in command, so there shouldn’t be any extra work beyond the above function.
How do you handle this?
Section titled “How do you handle this?”How do you dynamically add clojure deps? What else interrupts development flow that shouldn’t?
I’d love to build up a documented answer to every repl-flow interruption. Fight for flow!