5

I'm using tools.namespace to provide smart reloading of namespaces on the REPL. However, when calling refresh or refresh-all, it throws an error.

user=> (require '[clojure.tools.namespace.repl :as tn])
user=> (tn/refresh)
:reloading (ep31.common ep31.routes ep31.config ep31.application user ep31.common-test ep31.example-test)
:error-while-loading user

java.lang.Exception: No namespace: ep31.config, compiling:(user.clj:1:1)

And it seems to end up in this weird state where (require ep31.config) works without an error, but afterwards the namespace isn't actually defined.

2 Answers 2

12

I kind of figured this out, this seems to be a combination of circumstances

  • there were AOT compiled classes left in target/classes from doing lein uberjar previously
  • tools.namespace doesn't function correctly when loaded namespaces are AOT compiled
  • target/classes is by default on the classpath

So long story short, if you did a jar/uberjar build before, then remove target/ and things should start working again.

The question I haven't been able to solve yet is why target/classes is on the classpath to begin with. I'm suspecting it's being added by Leiningen, but haven't found yet where or why it's happening.

Sign up to request clarification or add additional context in comments.

3 Comments

This is correct. Leiningen puts target/classes on the classpath by default for two reasons: 1) to make compiled Java sources available to the application, and 2) the output directory for AOT-compilation (*compile-path*) must be on the classpath.
So if you did a lein clean after doing lein uberjar you would not encounter your problem? Or rather did lein clean as soon as you got into a bad state such as described in your question.
I deleted my build/clojure directory (I'm using the gradle plugin) and restarted my REPL and that fixed it.
3

I learned this the hard way, documentation for :target-path says (https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L309-L313):

;; All generated files will be placed in :target-path. In order to avoid
;; cross-profile contamination (for instance, uberjar classes interfering
;; with development), it's recommended to include %s in in your custom
;; :target-path, which will splice in names of the currently active profiles.
:target-path "target/%s/"

I guess there has to be legacy reasons that :target-path "target/%s/" isn't the default.

2 Comments

While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review
Good point! Included the documentation for :target-path, now the answer should make more sense (the documentation is quite succinct on describing the problem).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.