lynaghk / cljx

Write a portable codebase targeting Clojure/ClojureScript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stop requiring precompilation for REPL-ing

cemerick opened this issue · comments

The REPL middleware works well, but it doesn't help when you load a file or evaluate an expression that requires some other namespace that:

  1. Is defined in a .cljx file, and
  2. Has not already been precompiled into Clojure/ClojureScript already.

The REPL middleware needs to intercept load calls so that e.g. (require 'foo) will look for a foo.cljx resource on the classpath, cljx it to Clojure/ClojureScript based on the prevailing rules, and then invoke the regular file-loading mechanism for the type of REPL session in progress. Of course, if a .cljx file isn't available, the normal loading mechanism should apply.

Done pervasively/properly, this should make cljx precompilation entirely unnecessary except when cutting a jar/war/other distributable.

Should note that the workaround right now, if you're in a REPL and there's an ns dependency that hasn't been precompiled that you need, you can just open it in a buffer/window/whatever, and load it. This can mean manually walking down the require dep graph, which sucks…thus the appeal of making this "fix" happen.

Just for the sake of completion, when you say "open it .... and load it." do you mean the cljx file or the cljs/clj file?

Assuming you're using nREPL and the cljx middleware, I mean the cljx file. If you're not doing both, then the only way to load the code produced from cljx files is to run lein cljx, and then (require ...) the generated files from disk.

Halfway there. When you have the cljx nREPL middleware installed, it monkey-patches clojure.core/load to find, transform, and load .cljx files matching namespaces named in e.g. require and use forms in preference to any .clj files. This means you don't have to run lein cljx once before doing your Clojure REPL-ing, even if you're going to be loading .cljx-implemented namespaces (transitively or not).

Next step: same support for ClojureScript.

(BTW, "monkey-patching clojure.core/load" is a lot less scary than it sounds. load hasn't materially changed in > 4 years, so cljx swapping in its own implementation [which is 90% the same as clojure.core's] is very low-risk. That said, please report any breakage you find, and I'll get on it! :-) )

(Notes for my benefit)

ClojureScript compiler changes TODO (all in closure):

  • factor out ns->cp so it can be patched too (to return a Compilable
  • generalize cljs-deps so it passes Compilables on untouched

OK, this now works for ClojureScript, too, and it ended up not requiring any compiler changes there. This is available in [com.keminglabs/cljx "0.3.3-SNAPSHOT"].

Clojurescript cljx REPLing doesn't work here:

> lein repl
nREPL server started on port 50204 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
To start Austin, type: (cemerick.piggieback/cljs-repl :repl-env (cemerick.austin/exec-env))
Type (refresh) to reload all namespaces.
user=> (cemerick.piggieback/cljs-repl :repl-env (cemerick.austin/exec-env))
Browser-REPL ready @ http://localhost:50323/9580/repl/start
Type `:cljs/quit` to stop the ClojureScript REPL
nil
cljs.user=> (require 'namban.boeki)
"Error evaluating:" (require (quote namban.boeki)) :as ".require.call(null,new cljs.core.Symbol(null,\"namban.boeki\",\"namban.boeki\",-2013049770,null));\n"
#<SyntaxError: Parse error>
No stacktrace available.
nil

The project.clj.
Clojure cljx REPLing works though.

lein deps :tree suggested me to include [com.keminglabs/cljx "0.3.3-20140218.213435-1" :exclusions [org.clojure/clojure]] in project.clj but it's still not working and nothing changed in lein deps :tree.

Perhaps you used a different REPL environment to test that feature or something?

There is no require function in ClojureScript. You need to use either an ns form, or e.g. (load-namespace 'namban.boeki).

Yes, I also noticed that embarrassing fact some minutes ago :)