Undoubtedly one of the major advantages of using Clojure (and Lisps in general) is that
and REPLs make it trivial for editors to evaluate code that is present in an editor buffer.
Experiencing the interactive workflow that results from being able to evaluate Clojure expressions that are present in your editor's buffer frame is enlightening. When you have this ability to quickly verify behavior without the ceremony of restarting an application, you will start to move forward with more confidence. You have the ability to check that a function works against glaring edge cases in seconds. This allows you to think more clearly about what your code is actually doing, and more clearly about what you actually need.
Many editors provide support for evaluating ClojureScript code via a REPL connection, however the process for setting this up can seem complex, mysterious and convoluted.
Why does this complexity exist? The main reason that there is complexity in connecting a ClojureScript REPL to your editor is that the environment is just well ... complex.
The typical path of code that will ultimately evaluated in a Browser and eventually returned to an editor.
nREPL server - Clojure remote REPL network interface
Piggieback nREPL Middleware - re-directs nREPL evals to ClojureScript Compiler
... and back through all the layers
The main problem here is that a lot more is going on. When we evaluate Clojure remotely the message just needs to travel to the Clojure runtime and back. When we are using ClojureScript the code has to travel to Compiler and then to the browser and back.
Because of this complexity it is best if we start and understand the pieces. In practice you will not often have to set these up yourself but things can become very confusing very quickly if you don't understand what they are.
nREPL is server that implements a protocol that supports evaluating Clojure code remotely.
It is common for Clojure developers to start an nREPL server inside an application that is running on a remote server so they can interactively debug particularly thorny problems.
nREPL provides the server endpoint that most editors integrations talk to when they want to evaluate Clojure/ClojureScript code.
The simplest way to explain how nREPL works is that it understands a set of messages. The most important one for our purposes is the
:eval message that includes a
nREPL is extensible via middleware that can receive and handle these messages.
Piggieback is nREPL middleware that intercepts
:eval messages and re-directs them to a ClojureScript REPL for evaluation. So Piggieback is an extension of nREPL and we have to extend nREPL because it knows nothing about ClojureScript.
Their are two main parts to using Piggieback. First it has to be inserted into the middleware of the nREPL server that you are going to be using. Second, you have to start your ClojureScript REPL with a call
cider.piggieback/cljs-repl. You have to start your REPL this way so that it can do the bookkeeping necessary to re-direct
:eval messages to the ClojureScript REPL.
The ClojureScript REPL is written in Clojure and is what allows us to evaluate ClojureScript code in the first place.
You can run a ClojureScript REPL locally and this is what happens when you run
clojure -m figwheel.main -b dev -r. This is pretty simple to accomplish. However, it is when you wan to run it remotely over nREPL that things get more difficult.
Almost all editor integrations in the ClojureScript ecosystem can utilize nREPL for communication. This is why understanding it and its role as a REPL server is important.
There are other ways for editors to connect to Clojure remotely but currently nREPL integrations tend to provide the most editor functionality (i.e. documentation, auto-complete, jump to definition). You can opt to connect to a REPL by another means but the nREPL integrations are by far the most used.
A traditional way for editors to communicate with a REPL is to pipe forms (Clojure expressions in this case), to the STDIN of the REPL and capture the STDOUT as a response. This form of communication is much simpler.
Currently both Emacs and Cursive support this type of communication. Emacs has its inf-clojure. Cursive has particularly good support for this type of REPL communication when you create a
There are two major ClojureScript editor integrations, CIDER for Emacs and Cursive for IntelliJ.
Don't worry if neither of those are your favorite editors as there are many other integrations out there. But you should know that CIDER and Cursive account for a whopping 80% of Clojure editor use and this is not by accident as both CIDER and Cursive are both under intense active development.
10% of Clojurists use Vim Fireplace. The Vim support for Clojure/Script is nowhere near as extensive as the previous two, I'll chalk its high rate of adoption up to the sheer popularity of Vi among the hacker crowd.
Atom, VSCode and Sublime Text all have support for evaluating ClojureScript code from your editor as well.
I know that Emacs is the other text editor but I highly recommend that Vi users use Emacs with
evil-mode, many Clojurists who are come from a Vi background have switched and are happy about it. The main reason is that Emacs Clojure integration via CIDER is heads and shoulders above the currently available Vi integration.
See this blog post for an experience report on switching to Emacs.