Clojurescript REPL with Cider

Hi, I’m a ClojureScript beginner.

I am trying to start a ClojureScript project and connect to it with Emacs and Cider, using cider-connect. I am having a hard time to put together all the pieces to get that done.

I have been following Andrew Meredith’s book “Learn ClojureScript”. It briefly covers Figwheel, but it’s not really the development cycle I am looking for; this one is more about changing and saving a whole file to see the results, as Figwheel detects changes in the file.

Instead, I would prefer a REPL-based development cycle:

  1. Start a ClojureScript session
  2. The web browser is launched pointing at localhost
  3. I connect my Emacs instance to the ClojureScript session with cider-connect
  4. I eval a piece of ClojureScript code in the text editor
  5. The results happen in the browser

How can I achieve this development cycle with ClojureScript and Emacs?

That is what Figwheel lets you do. It connects you to a REPL running inside the browser. It will also re-eval changes to your files, but that’s for your resources, like say you change an HTML file, or the CSS files.

I am looking for a mix of Cider and Figwheel.

If I follow the instructions on figwheel.org, I’ll type clj -m figwheel.main, and soon I have a browser window running a piece of ClojureScript code; if I change the source file, figwheel kicks in and after half a second, the change is reflected on the web page.

On the other hand, if I run cider-jack-in-cljs in Emacs, Emacs will start a clojure process and a Cider session; I can evaluate small snippets of ClojureScript code, but I do not have a web page that I can see results on.

So, how can I get the best of both worlds? I am looking for a REPL so that I can manipulate a web page by evaluating snippets of code, from my text editor.

When you run cider-jack-in-cljs or cider-jack-in-clj&cljs, cider will ask you for the ClojureScript REPL type, looks like this:

Here you should select figwheel-main.

Provided you have set your figwheel configuration up and your Cider configuration, that really should get you to what you are after.

You say “Emacs will start a clojure process and a Cider session; I can evaluate small snippets of ClojureScript code”. This means that you should be in a ClojureScript/figwheel REPL. Does the prompt that you see start off as user>, then a little while later change to cljs.user>? If so, the REPL part at least is working. The question then becomes why isn’t the browser page opening?

To diagnose this, figwheel provides a startup message with some help and right at the end, just before the prompt and above the line which says To quit, type: :cljs/quit , you should see something like:

Opening URL http://localhost:9510/myapps.html
Do you have this line or not?

There may be something helpful in the startup message, and you can even post here. (You can use the Settings gear on the right of the editing tools and select Hide Details, and post the contents in there.) This can help us to better diagnose it.

Success, it works.

Within emacs, cider-jack-in-cljs using figwheel-main does start both a browser session on port 9500 and a REPL session on some port above 50000.

The prompt does change from user> to cljs.user> after a few seconds.

Thanks everyone for the pointers.

This is proving hard. I am having a hard time to find consistent documentation that touches all these components.

As a beginner myself, I find tooling challenging because there isn’t a one-size-fits-all approach, everyone seems to figure out their own setup, and tooling changes over time.

I spent a few hours trying to figure out the easiest way to create a ClojureScript app with Figwheel and Reagent, and settled on…

Create the app with lein new figwheel-main foobar -- --reagent

Then I open the src/foobar/core.cljs file in emacs (Spacemacs) and run cider-jack-in-cljs, selecting figwheel-main, then dev.

That pops open the browser. When I save changes, figwheel updates the browser. I haven’t figured out how to make it update when I change a Reagent component and cider-eval-defun-at-point. It only seems to work on save.

I also add a comment to the bottom of src/foobar/core.cljs that allows me to mess with application state while the app is running without reloading the page. When I cider-eval-sexp-at-point on any of those forms, the browser is updated immediately.

(comment
  (swap! app-state update-in [:text] #(str % " echo"))
  (reset! app-state initial-state)
  )

:+1:

Yes as a beginner the hardest thing I had to work out was not the language itself but how all these various tools (leiningen, nREPL, figwheel, emacs + cider) talk to each other.

figwheel-main now has excellent documentation at figwheel.org which I’m sure is what you’ve been looking at.

CIDER also has excellent documentation, which can be found at: https://docs.cider.mx/. There is a section dedicated to ClojureScript setup, well worth the time to read through this to try to understand it all. If you persist, you’ll get there in the end and it’s well worth your time and effort.

I have one really useful pointer which I only discovered recently: sometimes, especially when you have a large source file, you need to cider-load-buffer (C-c C-k) before doing a cider-eval-last-sexp (C-c C-e). In fact, as a rule of thumb I do that whenever I open a script containing any code I want to evaluate in the REPL, especially a large one, otherwise it can tend to hand. This also evaluates all symbols in the script and makes them available in the REPL.

That is correct behaviour. figwheel hot reloading only detects changes to files, and that too only files within paths you specify in your configuration, I think through :source-paths and/or :watch-dirs options.

You will need to re-render your app. Figwheel calls a function in your app to do this, after it has reloaded the code in the changed files. If you modify the state of the app without saving the files, Figwheel knows nothing about it. Which is why you need to call that same function yourself. I bind that call to a keyboard shortcut so that I can call it at will from wherever.

1 Like