What's the right way to hot-reload dependencies without restarting the repl?

I use leiningen, Emacs and cider.

clojure repl starting very slow, the question is how to add dependencies on the fly.

I’ve tried pomegranate, it seems only worked at current repl session.

1 Like

What do you expect it to work at beyond the current repl session?

yes, is there a way to do so?

You just need to add the dependencies to your project.clj file, to use them in the next REPL session.

I’m reading @sound2gd’s question as “What’s a workflow with hot-reloaded dependencies that works well”. Which I’m also interested in. Perhaps a wrapper around Pomegranate that also edits your project.clj or deps.edn file would be nice.

clj -A:find-deps at https://github.com/hagmonk/find-deps might be worth looking at – it’s rewriting deps.edn files.

1 Like

bravo, that’s what I want.

I think this should be a basic feature of “REPL driven development”.

once you open the REPL, you can interactively do anything your mind goes, withouting exiting the creative flow.

Ya, I don’t think I know of something that will update your lein profiles and pull in the dependencies into the running REPL all together.

Normally I add my dependencies to the user or repl profile https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md#default-profiles which I want to have available globally.

So I might use pomegranate to try out libs, and when I find something I like, I’d update my user or repl profile with it.

I also go and update my deps.edn repl alias, because I often use both lein and clj.

When in Emacs though, you need to specify to Emacs that you want to use the repl alias when jacking in by setting: cider-clojure-cli-global-options. Otherwise it won’t use an alias.

In lein, the user profile is always merged in. Can’t remember if cider-jack-in uses the repl profile by default, but that could also be configured using cider-lein-global-options in cider.

Here’s the doc for cider Jack in: https://docs.cider.mx/cider/basics/up_and_running.html

An alternative to all the above, is that you can instead add pomegranate as a dependency in your lein user profile and your deps alias which you’ve configured Cider to use.

And then you can also add a dependency on: https://github.com/gfredericks/user.clj as well to both these places.

Now, you can create a global user.clj which both lein and clj will use when starting a repl. In that user.clj, you can then add pomegranate code to pull in dependencies on load. With that options, you only need to modify your user.clj overtime as you pull in more and more deps. And it feels a bit like doing everything at the repl, since you can add pomegranate code to your user.clj, eval it, and if you like it just save it and it’ll persist beyond your current repl session.

thanks, but maybe user.clj solution is not what I expected.
I expect this:

my daily routine:

  1. run lein repl
  2. eval some code with cider, find some lib interesting, add to project.clj
  3. stop repl, re-run lein repl

this needs improvements. such as not stop repl , just hot-reload it.
and cider recognize it, auto-complete functions or methods that lib provides, and eval code that use that lib.

this needs improvements. such as not stop repl , just hot-reload it.

That’s what pomegranate does?

  1. Run lein repl
  2. Connect to it from Cider
  3. Open user.clj
  4. Add your dependencies to pomegranate:
(add-dependencies :coordinates '[[cool-lib-i-found "1.2.2"]]
                  :repositories (merge cemerick.pomegranate.aether/maven-central
                                       {"clojars" "https://clojars.org/repo"}))
  1. Eval user.clj
  2. C-X-S to save user.clj

Now your new lib is available inside your current Cider REPL, with auto-complete, doc, etc.

If you restart the repl, or your computer, etc, basically next time you run lein repl, user.clj will run again so your lib will be there as well.

since 1.0.0, pomegranate can not achieve that :rofl:

Works for me, are you using: https://github.com/clj-commons/pomegranate ?

This is what I have in my user.clj:

(require '[cemerick.pomegranate :as pomegranate :refer (add-dependencies)])

(let [cl (.getContextClassLoader (Thread/currentThread))]
  (.setContextClassLoader (Thread/currentThread) (clojure.lang.DynamicClassLoader. cl))
  (add-dependencies :coordinates '[[com.rpl/defexception "0.1.0"]
                                   [com.rpl/proxy-plus "0.0.1"]]
                    :repositories (merge cemerick.pomegranate.aether/maven-central
                                         {"clojars" "https://clojars.org/repo"})))

Using Java 8.

I tried it with:

[com.rpl/defexception "0.1.0"]
[com.rpl/proxy-plus "0.0.1"]

I started without them defined in pomegranate. Opened my user.clj, added them, pressed C-x C-k to eval user.clj again. It pulled in both dependencies dynamically into my repl. I was then able to require them and use them directly, with auto-complete and eveything (except the namespace didn’t auto-complete until I required it).

I then did C-x C-s to save my user.clj. I killed the repl, and started a repl again, connected to it from Cider, and tried to require defexception, and it worked.

1 Like

Last time I tried it, there was a bug in the current lein repl. Something like this https://github.com/nrepl/nrepl/issues/113