bhauman / lein-figwheel

Figwheel builds your ClojureScript code and hot loads it into the browser as you are coding!
Eclipse Public License 1.0
2.88k stars 208 forks source link

Can't get Figwheel 0.4.0 to work with nREPL #244

Closed romstad closed 8 years ago

romstad commented 9 years ago

Hi,

I can't figure out how to make Figwheel 0.4.0 work correctly with nREPL. I'm not entirely sure whether the problem is in Figwheel, piggieback or nREPL, but since everything works great with Figwheel 0.3.9, I suspect that either Figwheel or my own incompetence is to blame.

Anyway, this is what I do:

  1. Create a new project from the Reagent template with lein new reagent myapp.
  2. Edit the project.clj file to add piggieback support, as explained in the piggieback readme.
  3. Run the Figwheel REPL with rlwrap lein figwheel.
  4. Open http://localhost:3449 in my web browser.
  5. Connect to nREPL with lein repl :connect 7002.
  6. (use 'figwheel-sidecar.repl-api)
  7. (cljs-repl)

This initially appears to work, but on closer inspection, it's not perfect. For instance, whenever I add a new definition in the original figwheel REPL or in a source file sent to the browser through figwheel, the nREPL gives an undeclared var warning (but returns the correct value) when I try to use the new definition.

More seriously, println no longer works, even from the original figwheel REPL. When I try to use it, I get the following error:

cljs.user=> (println "?")
Tue Sep 22 15:29:41 CEST 2015 [figwh-httpkit-3] ERROR - handle websocket frame org.httpkit.server.Frame$TextFrame@10642256
java.lang.IllegalStateException: Can't change/establish root binding of: *cljs-compiler-env* with set
    at clojure.lang.Var.set(Var.java:221)
    at cemerick.piggieback$run_cljs_repl$fn__26760.doInvoke(piggieback.clj:184)
    at clojure.lang.RestFn.invoke(RestFn.java:410)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at clojure.core$apply.invoke(core.clj:630)
    at figwheel_sidecar.repl$add_repl_print_callback_BANG_$fn__15932.invoke(repl.clj:68)
    at figwheel_sidecar.core$handle_client_msg.invoke(core.clj:55)
    at figwheel_sidecar.core$setup_file_change_sender$fn__15156.invoke(core.clj:102)
    at org.httpkit.server.AsyncChannel.messageReceived(AsyncChannel.java:166)
    at org.httpkit.server.WSHandler.run(RingHandler.java:140)
    at org.httpkit.server.LinkingRunnable.run(RingHandler.java:120)
    at java.util.concurrent.Executors$RunnableAdaptnil
cljs.user=> er.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
artemyarulin commented 9 years ago

Had the same issue.

First check your ~/.lein/profile.clj. In my case I had some outdated stuff about nrepl there Second more interesting thing - I had to upgrade lein to 2.5.2. With 2.5.1 I always had warning WARNING: unable to load "cemerick.piggieback/wrap-cljs-repl" middleware

Hope it will help. But yeah - having some example project would help many users I guess

bhauman commented 9 years ago

Please try these things one at a time while judiciously cleaning between version changes:

Can you confirm that this isn't a problem in 0.3.9?

Upgrading lein to 2.5.2 may help.

Move you profiles.clj to profiles.clj.bak to test without its influence.

You can also set :repl false in the figwheel server config to not have 2 repls running at once.

Also try adding middleware explicitly according to the README https://github.com/bhauman/lein-figwheel#middleware

Failing all that can you give me a lot more details about your environment.

artemyarulin commented 9 years ago

Hm, I'm still having a poor understanding of all the things related to repl, middlewere and so on.

But here goes minimum project.clj that makes Figwheel 0.4 work + emacs with cider can connect to it :)


(defproject example "0.0.1"
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [org.clojure/clojurescript "1.7.122"]
                 [com.cemerick/piggieback "0.2.1"]]
  :plugins [[lein-cljsbuild "1.1.0"]
            [lein-figwheel "0.4.0"]]
  :source-paths ["src" "tests"]
  :figwheel {:nrepl-port 6700}
  :cljsbuild {:builds {:repl {:figwheel true
                              :source-paths ["src" "tests"]
                              :compiler {:language-in :ecmascript5
                                         :language-out :ecmascript5
                                         :output-to "target/repl.app.js"
                                         :output-dir "target"
                                         :asset-path "../target"
                                         :main ns.app}}}})
