16 July 2019

CIDER jack-in to Clojure CLI projects from Spacemacs

spacemacs logo

Running a Clojure project created with CLI tools or clj-new may require you to pass in an alias for the REPL to pick up the right libraries.

A few days ago I created a new ClojureScript and reagent project, using the Clojure CLI tools and clj-new project creation tool, which converts Leiningen and Boot templates into a deps.edn based project. Unfortunately when I created a project from the fighwheel-main template the REPL failed to run from CIDER using cider-jack-in-cljs, saying that figwheel-main was not found. All that was required was to specify the :fig alias when running a REPL.

This article covers two approaches to running Clojure CLI projects from CIDER jack-in that require setting of an alias or multiple aliases e.g. -A:fig:build:party:hammock

See Getting started with Clojure CLI tools for background to this article.

Understanding the problem

I created a new project with the Clojure CLI tools and the figwheel-main template (using clj-new). This is the first time with this approach, so I may have missed something.

clj -A:new figwheel-main practicalli/study-group-guide -- --reagent

I ran cider-jack-in-cljs from Spacemacs and was prompted for the build tool. I selected figwheel-main and rather than being prompted for the name of the build to run, I got an error in the mini-buffer.

error in process filter: Figwheel-main is not available.  Please check https://docs.cider.mx/cider/basics/clojurescript

The same error was seen when looking at the output in the *messages* buffer.

[nREPL] Starting server via /usr/local/bin/clojure -Sdeps '{:deps {nrepl {:mvn/version "0.6.0"} cider/piggieback {:mvn/version "0.4.1"} refactor-nrepl {:mvn/version "2.5.0-SNAPSHOT"} cider/cider-nrepl {:mvn/version "0.22.0-beta8"}}}' -m nrepl.cmdline --middleware '["refactor-nrepl.middleware/wrap-refactor", "cider.nrepl/cider-middleware", "cider.piggieback/wrap-cljs-repl"]'...
[nREPL] server started on 40737
[nREPL] Establishing direct connection to localhost:40737 ...
[nREPL] Direct connection to localhost:40737 established
 error in process filter: user-error: Figwheel-main is not available.
 

The web page for the ClojureScript did not automatically open because figwheel-main is not running and the application was not built.

The project fails to run when using cider-jack-in-cljs as it cannot find the figwheel-main namespace. This is because CIDER is not being called with the -A:fig alias, which has a configuration to include figwheel-main as a dependency.

Hacking the CIDER jack-in command

Its very easy to hack the cider-jack-in-* commands command that CIDER uses to start a REPL using the universal argument.

SPC u , " or SPC u , s j s calls cider-jack-in-cljs with the universal argument. This will display an editable prompt for Cider jack-in in the mini-buffer.

Spacemacs Clojure - CIDER jack-in command line hacking

Use the arrow keys to edit this command and add the -A:fig option just after the /usr/local/bin/clojure executable name.

/usr/local/bin/clojure -A:fig -Sdeps '{:deps {nrepl {:mvn/version "0.6.0"} cider/piggieback {:mvn/version "0.4.1"} refactor-nrepl {:mvn/version "2.5.0-SNAPSHOT"} cider/cider-nrepl {:mvn/version "0.22.0-beta8"}}}' -m nrepl.cmdline --middleware '["refactor-nrepl.middleware/wrap-refactor", "cider.nrepl/cider-middleware", "cider.piggieback/wrap-cljs-repl"]'...

Emacs would use C-u before a cider-jack-in-* keybinding, C-u C-c M-J for the same results.

The *messages* buffer also shows the edited command line used to start a ClojureScript REPL.

[nREPL] Starting server via /usr/local/bin/clojure -A:fig -Sdeps '{:deps {nrepl {:mvn/version "0.6.0"} cider/piggieback {:mvn/version "0.4.1"} refactor-nrepl {:mvn/version "2.5.0-SNAPSHOT"} cider/cider-nrepl {:mvn/version "0.22.0-beta8"}}}' -m nrepl.cmdline --middleware '["refactor-nrepl.middleware/wrap-refactor", "cider.nrepl/cider-middleware", "cider.piggieback/wrap-cljs-repl"]'...
[nREPL] server started on 35247
[nREPL] Establishing direct connection to localhost:35247 ...
[nREPL] Direct connection to localhost:35247 established

Adding CIDER configuration with .dir-locals.el

Rather than edit the cider jack-in command options each time, a local configuration file can be created to set a variable defining the :fig alias we want to include when running a REPL for this project.

.dir-locals.el is an Emacs configuration file in which you can set variables for use with all files within the current directory or its child directories.

SPC SPC add-dir-local-variable is a simple wizard function to help you create the .dir-locals.el file. It will prompt you for the major mode, a variable name and variable value.

This variable will be used with the clojure-mode (using nil rather than clojure-mode the variable would be applied to all modes).

A variable called cider-clojure-clj-global-options will be used to set the :fig alias.

((clojure-mode . ((cider-clojure-cli-global-options . "-A:fig"))))

SPC SPC revert-buffer on one of the project source code files will load the variable from .dir-locals.el into Spacemacs. Otherwise, you can close the project buffer(s) and re-open them to load this variable into Emacs. Once the buffer is loaded again, running cider-jack-in-cljs works perfectly.

You can check the results by looking at the *mesages* buffer and you will see the details of the command that cider-jack-in-cljs function ran.

The .dir-locals.el is a list of lists. Each inner list contains which maps major mode names (symbols) to alists (see Association Lists). Each alist entry consists of a variable name and the directory-local value to assign to that variable, when the specified major mode is enabled. Instead of a mode name, you can specify ‘nil’, which means that the alist applies to any mode; or you can specify a subdirectory (a string), in which case the alist applies to all files in that subdirectory.

Understanding the :fig alias

deps.edn has a top-level key called :aliases that can include one or more alias definitions as maps. This example is from the figwheel-main template and has an extra dependency for the figwheel-main and rebel-readline-cljs libraries. So when starting a REPL with this alias, both those dependencies are available in the project.

:aliases
  {:fig
    {:extra-deps
      {com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
       com.bhauman/figwheel-main {:mvn/version "0.1.9"}}

The alias keeps these develop time libraries out of our application dependencies, as they are not required for running the application.

Leiningen includes figwheel-main as a dependency in the project.clj file in the :profiles {:dev ,,,} section. The dev profile is used by Leiningen by default, so the figwheel-main dependency is always there.

Summary

Using CIDER with projects created with Clojure CLI tools and clj-new works very well and only requires specification of which alias to use when starting the REPL from within Spacemacs.

If you have multiple aliases needed each time, you can chain them together:-A:fig:build:custom by editing the jack-in command line or including those aliases in the .dir-locals.el

Thank you. @jr0cket

Practicalli - free online books on Spacemacs and Clojure development

Tags: clojure-cli cider emacs spacemacs figwheel-main