= Using shadow-cljs
:experimental:

`shadow-cljs` is one of the most popular toolchain for doing ClojureScript
development these days. In this section we'll discuss how to set it up and
use it together with CIDER.

== Setting up shadow-cljs

NOTE: This section assumes you've already installed node.js.

Installing `shadow-cljs` is pretty straight-forward. You can do it via `npm` or `yarn`:

  $ npm install -g shadow-cljs
  $ yarn global add shadow-cljs

While it's not necessary to do a global installation that's generally the recommended approach.

== Starting a shadow-cljs REPL

=== Using cider-jack-in-cljs

Provided you've configured your project correctly, you can simply use
`cider-jack-in-cljs`:

* Press kbd:[C-c C-x j s] (or do `M-x cider-jack-in-cljs`)
* When prompted for the ClojureScript REPL type to start, select `shadow`

This will automatically start the shadow-cljs server and connect to
it. You'll also be prompted for the shadow-cljs build to use. Select
your desired build (e.g. `app`) and you should see something like:

  shadow.user> To quit, type: :cljs/quit
  [:selected :app]
  cljs.repl>

NOTE: CIDER will extract the list of available builds automatically
from the `shadow-cljs.edn` file in the root of the current project.

You can get rid of the prompts for the REPL type and the target build
by creating a `.dir-locals.el` file with the following contents in the
root of your project.

[source,clojure]
----
((nil . ((cider-default-cljs-repl . shadow)
         (cider-shadow-default-options . "<your-build-name-here>")
         (cider-shadow-watched-builds . ("<first-build>" "<other-build>")))))
----

=== Using cider-connect-cljs

Alternatively you can start the server manually with something like:

[source,sh]
----
$ shadow-cljs watch app
----

And connect to it with `cider-connect`.

...For that to work, `shadow-cljs.edn` contents like the following are assumed:

```clj
 :dependencies [[cider/cider-nrepl "0.50.2"] ;; mandatory (unless it's inherited from deps.edn or otherwise present in the classpath of shadow-cljs's JVM process)
                [refactor-nrepl/refactor-nrepl "3.9.0"]] ;; refactor-nrepl is optional

 :nrepl {:middleware [cider.nrepl/cider-middleware ;; it's advisable to explicitly add this middleware. It's automatically added by shadow-cljs (if available in the classpath), unless `:nrepl {:cider false}`
                      refactor-nrepl.middleware/wrap-refactor] ;; refactor-nrepl is optional
         :port 50655} ;; optional - if not specified, a random free port will be used
```

NOTE: If https://docs.cider.mx/cider-nrepl/[cider-nrepl] isn't in your
classpath you should make sure it's there. You can do this by correctly filling
the `shadow-cljs.edn` configuration file
residing in the root of your project, as described above. Alternatively you can set
`cider-repl-auto-detect-type` to `nil`, as the auto-detection of
REPL types doesn't work without `cider-nrepl`.

If you already have a running server watching a build (for instance
you have already run `npx shadow-cljs watch :dev`), you can use the
`shadow-select` CLJS REPL and specify `:dev` when prompted.

=== Using shadow-cljs with deps.edn and custom repl initialization

In case you want to manage your dependencies via https://clojure.org/guides/deps_and_cli[deps.edn], you can use a
custom cljs-repl init form. This supposes you have shadow-cljs in your `deps.edn` dependencies.
```clj
{:paths ["src"]
 :deps {...
        thheller/shadow-cljs       {:mvn/version "2.15.6"}
        ...
        }
 :aliases {:dev {:extra-paths ["dev"]}}}
```

Create a `:dev` alias with an extra source path of "dev" and add the following namespace
```clj
(ns user
  (:require [shadow.cljs.devtools.api :as shadow]
            [shadow.cljs.devtools.server :as server]))

(defn cljs-repl
  "Connects to a given build-id. Defaults to `:app`."
  ([]
   (cljs-repl :app))
  ([build-id]
   (server/start!)
   (shadow/watch build-id)
   (shadow/nrepl-select build-id)))
```

Supposing your build-id is `:app`, add the following to your `.dir-locals.el`
```elisp
((nil . ((cider-clojure-cli-aliases        . ":dev")
         (cider-preferred-build-tool       . clojure-cli)
         (cider-default-cljs-repl          . custom)
         (cider-custom-cljs-repl-init-form . "(do (user/cljs-repl))")
         (eval . (progn
                   (make-variable-buffer-local 'cider-jack-in-nrepl-middlewares)
                   (add-to-list 'cider-jack-in-nrepl-middlewares "shadow.cljs.devtools.server.nrepl/middleware"))))))
```

`cider-jack-in-cljs` should then work out of the box.

== Configuration

You can tweak the command used by `cider-jack-in-cljs` to start the `shadow-cljs` server
via the following configuration variables:

* `cider-shadow-cljs-command` (its default value is `npx shadow-cljs`)
* `cider-shadow-cljs-parameters` (its default value is `server`)

All of this results in the following default command to start the shadow-cljs server:

  $ npx shadow-cljs server

The command is visible in the minibuffer when you're doing `cider-jack-in-cljs`.

As noted earlier you can also set a default build via `cider-shadow-default-options`:

  (setq cider-shadow-default-options "app")

== Additional Resources

=== Official shadow-cljs Documentation

Here are a few useful sections from ``shadow-cljs``'s own documentation:

* https://shadow-cljs.github.io/docs/UsersGuide.html#_installation[Installation]
* https://shadow-cljs.github.io/docs/UsersGuide.html#nREPL[nREPL Setup]
* https://shadow-cljs.github.io/docs/UsersGuide.html#cider[Integration with CIDER]