romstad commented 9 years ago

Hi Bruce and Artem,

Thanks for your suggestions! Unfortunately, none of them seem to make any difference.

Can you confirm that this isn't a problem in 0.3.9?

Yes.

Upgrading lein to 2.5.2 may help.

I'm on 2.5.2 already.

Move you profiles.clj to profiles.clj.bak to test without its influence.

I did, and I still get the same error.

You can also set :repl false in the figwheel server config to not have 2 repls running at once.

Tried this, the error still appears in the terminal window where I started figwheel.

Also try adding middleware explicitly according to the README https://github.com/bhauman/lein-figwheel#middleware

Makes no difference.

Just to make sure the problem isn't in the Reagent Leiningen template, I just retried all steps in my original message with the Figwheel Leiningen template instead (doing lein new figwheel example in step 1), still without a ~/.lein/profiles.clj file, and still get the same error.

Here is my project.clj file (the only thing I have changed from the Fighweel lein template):

(defproject example "0.1.0-SNAPSHOT"
  :description "FIXME: write this!"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}

  :dependencies [[org.clojure/clojure "1.7.0"]
                 [org.clojure/clojurescript "1.7.122"]
                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]
                 [org.clojure/tools.nrepl "0.2.11"]
                 [com.cemerick/piggieback "0.2.1"]]

  :plugins [[lein-cljsbuild "1.1.0"]
            [lein-figwheel "0.4.0"]]

  :source-paths ["src"]

  :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]

  :cljsbuild {
    :builds [{:id "dev"
              :source-paths ["src"]

              :figwheel { :on-jsload "example.core/on-js-reload" }

              :compiler {:main example.core
                         :asset-path "js/compiled/out"
                         :output-to "resources/public/js/compiled/example.js"
                         :output-dir "resources/public/js/compiled/out"
                         :source-map-timestamp true }}
             {:id "min"
              :source-paths ["src"]
              :compiler {:output-to "resources/public/js/compiled/example.js"
                         :main example.core
                         :optimizations :advanced
                         :pretty-print false}}]}

  :figwheel {
             ;; :http-server-root "public" ;; default and assumes "resources" 
             ;; :server-port 3449 ;; default
             ;; :server-ip "127.0.0.1" 

             :css-dirs ["resources/public/css"] ;; watch and update CSS

             ;; Start an nREPL server into the running figwheel process
             :nrepl-port 7888

             ;; Load piggieback middleware
             :nrepl-middleware ["cemerick.piggieback/wrap-cljs-repl"]

             ;; Server Ring Handler (optional)
             ;; if you want to embed a ring handler into the figwheel http-kit
             ;; server, this is for simple ring servers, if this
             ;; doesn't work for you just run your own server :)
             ;; :ring-handler hello_world.server/handler

             ;; To be able to open files in your editor from the heads up display
             ;; you will need to put a script on your path.
             ;; that script will have to take a file path and a line number
             ;; ie. in  ~/bin/myfile-opener
             ;; #! /bin/sh
             ;; emacsclient -n +$2 $1
             ;;
             ;; :open-file-command "myfile-opener"

             ;; if you want to disable the REPL
             :repl false

             ;; to configure a different figwheel logfile path
             ;; :server-logfile "tmp/logs/figwheel-logfile.log" 
             })

In case you can't reproduce this and nobody else has this problem, don't worry. I'm happy to go back to 0.3.9, which currently does everything I need. Figwheel is awesome.

artemyarulin commented 9 years ago

Pretty weird - I've took your project file and it works like a charm. Most probably something wrong with profiles or lein itself

bhauman commented 9 years ago

Also you are relying on nrepl 2.11. Which came out after figwheel 0.4.0

yatesco commented 9 years ago

If it helps, the following works for me (note, nothing in .lein/profiles):

