Setting integrated development environments for ClojureScript
Now that we've got the basic lay of the land, we can now focus on configuring a proper Integrated Development Environment. We'll also discuss how we can make it ClojureScript-aware using the REPLs we've covered so far.
In doing so, we strive to profit from the many ways IDEs can assist us. IDEs are powerful tools, exposing functionalities such as code completion, syntax highlighting, program structure introspection, and navigation.
We'll focus on Emacs, its Clojure development environment, CIDER, as well as another simpler package, inf-clojure
. The reason why we chose these Emacs-based tools is that they are the most used IDEs for most Clojurists, and are actively maintained by a vibrant community of open source enthusiasts.
Working on Emacs with Piggieback and Weasel on CIDER
CIDER, or the Clojure Interactive Development Environment that Rocks for Emacs ( https://github.com/clojure-emacs/cider ), is an open source Emacs Library for working with Clojure on Emacs. Originally called nrepl.el, it is stable, feature-rich, and an active project that is highly beneficial to Clojure and ClojureScript developers.
If you're going to use CIDER, its authors have stated that they expect ClojureScript developers to use Piggieback and Weasel as their default toolkit.
Let's assume that you can launch a Piggieback/Weasel-enabled nREPL session for your ClojureScript project (refer to the Live-coding ClojureScript on top of nREPL with PiggieBack and Weasel section). We'll now focus on how CIDER empowers you to develop ClojureScript with Emacs.
Installing CIDER
Installing Cider is a matter of getting the relevant library from package.el
(using MELPA, MELPA Stable, or Marmalade repositories) and issuing the following command (in Emacs):
M-x package-install [RET] cider [RET]
Alternatively, add the following lines to your Emacs configuration file:
(unless (package-installed-p 'cider) (package-install 'cider))
You'll also need to hook up the CIDER middleware into our nREPL. To do this, add the following to the :user
section in your ~/.lein/profiles.clj
file:
:plugins [[cider/cider-nrepl "x.y.z"]]
We haven't spoken about Leiningen profiles too much prior to now. To learn more about how the profiles.clj
file works, check out the Leiningen documentation at https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md#declaring-profiles. Take care, the "x.y.z"
version number in cider-nrepl
must match the CIDER version, otherwise you'll get a warning when trying to connect to a project's REPL.
Working with Clojure and ClojureScript REPLs on CIDER
At this point, you're free to tweak CIDER's configuration to add features like different autocompletion providers or syntax-highlighting behavior. Whether you choose to or not, you should have everything you need to get CIDER up and running at this point.
Once you have installed CIDER and its nREPL middleware, you can open a Clojure file (even an empty buffer to experiment in), launch an REPL on it and begin to work interactively. Most Clojure developers go back and forth between editing and sending code to the REPL for evaluation. To launch a Clojure nREPL session from Emacs use the following command:
M-x cider-jack-in
Now, how can we get this set up to work with ClojureScript? Let's go back to our piggieback_project
from earlier in this chapter and get CIDER working for it.
First, we'll need to tell CIDER which ClojureScript evaluation environment we are going to use. CIDER defaults to Rhino, so for our case we'll need to tell CIDER to use Weasel. Customize the cider-cljs-repl
file to set it to Weasel:
M-x customize-variable RET cider-cljs-repl RET Weasel RET
Make certain that your ClojureScript file contains the following connection code:
(ns piggieback-project.core (:require [weasel.repl :as repl])) (when-not (repl/alive?) (repl/connect "ws://localhost:9001"))
Tip
Make sure that this ClojureScript code has been successfully compiled at least once. Otherwise, we won't be able to load the websocket client.
Next, we'll use the lein-cljsbuild
package. To activate this plugin make sure that your project.clj
file looks as follows:
(defproject piggieback_project "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :plugins [[lein-cljsbuild "1.1.0"]] :cljsbuild { :builds [{:source-paths ["src"] :compiler {:main piggieback-project.core :output-to "out/main.js" :output-dir "out" :optimizations :none}}]} :dependencies [[org.clojure/clojure "1.7.0"] [org.clojure/clojurescript "1.7.122"] [weasel "0.7.0" :exclusions [org.clojure/clojurescript]]] :profiles {:dev {:dependencies [[com.cemerick/piggieback "0.2.1"] [org.clojure/tools.nrepl "0.2.10"]] :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}})
Now we'll build the code responsible for creating the connection. While in the project directory, type the following:
lein cljsbuild once
Now open any ClojureScript file in Emacs, and launch the nREPL session with:
M-x cider-jack-in-clojurescript
You'll see two REPLs, one for Clojure and the other for ClojureScript. The ClojureScript REPL should notify you that it is waiting for the client to connect.
Connect your browser to the Weasel session by opening greet.html
. You should get the following screen in Emacs:
Now, switch to the window containing the Clojure REPL and set it to show the buffer containing your test.cljs
ClojureScript file.
Load the content of the file in your REPL using the following Emacs command:
C-c C-k
Then, set the namespace of the REPL to be the one declared by the current source file:
C-c M-n
Switch now to your ClojureScript REPL:
C-c C-z
Start typing the name of the function. You'll notice that code completion should be working. In the minibuffer, Emacs should also help you with the signature of your function.
Now let's evaluate some ClojureScript in our REPL:
piggieback-project.test> (defn test-fn [your-name] (js/alert (+ "hello " your-name))) piggieback-project.test> (test-fn "Rafik")
And a popup should happily greet you from your connected browser.
Working on Emacs with Figwheel and inf-clojure
In order to use Figwheel with Emacs, we'll need to use inf-clojure
, an Emacs package offering basic interaction with a running Clojure subprocess. In conjunction with clojure-mode, this setup will make sure that we benefit from static code analysis features. inf-clojure
is not as feature rich as CIDER, which is worth keeping in mind. It is nevertheless, able to load files, switch namespaces, evaluate expressions, show documentation and source of symbols, and do macro-expansion.
Installing inf-clojure
Type the following in your Emacs:
M-x package-install [RET] inf-clojure [RET]
You may also want to add the following snippet to your Emacs configuration file:
(unless (package-installed-p 'inf-clojure) (package-install 'inf-clojure))
To enable inf-clojure
whenever you visit a Clojure or ClojureScript file, add the following to your Emacs configuration file:
(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode)
Configuring inf-clojure to run Figwheel as a Clojure subprocess
In order for Emacs to know that we want to use Figwheel as our REPL environment, we'll need to configure it explicitly. To do this, add the following to your Emacs configuration file (usually ~/.emacs
):
(defun figwheel-repl () (interactive) (run-clojure "lein figwheel"))
Restart Emacs or re-evaluate the the configuration file buffer for the modifications to take effect. Next, let's open a file in the source directory of the figwheel_project
we've set up for the browser, say core.cljs
, and launch the ClojureScript powered inf-clojure
session by typing the following:
M-x figwheel-repl
You'll end up to a configuration like the one shown in the following screenshot, where Figwheel, run from inf-clojure
, is awaiting connection from the browser:
As soon as you open the greet.html
file within your browser, the user prompt should change to notify you that the evaluation environment is successfully connected to the Figwheel REPL:
Let's evaluate some ClojureScript. Split your window in two using the following:
C-x 2
And load the buffer containing core.cljs
:
C-x b core.cljs [RET]
You should end up with something like the following:
Move the cursor to the (js-alert...)
form and evaluate it by hitting the following:
C-c C-c
You should see the greeting showing up in the browser.
We've now seen two different possible setups on Emacs: one based on Piggieback/Weasel, which is harder to set up but offers a fully-fledged Clojure development environment—CIDER, and another using Figwheel but offering less integrated development functionality. Which one you choose to use relies pretty much on personal taste, and how much effort you feel like putting in.