BetterThanTomorrow / calva

Clojure & ClojureScript Interactive Programming for VS Code
https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva
Other
1.58k stars 212 forks source link

Cannot jack-in to deps.edn + shadow-cljs project #1307

Open eerohele opened 2 years ago

eerohele commented 2 years ago

Steps to reproduce

  1. Have a project with deps.edn and shadow-cljs.

  2. Have .nrepl.edn in project root with this content:

    {:middleware [shadow.cljs.devtools.server.nrepl/middleware]}
  3. In a terminal, start shadow-cljs watch:

    npx shadow-cljs watch :app
  4. In Calva, Run Start a project REPL and Connect.

  5. Choose any deps.edn aliases.

  6. Choose the shadow-cljs build ID whose watch you started (:app).

Expected result

Can jack in.

Actual result

Get this error:

Failed starting cljs repl for build: :app. Is the build running and connected? See the Output channel "Calva Connection Log" for any hints on what went wrong.

Additional information

No combination of custom connect sequences I attempted worked. Some yielded different errors.

Root cause?

Here's the jack in invocation Calva uses:

clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,"0.8.3"},cider/cider-nrepl {:mvn/version,"0.26.0"}}}' -A:dev -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"

nREPL should pick up the shadow-cljs middleware from .nrepl.edn, but maybe the ---middleware setting overrides the middleware definition in .nrepl.edn? Not sure.

Workaround

  1. In the terminal, run:

    clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version,"0.8.3"},cider/cider-nrepl {:mvn/version,"0.26.0"}}}' -A:dev -m nrepl.cmdline --middleware "[shadow.cljs.devtools.server.nrepl/middleware cider.nrepl/cider-middleware]"
  2. In Calva, add a custom connect sequence like this (startCode):

    {
        "name": "App",
        "dependsOn": "User provided",
        "projectType": "deps.edn",
        "cljsType": {
            "startCode": "(shadow.cljs.devtools.server/start!)",
            "connectCode": "(shadow.cljs.devtools.api/nrepl-select :app)"
        }
    }
  3. In Calva, run Connect to a REPL server in project.

  4. Choose "App" project type.

Only adding the shadow-cljs middleware into the middleware list doesn't work. If you try to start the shadow-cljs server/watch via npx and then connect, there's an error like this in the REPL view:

shadow-cljs has not been started yet!
In embedded mode you need to call (shadow.cljs.devtools.server/start!) to start it.
If you have a shadow-cljs server or watch running then you are not connected to that process.

Even though the server/watch is actually running.

PEZ commented 2 years ago
  1. Have .nrepl.edn in project root with this content

I was unaware of this way to configure nREPL.

eerohele commented 2 years ago

There's some documentation on it here on the nREPL web site.

eerohele commented 2 years ago

Also, I noticed that the documentation explicitly states that CLI options override config file keys. Well, that's a bummer.

bpringe commented 2 years ago

Maybe Calva could check for that .nrepl.edn file, and if it exists, add the middleware from that config to what Calva wants to inject. It could be a naive solution, but I don't initially see it causing any major problems.

I'm not sure what Calva currently does during jack-in and connect with this jack-in profile without looking at the code, but it could/should also call the startCode and connectCode from the repl connect sequence above. It seems that would make this scenario work, unless I'm missing something.

PEZ commented 2 years ago

This is probably not the same problem, but I paste it here so that we get a more complete view of this whole shenanigan.

cider-jack-in-cljs clojure fails on shadow-cljs+deps.edn with "missing instance"

orestis commented 2 years ago

This also looks like a duplicate or at least with the similar root cause as https://github.com/BetterThanTomorrow/calva/issues/1285. One issue being, that the shadow-cljs CLJS repl needs some more nRepl middleware (piggyback and shadow's own middleware).

In an ideal world, Calva would use the dynamic middleware facility so that all jack-in commands start a plain nRepl session and then Calva would add needed middleware as needed. See https://lambdaisland.com/blog/2021-11-24-making-nrepl-cider-more-dynamic-2 for an example. The issue of actually having the dependencies on the classpath via sideloading (#1451) is related but also orthogonal to this, as since Calva is responsible for starting Clojure, it can pass in the deps as needed.