(defproject pj-health "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [org.clojure/clojurescript "1.7.122"]
                 [org.immutant/web "2.1.0"]
                 [com.cognitect/transit-clj "0.8.281"]
                 [hiccup "1.0.5"]
                 [compojure "1.4.0"]

                 ;; web libs
                 [reagent "0.5.1"]
                 [re-frame "0.4.1"]
                 [com.cognitect/transit-cljs "0.8.225"]]

  :source-paths ["src/clj"]

  :main pj-health.core

  :plugins [[lein-cljsbuild "1.1.0"]
            [lein-figwheel "0.4.0" :exclusions [cider/cider-nrepl]]
            [lein-ancient "0.6.7"]
            [lein-immutant "2.0.0"]]

  ;; Hook so uberjar (called by immutant war) compiles clojurescript
  :hooks [leiningen.cljsbuild]

  :clean-targets ^{:protect false} [:target-path :compile-path "resources/public/compiled"]

  :cljsbuild {:builds
              [{:id           "dev"
                :source-paths ["src/cljs"]
                :figwheel     {:on-jsload "pj-health.core/mount-root"}
                :compiler     {:main pj-health.core
                               :output-to "resources/public/compiled/js/app.js"
                               :output-dir "resources/public/compiled/js/out"
                               :asset-path "compiled/js/out"
                               :source-map-timestamp true}}]}

  :figwheel {:nrepl-port 7888
             ;; Load CIDER, refactor-nrepl and piggieback middleware
             :nrepl-middleware ["cider.nrepl/cider-middleware"
                                "refactor-nrepl.middleware/wrap-refactor"
                                "cemerick.piggieback/wrap-cljs-repl"]}
  :profiles {:dev {:plugins      [[cider/cider-nrepl "0.10.0-SNAPSHOT"]
                                  [refactor-nrepl "1.2.0-SNAPSHOT"]]
                   :dependencies [;; needed for run-dmc
                                  [ring/ring-devel "1.4.0"]
                                  ;; needed for nREPL
                                  [com.cemerick/piggieback "0.2.1"]
                                  [org.clojure/tools.nrepl "0.2.11"]]
                   :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
             :uberjar {:aot       :all
                       :cljsbuild {:source-paths ["src/cljs"]
                                   :compiler     {:main pj-health.core
                                                  :output-to "resources/public/compiled/js/app.js"
                                                  :optimizations :advanced
                                                  :pretty-print false}}}})

This works:

However as soon as I open another REPL (for Clojure for example in a mixed project), and regardless of which order I open the REPLs and regardless of whether I jack-in or connect without fail the clojurescript evaluations go to the Clojure REPL and fail. Closing the Clojure REPL so there is only one ClojureScript REPL resumes the happy place.

romstad commented 9 years ago

Also you are relying on nrepl 2.11. Which came out after figwheel 0.4.0

Thanks! That actually seems to have been the problem. After downgrading to nrepl 0.2.10, everything seems to work. It's still a little mysterious that Colin is apparently able to get things working with nrepl 0.2.11, but anyway, I'm beginning to get convinced that the problem is most likely on my side. Feel free to close this issue.

romstad commented 9 years ago

Correction: It doesn't work with nrepl 0.2.10 after all. I'm not sure what hallucination caused me to believe that it worked when I wrote that -- I get exactly the same errors with 0.2.10 as with 0.2.11.

However, I've now discovered that downgrading to piggieback 0.1.5 does solve the problem. Summarising, the situation is this (with no ~/.lein/profile.clj):

lein-figwheel 0.3.9: Works lein-figwheel 0.4.0 + piggieback 0.1.5: Works lein-figwheel 0.4.0 + piggieback 0.2.1: Doesn't work

Looking back in the git log, it seems that lein-figwheel 0.3.9 and earlier depended on piggieback 0.1.5. It therefore seems likely that the error I see is caused by recent changes in piggieback rather than by recent changes in figwheel. It's still a mystery to me that the combination of figwheel 0.4.0 and piggieback 0.2.1 seems to work for everybody else, but whatever the problem is, it seems that figwheel is not to blame.

bhauman commented 9 years ago

yeah this stuff sucks, I wish folks would just let nREPL cljs stuff go and use the more direct options, at least you can reason about them

On Mon, Sep 28, 2015 at 6:09 AM, Tord Romstad notifications@github.com wrote:

Correction: It doesn't work with nrepl 0.2.10 after all. I'm not sure what hallucination caused me to believe that it worked when I wrote that -- I get exactly the same errors with 0.2.10 as with 0.2.11.

However, I've now discovered that downgrading to piggieback 0.1.5 does solve the problem. Summarising, the situation is this (with no ~/.lein/profile.clj):

lein-figwheel 0.3.9: Works lein-figwheel 0.4.0 + piggieback 0.1.5: Works lein-figwheel 0.4.0 + piggieback 0.2.1: Doesn't work

