Skip to content
Sam Estep edited this page Jun 30, 2016 · 9 revisions

Reloading modified source files using clojure.tools.namespace.repl/refresh (eg. by following Stuart's workflow) may return surprising results at the beginning:

boot.user=> (require '[clojure.tools.namespace.repl :as repl])
nil

boot.user=> (repl/refresh)
:reloading ()
:ok

No files reloaded? Looks like they are not found by c.t.n.repl, or being more specific scanned directories are simply incorrect. As the doc says directories may be overwritten by set-refresh-dirs:

boot.user=> (def dirs (get-env :directories))
boot.user=> (apply repl/set-refresh-dirs dirs)

Then you can reload namespaces, no problems.

If you'd like to incorporate this sort of reloading into your task pipeline during development, the third-party boot-refresh library provides a Boot task wrapping the refresh function that automatically handles set-refresh-dirs and other tricky issues. You can then compose that task with the built-in watch task to automatically reload your code as you change it.

Additionally, you can take a look at system, a library optimized for REPL reloading, built with Boot in mind.

Problems with setting refresh-dirs

The above method has an interesting side effect of refreshing the namespaces that are compiled for both Clojure and Clojurescript (e.g. cljc files) even if you're only using them through Clojurescript. For example, if you are using something like mount on the client side, the mount.core namespace will get reloaded on the JVM - the code is in the same file! This is bad, as the namespace has state that you don't want to touch.

As a workaround you might want to set the refresh-dirs exclusively to the sources that you actually need to reload:

(apply tns/set-refresh-dirs
  (map #(.getPath (io/file (System/getProperty "user.dir") %)) all-paths))

where all-paths is a set of sources/resources to refresh defined in your build.boot.

Clone this wiki locally