30 August 2019

How to add new dependency at runtime to Clojure project

If you are working with Clojure for a while you may come across the following situation.

While you working on some project you have your REPL session up and working with the code base and realized that you need to add some external dependency to the project.

For me in the past I normally stop the REPL and then add the new dependency to the project.clj or deps.edn and then restart REPL from the beginning.

This is well and good except that it is annoying and it interrupts your flow and thus make you less productive.

Then I found out about one library that allow me to avoid this pattern and I am very happy to be able to use this all the time. It is call Alembic

How to do it

For every project, I will include the following as dependency during development phrase.

;; dependency vector
:dependencies [
  [org.clojure/clojure "1.10.1"]
  ;; .. more library
  [alembic "0.3.2"]]

;; Or alternatively add it to your dev profile
:profiles {:dev {:dependencies [[alembic "0.3.2"]]}}

I keep the following snippet handy and include it as I need it.

(require '[alembic.still :refer [distill lein]]')

(defn add-project-dependency
  "Add project dependency at runtime via alembic."
  ([dep-vector]
   (let [[lib-name lib-version] dep-vector]
     (add-project-dependency lib-name lib-version)))
  ([lib-name lib-version]
   (let [dep-name (symbol lib-name)
         dep-version (name lib-version)]
     (alembic.still/distill [dep-name dep-version]))))

Now when I need to add new library to existing project without restarting the project I will do something like

  ;; Try evaluate the following
  (add-project-dependency :hara/io.file "3.0.5")
  ;; OR
  (add-project-dependency "hara/io.file" "3.0.5")
  ;; OR
  (add-project-dependency '[hara/io.file "3.0.5"])

The magic is that alembic will allow you to add the new dependency to the project at runtime.

Tags: development clojure cider emacs repl