Looking back in the git log, it seems that lein-figwheel 0.3.9 and earlier depended on piggieback 0.1.5. It therefore seems likely that the error I see is caused by recent changes in piggieback rather than by recent changes in figwheel. It's still a mystery to me that the combination of figwheel 0.4.0 and piggieback 0.2.1 seems to work for everybody else, but whatever the problem is, it seems that figwheel is not to blame.

— Reply to this email directly or view it on GitHub https://github.com/bhauman/lein-figwheel/issues/244#issuecomment-143714175 .

yatesco commented 9 years ago

Hi @bhauman - excuse my ignorance, but are you suggesting we 'consumers' use emacs + cider etc. without nREPL? If so - how would I do that?

Or are you suggesting the library authors don't use the nREPL mechanism?

bhauman commented 9 years ago

@yatesco hey!

I use inf-clojure because is is stable and there are way way way less moving parts.
I can read the code and understand it. The nREPL cider story for ClojureScript is insanely brittle and it seems the folks that use it have a good deal of expertise in making this house of cards work.

There is a page on using inf-clojure in the figwheel wiki. The cider benefits for cljs aren't enough to justify the constant instability.

I would really like to see folks expand inf-clojure's functionality by using the :special-fns feature of the cljs repl. At least this is a path we can reason about.

yatesco commented 9 years ago

I see - thanks for the clarity. I will check out inf-clojure :-).

yogthos commented 9 years ago

I'm seeing the same issue here using the Figwheel nREPL with Cursive. I start the Cljs REPL using the following config:

:figwheel
                  {:http-server-root "public"
                   :server-port 3449
                   :nrepl-port 7002
                   :css-dirs ["resources/public/css"]
                   :ring-handler myapp.handler/app}

then when I connect Cursive to the REPL I run:

