Circular dependency bug when user.clj exists
weavejester opened this issue · comments
When lein cljx once
or lein cljx auto
is executed, any code in the user
namespace is automatically loaded. In the development profile, this namespace may be populated. For instance if a project is designed along the lines of Stuart Sierra's reloaded workflow, there may be a file "dev/user.clj" that is included in the development profile.
If this is the case, running lein cljx
can result in a circular dependency, if the user namespace depends on files that are generated by cljx.
I'm currently working around this with the following:
:aliases {"cljx" ["with-profile" "cljx" "cljx"]}
:profiles {:cljx {}}
That probably can't be solved as user.clj
is loaded by the Clojure runtime. See #20 for some related info.
Having a workaround might be the best that can be done. Maybe something to add to the documentation?
@weavejester Just to make sure I understand what that workaround is doing for you: :cljx
is empty, and so disables the :dev
profile, and thus your user.clj
(which is only on the classpath because of some configuration in the :dev
profile) is not visible when cljx runs?
user.clj
is a strange beast in general because of the stage at which it is loaded. May I suggest putting code that you might otherwise add to user.clj
into e.g. :repl-options :init
or :inclusions
?
@weavejester I use Sierra's reloaded pattern all the time, and I've run into the same issue and come to the same solution.
Do you think there's a neater way to workaround?
Or are you suggesting that we simply add a note about this to the README somewhere?
@cemerick, I usually have options set up like:
:profiles {:dev {:source-paths ["src" "dev"]}}
And then place dev-specific source files in a dev
directory, such as dev/user.clj
.
Obviously this causes problems for cljx, so my solution is:
:aliases {"cljx" ["with-profile" "cljx" "cljx"]}
:profiles {:dev {:source-paths ["src" "dev"]}
:cljx {}}
I wonder if it would be possible to have lein cljx
automatically merge in a :cljx
profile, in the same way that lein uberjar
automatically merges in a :uberjar
profile.
I'm not sure whether that would solve it completely, but it would at least remove the need for an alias.
Merging an empty profile means that e.g. :dev :depenencies
aren't available, and so custom :rules
provided by deps wouldn't be accessible.
This should work; prepend to your user.clj
:
(require '[cljx.repl-middleware :as cljx])
(reset! @#'cljx/cljx-load-rules {:clj cljx.rules/clj-rules})
@@#'cljx/install-cljx-load
It's so hairy-looking because those bits are currently intended solely for use by the nREPL middleware (thus the ns name), but they accomplish the same thing here: swapping in an enhanced clojure.core/load
that knows how to resolve, transform, and load .cljx
files.
I hadn't contemplated the need for this outside of the REPL integration, so something tidier would be needed; e.g. adding cljx.install-cljx-load
before all of your other :require
s could be all that's necessary, if such a namespace were provided that had a top-level forcing the delay in question.
Oops, Github converted my hyperlink to a cross-reference, and I have no way to delete it.
Thanks, the code in the preceding comment solves this for me.
Unh, just ran into this also :/
Also, prepending the following doesn't seem to work, so I opted for the "profile without user.clj on source-path" -hack.
(require '[cljx.repl-middleware :as cljx])
(reset! @#'cljx/cljx-load-rules {:clj cljx.rules/clj-rules})
@@#'cljx/install-cljx-load
Another quick workaround is to comment the source path with user.clj in the project.clj before running cljx, then uncomment it for further compilation steps