Understanding jack-in in Calva

(I accidentally deleted my original post - posting again)

I’m using Cursive for the moment but would like to try out Calva. I’m just getting started but I am not grasping how the jack-in REPL is supposed to work. I have a Leiningen project that includes an nREPL running on port 3000. I also use nREPL in production because I have a legacy application running in PHP that queries the Clojure app through the nREPL.

When I open IntelliJ/Cursive, this my workflow

  1. Run lein run on the terminal
  2. Run shadow-cljs watch app on the terminal
  3. Open an nREPL window in IntelliJ that connects to port 3000
  4. Open another nREPL that connects to the port file specified by shadow-cljs.

Would I use the same workflow in Calva? In Calva it his highly recommended to use jack-in instead of connecting to a running REPL. I’m not sure I grasp the difference? I would be extremely grateful for an explanation. :slight_smile:

1 Like

jack-in will just start an nRepl for you.

The only reason it is recommended, is that Calva needs some additional nRepl middlewares to be injected as dependencies when you start your nRepl for all the features to work, jack-in will do that for you automatically.

If you start the nRepl yourself, you’ll need to make sure you do so with the correct added dependencies for Calva to work fully.

1 Like

Thanks @didibus. So on this case I need to have a nREPL server running on port 3000 so my PHP application can communicate with my app. But I guess that I could also jack-in to another nREPL in Calva? How would I do that? If I just type lein run to start my app, then it will just be my “normal” nREPL running.

Hi there!

Jack-in is a bit of an unfortunate name… :grinning: . Basically there are two options:

  1. You start the REPL, and you connect to that REPL. What @didibus said applies: Here you are responsible for meeting Calva’s dependencies requirements.
  2. Calva starts the REPL and connects it. Calva will injects the dependencies it needs. (This is Jack-in)

Jack-in does not cover as many project setups as Connect does. The recommendation is intended to be more like: If your setup allows jack-in, then consider using it. If not, then regular connect is what you need to use.

There is a Calva command for copying the command line Jack-in would use to the clipboard. It can be used to modify the command line you use to start the REPL yourself. Or to inform you about what dependencies Calva has so that you can configure your project.

I’m not sure I understand the setup with your PHP app… That step 1 in your workflow, it is starting a dev version of your server, right? I don’t see when you are connecting to it. If you are not connecting to it, then you should be able to use a similar workflow with Calva. You probably need to us VS Code Workspaces to be able to open the same project in different windows. See Workspace Layouts - Calva User Guide for some info on this.

Using Jack-in:

  1. lein run (I would use the VS Code integrated terminal, it is pretty awesome)
  2. In one VS Code workspace. Jack-in, selecting the shadow-cljs project type, selecting to start and connect the the :app build.
  3. In another VS Code workspace. Connect to nREPL post 3000

I’ve tried to describe the Jack-in mechanism here: The Jack-in Academy - Calva User Guide

Using connect:

  1. lein run
  2. shadow-cljs -d cider/cider-nrepl:0.27.4 watch app (Again. I’d choose the VS Code terminal)
  3. In one VS Code workspace. Connect, selecting the shadow-cljs project type, selecting connect the the :app build.
  4. In another VS Code workspace. Connect to nREPL post 3000

(The reason you need two VS Code windows is that Calva only can handle one project session per window. Since in your case the Clojure REPL and the ClojureScript REPL are not in the same process, it gets to be two separate sessions from Calva’s perspective.)

You can configure things so that shadow-cljs uses Leingen to start the the REPL and skip the lein run step there. See the Leiningen build tools section here: Shadow CLJS User’s Guide

Here’s the current command line that Calva uses for a Leingingen project with a :dev profile, btw:

lein update-in :dependencies conj '[nrepl,"0.9.0"]' -- update-in :plugins conj '[cider/cider-nrepl,"0.27.4"]' -- update-in '[:repl-options,:nrepl-middleware]' conj '["cider.nrepl/cider-middleware"]' -- with-profile +dev repl :headless

I hope this helps some. Please don’t hesitate to keep asking until you have your workflow working well in Calva.

2 Likes