(use 'figwheel-sidecar.repl-api)
(cljs-repl)

Everything works perfectly in 0.3.9, and I get the errors with 0.4.0.

bhauman commented 9 years ago

Did you look at the ChangeLog?

On Mon, Oct 5, 2015 at 2:26 PM, Dmitri Sotnikov notifications@github.com wrote:

I'm seeing the same issue here using the Figwheel nREPL with Cursive. I start the Cljs REPL using the following config:

:figwheel {:http-server-root "public" :server-port 3449 :nrepl-port 7002 :css-dirs ["resources/public/css"] :ring-handler myapp.handler/app}

then when I connect Cursive to the REPL I run:

(use 'figwheel-sidecar.repl-api) (cljs-repl)

Everything works perfectly in 0.3.9, and I get the errors with 0.4.0.

— Reply to this email directly or view it on GitHub https://github.com/bhauman/lein-figwheel/issues/244#issuecomment-145622966 .

yogthos commented 9 years ago

Ah ok I tried adding piggieback as a dependency, but missed the :nrepl-middleware flag in figwheel config. Adding that in seems to do the trick thanks.

yogthos commented 9 years ago

Although, I'm noticing a different problem now, the Cursive nREPL seems fine, however the one that starts up in the terminal gets the following error when println is called. This does seem to be piggieback specific though:

cljs.user=> Mon Oct 05 16:22:12 EDT 2015 [figwh-httpkit-1] ERROR - handle websocket frame org.httpkit.server.Frame$TextFrame@3f6186eb
java.lang.IllegalStateException: Can't change/establish root binding of: *cljs-compiler-env* with set
    at clojure.lang.Var.set(Var.java:221)
    at cemerick.piggieback$run_cljs_repl$fn__40570.doInvoke(piggieback.clj:184)

Do you have any tips as to how 0.3.9 used piggieback so that this didn't happen?

yogthos commented 9 years ago

The config I have looks as follows:

   :project/dev  {:dependencies [[ring/ring-mock "0.3.0"]
                                 [ring/ring-devel "1.4.0"]
                                 [pjstadig/humane-test-output "0.7.0"]
                                 [lein-figwheel "0.4.0"]
                                 [com.cemerick/piggieback "0.2.1"]]
                  :plugins [[lein-figwheel "0.4.0"]]
                   :cljsbuild
                   {:builds
                    {:app
                     {:source-paths ["env/dev/cljs"] :compiler {:source-map true}}}} 

                  :figwheel
                  {:http-server-root "public"
                   :server-port 3449
                   :nrepl-port 7002
                   :nrepl-middleware ["cemerick.piggieback/wrap-cljs-repl"]
                   :css-dirs ["resources/public/css"]
                   :ring-handler myapp.handler/app}
...
}
romstad commented 9 years ago

yogthos: Your setup is pretty much exactly the same as mine (Figwheel 0.4.0, nREPL, Cursive, starting from your excellent Reagent Leiningen template), and the error you report is exactly the one I mentioned in my first post. As I mentioned a few posts back, the solution for me ended up being downgrading from piggieback 0.2.1 to 0.1.5.

Do you have any tips as to how 0.3.9 used piggieback so that this didn't happen?

As far as I can see, 0.3.9 used piggieback exactly like 0.4.0, but it used version 0.1.5 (which I guess was the current version at the time).

bhauman commented 9 years ago

@yogthos I was using 0.1.5 before, when you upgrade to 0.2.1 you need to follow the instructions on the piggieback page.

I highly suggest you skip nREPL and Piggieback:

https://github.com/bhauman/lein-figwheel/wiki/Running-figwheel-in-a-Cursive-Clojure-REPL

romstad commented 9 years ago

I highly suggest you skip nREPL and Piggieback:

https://github.com/bhauman/lein-figwheel/wiki/Running-figwheel-in-a-Cursive-Clojure-REPL

Unfortunately, that gives a vastly inferior Cursive REPL experience -- or at least it did the last time I tried (quite a long time ago, there is a chance that Cursive has improved in this respect since then). For the moment, I'll just keep using piggieback 0.1.5, which works just fine for me.

bhauman commented 9 years ago

oh I didn't realize this...

yogthos commented 9 years ago

It does look like figwheel 0.4.0 + piggieback 0.1.5 is the smoothest solution at the moment.

bhauman commented 9 years ago

It would be nice to have these magic version combinations documented for the various REPL setups.

On Oct 5, 2015, at 5:05 PM, Dmitri Sotnikov notifications@github.com wrote:

It does look like figwheel 0.4.0 + piggieback 0.1.5 is the smoothest solution at the moment.

— Reply to this email directly or view it on GitHub.

arichiardi commented 9 years ago

I confirm figwheel 0.4.0 and piggieback 0.1.5 works, with 0.2.1 it goes:

java.lang.IllegalStateException: Can't change/establish root binding of: *cljs-compiler-env* with set
    at clojure.lang.Var.set(Var.java:221)
    at cemerick.piggieback$run_cljs_repl$fn__17232.doInvoke(piggieback.clj:184)
    at clojure.lang.RestFn.invoke(RestFn.java:410)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at clojure.core$apply.invoke(core.clj:630)
    at figwheel_sidecar.repl$add_repl_print_callback_BANG_$fn__12724.invoke(repl.clj:68)
    at figwheel_sidecar.core$handle_client_msg.invoke(core.clj:55)
    at figwheel_sidecar.core$setup_file_change_sender$fn__11948.invoke(core.clj:102)
    at org.httpkit.server.AsyncChannel.messageReceived(AsyncChannel.java:166)
    at org.httpkit.server.WSHandler.run(RingHandler.java:140)
    at org.httpkit.server.LinkingRunnable.run(RingHandler.java:120)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
jbeja commented 9 years ago

Yep, I am having the same issue as everyone, the cljs-repl became useless after connection was establish, thought it doesn't give me any message just doesn't run the code.

geraldodev commented 9 years ago

@romstad

Can you share a project.clj that worked with figwheel nrepl piggieback. I'm asking because I've spent many hours trying without success.

Thanks in advance,

Geraldo

tristanstraub commented 9 years ago

Was getting this error, but not getting this error anymore with these dependencies:

                       [figwheel "0.5.0-SNAPSHOT"]
                       [figwheel-sidecar "0.5.0-SNAPSHOT"]
                       [com.cemerick/piggieback "0.2.2-SNAPSHOT"]

And plugin:

                             [lein-figwheel "0.5.0-SNAPSHOT"]
alexkehayias commented 8 years ago

@tristanstraub can you post a full project file? I was able to get it running, but stacktraces weren't working (class not found) using latest version of cljs.

alexkehayias commented 8 years ago

If it helps anyone else, I was able to get this working using lein-figwheel "0.5.0-1" with the following project file https://github.com/alexkehayias/chocolatier/blob/dev/project.clj

bhauman commented 8 years ago

Please reference this new documentation on using Figwheel and nREPL

https://github.com/bhauman/lein-figwheel/wiki/Using-the-Figwheel-REPL-within-NRepl