Fork me on GitHub
#cider
<
2022-12-15
>
Valentin Mouret15:12:53

Hello 🙂 Initially, I had three different «subprojects» frontend, backend, domain, each with their own deps.edn. I just refactored everything into one project and it works fine if I spawn a REPL for the frontend (shadow) and a REPL for the backend. However, as far as I understand, I should be able to spawn a single REPL for both now, with cider-jack-in-clj&cljs. This opens two windows that both seam to run shadow: 1:

;; ClojureScript REPL type: shadow
;; ClojureScript REPL init form: (do (require '[shadow.cljs.devtools.api :as shadow]) (shadow/watch :app) (shadow/nrepl-select :app))
;;
2:
;;
;; ClojureScript REPL type: shadow
;;
I will put the Emacs messages in the thread. Can someone help me understanding what I did wrong and how to fix it?

Valentin Mouret15:12:18

This is the Emacs message I get:

[nREPL] Starting server via /opt/homebrew/bin/clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.0.0"} cider/cider-nrepl {:mvn/version "0.28.7"} refactor-nrepl/refactor-nrepl {:mvn/version "3.6.0"} cider/piggieback {:mvn/version "0.5.2"}} :aliases {:cider/nrepl {:main-opts ["-m" "nrepl.cmdline" "--middleware" "[refactor-nrepl.middleware/wrap-refactor,cider.nrepl/cider-middleware,cider.piggieback/wrap-cljs-repl]"]}}}' -M:cider/nrepl
[nREPL] server started on 49951
[nREPL] Establishing direct connection to localhost:49951 ...
[nREPL] Direct connection to localhost:49951 established
[nREPL] Establishing direct connection to localhost:49951 ...
[nREPL] Direct connection to localhost:49951 established
Connected! Clojure isn't a language, it's a building material.
error in process filter: user-error: The shadow-cljs ClojureScript REPL is not available.  Please check  for details
error in process filter: The shadow-cljs ClojureScript REPL is not available.  Please check  for details

dpsutton15:12:41

your understanding is half right and half wrong. cider-jack-in-clj&cljs will attempt to use the same process to run two different repls. Since you are using shadow you are using npx shadow-cljs … for one process and presumably clj -A:… for the backend process. You will need to continue to start both processes separately

👍 1
Valentin Mouret15:12:32

That makes sense! Thanks. What is the purpose of cider-jack-in-clj&cljs then?

dpsutton15:12:35

figwheel and figwheel main can be run from a regular clj repl. shadow technically can as well but you have to do a bit more work. But the idea is that if a clj repl can become a cljs repl by just running something like (figwheel/run! <build>) then you can just make two repls into the same process

dpsutton15:12:27

shadow does it’s own startup from its own process. this brings many nice things to the table and thomas has made incredible software. But because it is a separate process, your cljs repl is in one process and the clojure repl in another. So the “trick” of clj&cljs doesn’t work there

dpsutton16:12:03

honestly, cider-jack-in-clj&cljs usually brings more questions and headaches than the purported benefit. I’d be in favor of removing it

Valentin Mouret16:12:49

Thanks so much for the details. :man-bowing: The tooling around Clojure is a bit hard to navigate at times. But when it works it’s great. 🙂

Valentin Mouret16:12:22

Haha, that was already me asking the question back then. 😄

Apple16:12:51

Oh yeah that was you.

Apple16:12:57

I just realize.

Valentin Mouret16:12:15

I am coming from non-lispy languages, so managing a REPL is new world. Writing code to handle «REPL specific» things is not intuitive to me yet. + Clojure + ClojureScript + Emacs + Shadow + … 🤯 So, when I read your suggestion, it’s not evident where/how this should be written or launched.

Valentin Mouret16:12:18

What I understand is that: I would need a file somewhere (cljs?), where I describe the shadow REPL to be created. Then, this would be the target of my shadow «entrypoint»?

dpsutton16:12:36

Yeah. That’s why i’m not a fan of the clj&cljs style. You don’t know where to go and what documentation to read to fix your issues. I added the startup command: info at the top of repls to hopefully demystify how CIDER works

Valentin Mouret16:12:47

It’s not a hard requirement on my side at all. When I discover something new, I don’t want to reinvent the wheel. Conformism isn’t always bad. 🙂

dpsutton16:12:48

because CIDER is just starting your repls the same way you would ever start a repl: clojure -Sdeps '{cider/nrepl <cider-nrepl-dep>}' -M:your:aliases:cider/nrepl . And it is just calling nrepl.cmdline as the main and puts some middleware as an arg to nrepl.cmdline

Valentin Mouret16:12:07

Not sure I get everything you said, but thank you for taking the time. I don’t have a reason to spawn only one REPL besides potential environment simplicity, but to be honest the overhead makes the tradeoff not worth in my opinion. Two REPLs is perfectly fine. 🙂

Apple16:12:21

Not a good writer myself.... Whenever you are ready to revisit this, just put the cider dependency in your dev related lein profile/deps alias, and the clj code in your dev startup code.

Valentin Mouret16:12:24

Now, I am having a funky problem. I run cider-jack-in-clj, and I get a working REPL for my backend. Then, cider-jack-in-cljs, and I get a working REPL for my frontend. Everything looks right. But, when I navigate to a backend file (`.clj`), the buffer is not connected to the Clojure REPL anymore. I navigate to the CLJ REPL buffer, it’s there. I navigate back to the .clj file and it’s connected, but .cljs files are not connected anymore. 🤯

dpsutton16:12:13

CIDER has a bug that it considers itself connected to the last repl you had your point in. So visit the cljs buffer and then cljs files will see it is connected. for clj files, visit the clj repl and it will behave as you like

Valentin Mouret16:12:15

Ok! So, what do people do to work with projects that have Clojure and ClojureScript?

dpsutton16:12:55

exactly what i just said. just have the clojure repl visible and the last repl you touched when doing backend, and similar when working in the frontend

dakra16:12:23

If you use the infamous cider-jack-in-clj&cljs then it works as expected and you don't have to select the clj or cljs repl first. I think there are multiple issues for this already. I commented in one how I solved it with shadow: https://github.com/clojure-emacs/cider/issues/2946#issuecomment-768140666

Valentin Mouret16:12:37

So, if I constantly navigate between cljs and clj, I need to navigate to their respective REPLs in between?

Apple16:12:13

I had the exact problem and asked the question. The solution was to use one shadow repl to support both clj and cljs repl, and use cider-connect-sibling-cljs https://clojurians.slack.com/archives/C099W16KZ/p1667924263389159?thread_ts=1667924045.274949&amp;cid=C099W16KZ

1
Valentin Mouret16:12:14

I am not using jack-in-clj&cljs, I use jack-in-clj and jack-in-cljs.

Valentin Mouret16:12:45

> la boucle est bouclée

dakra16:12:45

I meant if you use jack-in-clj and separately jack-in-cljs you hit that bug that cider gets confused about where to eval. So the solution is to use jack-in-clj&cljs or connect-sibling..

dpsutton16:12:16

ah maybe my info is outdated. sorry about that

Valentin Mouret16:12:29

Ok! So, I will experiment with your solutions to make shadow play nice with Cider.

Valentin Mouret16:12:37

Thank you all for your time and answers. 🙂

Valentin Mouret16:12:06

I will probably be back at some point with annoying questions. 🙂

Apple16:12:35

Two repls are fine. When you have free cycles...

dakra16:12:05

I agree that it's definitely confusing working with shadow and tools.deps in the same session. This area could need a bit more love and documentation 😄

Apple16:12:22

@UFAP0C8KU how to setup to use jack-in-clj&cljs?

dakra16:12:33

As I wrote in that github issue. E.g. my current .dir-locals.el for one of my projects contains this currently:

((clojure-mode . ((cider-clojure-cli-global-options . "-A:dev:cljs")
                  (cider-preferred-build-tool . clojure-cli)
                  (cider-custom-cljs-repl-init-form . "(do (require '[shadow.cljs.devtools.api :as shadow]) (require '[shadow.cljs.devtools.server :as server]) (server/start!) (shadow/watch :app) (shadow/nrepl-select :app))")
                  (cider-default-cljs-repl . custom))))

dakra16:12:30

but then you also need to add shadow.cljs.devtools.server.nrepl/middleware to your nrepl-middlewares

dakra16:12:53

I do that for every project that uses the :cljs alias.

Valentin Mouret16:12:31

I am not 100% clear on what the purpose of the :cljs alias is.

dakra16:12:57

Nothing. That's just an arbitrary deps.edn alias where I specify additional deps etc.

👍 1
dakra16:12:29

But as I always use :cljs alias for my cljs projects I use this to decide if I add the shadow nrepl middleware or not.

Valentin Mouret16:12:16

Yeah, that’s the other part that’s not 100% clear… 😄

dakra16:12:30

cider-jack-in-nrepl-middlewares is a variable that specifies what nrepl middlewares to inject in your session. And for shadow cljs to work it needs "shadow.cljs.devtools.server.nrepl/middleware" added

Valentin Mouret16:12:49

Ok, I am starting to piece things together now.

Valentin Mouret16:12:24

As far as I understand, this middleware will also be in your clj REPL. So, most likely it’s not breaking stuff.

Valentin Mouret16:12:31

(for this clj REPL)

dakra16:12:22

yes, shadow itself runs also on the jvm. (afaik the npx shadowcljs command is just a wrapper around the java stuff)

Apple16:12:59

I feel we are doing essentially the same thing. Difference is that your code goes to .emacs and mine goes to dev startup code.

dakra16:12:04

Probably. I think jack-in-clj&cljs is just a shortcut for jack-in and connect-sibling?!

Valentin Mouret17:12:07

I am getting:

error in process sentinel: nrepl-server-sentinel: Could not start nREPL server: Execution error (FileNotFoundException) at nrepl.cmdline/require-and-resolve (cmdline.clj:220).
Could not locate shadow/cljs/devtools/server/nrepl__init.class, shadow/cljs/devtools/server/nrepl.clj or shadow/cljs/devtools/server/nrepl.cljc on classpath.
I am missing some dependency, but it’s not clear which.

Valentin Mouret17:12:53

I added nrepl/nrepl to both deps.edn and shadow-cljs.edn, but it does not change things.

dakra17:12:18

you need the shadow-cljs dep as well. e.g. thheller/shadow-cljs {:mvn/version "2.20.14"}

Valentin Mouret17:12:01

Thanks! That was not very obvious. But now it looks like it’s working!

Valentin Mouret17:12:12

It’s alive! 👻

Valentin Mouret17:12:09

I am using re-frame’s 10x with preloads inside shadow-cljs.edn. It’s used in my code, so the build actually fails. Is it something I should add to the (do (require '[shadow.cljs.devtools.api :as shadow]) (shadow/watch :app) (shadow/nrepl-select :app))?

dakra17:12:45

I think you have to set more.. see my dir-locals from above. e.g. (cider-custom-cljs-repl-init-form . "(do (require '[shadow.cljs.devtools.api :as shadow]) (require '[shadow.cljs.devtools.server :as server]) (server/start!) (shadow/watch :app) (shadow/nrepl-select :app))") and (cider-default-cljs-repl . custom)

Valentin Mouret17:12:46

Ah so. I’ll give it a shot. Thanks.

Valentin Mouret17:12:19

Yeah, that’s already what I had.

Valentin Mouret17:12:14

Probably this is not handling «preloads» from shadow, which are loading re-frame 10x.

Valentin Mouret17:12:02

boy, this is getting out of hands

dakra17:12:33

hehe. surely not simple and straight forward 😕

dakra17:12:29

how does the build fail?

Valentin Mouret17:12:00

[:app] Compiling ...
[:app] Build failure:
The required namespace "day8.re-frame-10x.preload" is not available.

dakra17:12:30

is re-frame-10x in your classpath / deps?

Valentin Mouret17:12:49

I had dependencies in shadow-cljs.edn and I think I need to move them all to deps.edn now.

dakra17:12:19

If you have all deps in deps.edn (like I have) then another gotcha might be that I had to explicitly specify guava dependency, otherwise shadow 2.20.11+ crashed for me. Took me also a while to figure out. So currently I have this for shadow in my deps.edn:

:cljs     {:extra-deps {com.cognitect/transit-cljs  {:mvn/version "0.8.280"}
                          day8.re-frame/http-fx-alpha {:mvn/version "0.0.2"}
                          day8.re-frame/tracing       {:mvn/version "0.6.2"}
                          re-frame/re-frame           {:mvn/version "1.3.0"}

                          thheller/shadow-cljs {:mvn/version "2.20.14"}
                          ;; Maybe explicitly add deps for shadow.
                          ;; For more info why this is needed
                          ;; See 
                          ;; You can check what deps are needed on
                          ;; 
                          ;; And maybe use 
                          ;; as a template and experiment what's missing/wrong.

                          ;; Since 2.20.11 guava is not explicitly required by
                          ;; shadowcljs anymore but apparently it's still needed
                          ;; because it doesn't start without this pinned version.
                          com.google.guava/guava {:mvn/version "31.0.1-jre"}
                          }}
  :cljs-dev {:extra-deps {binaryage/devtools         {:mvn/version "1.0.6"}
                          com.lambdaisland/dom-types {:mvn/version "0.5.37"}
                          day8.re-frame/re-frame-10x {:mvn/version "1.5.0"}}}

Valentin Mouret17:12:38

Now I understand the cljs namespace. 🙂 Thanks for this. I stumbled upon this new YouTube series of people showing their REPLs. Looks like a missing piece of the puzzle indeed.

Valentin Mouret17:12:04

Thank you so much for your time! Now everything works perfectly and I have a working setup!

dakra17:12:12

No problem. Great it's working:)