Thanks @PEZ ! The Jack-in Academy was very helpful, you have really made a great job to allow different configurations for the jack-in. However, I am afraid that I still don’t fully grasp exactly what’s going on…

…so I will take you up on that offer :smiley:

I think we can ignore the PHP aspect of it. PHP is running on a separate apache server and only needs to be able to connect to a running nREPL in the app, on port 3000. That nREPL is started when I type lein run but I don’t necessarily need to connect to it myself in development. Does that make the two VS-code windows unnecessary or do still I need them to be able to open both CLJ and CLJS REPLs?

I followed these steps

It almost works. After step 1 the app is up and running and PHP can connect to it. After step 2, the terminal outputs
nREPL server started on port 50450 on host 127.0.0.1 - nrepl://127.0.0.1:50450

and prompts me to select shadow-cljs build, which I do. But then I get 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. I guess that in step 1, I also need to run shadow-cljs watch app and open a browser window? I tried that and shadow-cljs is running, but I still get the same error message Failed starting cljs repl for... So there is something that I am missing here.

(I skipped step 3 because I think that has to do with the PHP-thingy?)

Another thing I don’t grasp is if the jack-in creates another JVM process? When I type lein run, the app starts and it starts the web server, connects to the db, opens the nREPL for PHP to connect to, etc… Then when I do the jack-in, does that start another JVM process for the app and open a REPL into that? Meaning that if a http request to the app (started by lein run) modifies an atom, that change would only be visible if I connect to the nREPL running on port 3000, while the jack-in is connected to another another JVM process, and the change will not have happened there?

As you see there are a few things that I am not getting… :slight_smile:

1 Like

Hello again @DrLjotsson, glad you took me up on the offer!

Actually, no, Calva should start the watcher for you. But it looks like it fails. I don’t know why, but maybe you should use the non-jack-in way here. It’ll give you more control over what happens.

You seem to grasp it. :smile: Yes, jack-in will start a completely separate REPL. Now I understand your PHP app setup better (even if not fully). If you want to stick with Jack-in you would then skip the lein run step and connect your PHP app to the REPL that Calva starts. But, again, I think we might be outside what jack-in was designed to support, I suggest using the you-start-the-repl-and-connect-calva-to-it option instead.

  1. lein run (assuming project.clj configures versions of cider-nrepl etcetera that are compatible with Calva. Consider version 0.9.0 of nrepl, and 0.27.4 of cider-nrepl)
  2. In one VS Code workspace connect Calva to nREPL on port 3000.
  3. shadow-cljs -d cider/cider-nrepl:0.27.4 watch app
  4. In another VS Code workspace. Connect Calva, selecting the shadow-cljs project type, on whatever nREPL port that shadow-cljs started, selecting connect the :app build.

As you see you will still need to use two VS Code windows. This is a limitation in Calva. Can be avoided by configuring shadow-cljs to use Leiningen for dependencies and use shadow-cljs to start both the Clojure and ClojureScript REPLs. But maybe that is an exercise for another time.

Thanks @PEZ !!

1 Like

You are entirely welcome, @DrLjotsson!

For everyone else’s information. The project was setup so that shadow-cljs is letting Leiningen take care of dependencies and starting the REPL (:lein true). For @DrLjotsson’s project it meant he can jack-in using the shadow-cljs project type and get both the Clojure and ClojureScript parts of the solution running in the same VS Code/Calva window.

I think that what stopped it from working using the Leiningen project type + shadow-cljs is that the project was lacking shadow-cljs dependencies and Calva just assumes they are provided. I think Calva can improve here, at least via better documentation. I’ve created an issue to track this here:

1 Like

Thanks @PEZ !

I’m also not that familiar with the inner workings of Clojure apps. So one thing that confused me was that after the jack-in, the app was not “started” (i.e., I couldn’t access it through my browser). While lein run automatically calls my -main function, I needed to manually call the function that -main calls after jack-in, to get my webserver running, open database connections etc. But maybe 99% of Clojure users understand that :slight_smile:

1 Like

That’s very good information. You can configure Jack-in to call this function for you, but I think the problem rather is to realize that it doesn’t happen automatically.

1 Like