This is a tiny example project for setting up development usingnREPLandshadow-cljs.TheClojureScriptapp is rendered usingReagent.
By default the project usesdeps.ednfor dependencies. There is aLeiningensetup as well.
npm i
(Oryarn
,whatever you fancy.)
If you are using something likeCalvaorCIDER,just jack in to the project as ashadow-cljsproject type, and hack away.
The following instructions are for working with the project without an editor. You probably wouldn't do that. The point is mostly to demystify what the editors are doing when starting and attaching to a shadow-cljs project. So, you could say it is for educational purposes. Since it's pretty quick, why not try it out?
You can start this project using eithershadow-cljs
,clojure
,orlein
.As you are doing this to maybe learn something, please consider trying all three options.
npx shadow-cljs -d cider/cider-nrepl:0.28.5 clj-repl
...
shadow.user=>
NB: If you useshadow-cljs
it will in turn useclojure
to start Clojure and the nREPL server. (Orlein
if you editshadow-cljs.edn
and change this.)
To start the project and the nREPL server withclojure
,in one terminal:
% clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version, "1.0.0" },cider/cider-nrepl {:mvn/version, "0.28.5" }}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware,shadow.cljs.devtools.server.nrepl/middleware]"
Attach to the nREPL server in another terminal:
% clojure -Sdeps '{:deps {reply/reply {:mvn/version "0.5.1" }}}' -M -m reply.main --attach `<.nrepl-port`
...
user=>
Or, since thedeps.edn
file specifies thenrepl
dependency:
% clj -M -m nrepl.cmdline -c --port `<.nrepl-port`
...
user=>
To start the project and the nREPL server with Leiningen, in one terminal:
lein update-in:dependencies conj '[nrepl, "1.0.0" ]' -- update-in:dependencies conj '[cider/cider-nrepl, "0.28.5" ]' -- update-in:plugins conj '[cider/cider-nrepl, "0.28.5" ]' -- update-in '[:repl-options,:nrepl-middleware]' conj '[cider.nrepl/cider-middleware,shadow.cljs.devtools.server.nrepl/middleware]' -- repl:headless
NB: This doesn't properly inject the shadow-cljs nREPL middleware for some reason.You'll need to add this toproject.clj
:
:repl-options{:nrepl-middleware[shadow.cljs.devtools.server.nrepl/middleware]}
Attach to the nREPL server in another terminal:
% lein repl:connect
...
main.server=>
(Not needed if if you started the REPL using the shadow-cljs executable.)
user=> (do(require'shadow.cljs.devtools.server) (shadow.cljs.devtools.server/start!))
shadow-cljs - HTTP server available at http://localhost:8700
shadow-cljs - server version:2.19.9 running at http://localhost:9632
shadow-cljs - nREPL server started on port57770
:shadow.cljs.devtools.server/started
user=>
(Never mind the second nREPL server started here.)
At this point the shadow-cljs dev browser is running and serving on port 8700, but your ClojureScript app is not running. It is not even compiled. As you'll see if you visithttp://localhost:8700with your browser.
(Therequire
is not needed if you started the REPL with the shadow-cljs executable.)
user=> (do(require'shadow.cljs.devtools.api) (shadow.cljs.devtools.api/watch:app))
[:app] Configuring build.
[:app] Compiling...
[:app] Build completed. (170files,0compiled,0warnings,1.35s)
:watching
user=>
Openhttp://localhost:8700in a web browser. (Or refresh if you opened it in an earlier step.)
Confirm that the shadow-cljs watcher is running by editing some hiccup insrc/main/core.cljs
and save the file.
(Therequire
is not needed if you started the REPL with the shadow-cljs executable.)
user=> (do(require'shadow.cljs.devtools.api) (shadow.cljs.devtools.api/nrepl-select:app))
To quit, type::cljs/quit
[:selected:app]
cljs.user=>
(If you instead of[:selected:app]
see:missing-nrepl-middleware
,you are probably using Leiningen and missed a note above.)
Confirm that your REPL is attached to the app in the browser:
cljs.user=> (js/alert"BOOM!")
(You need to dismiss the alert in the browser to get the prompt back.)
Something more interesting could be to update the app state, maybe?
cljs.user=> (load-file"src/main/core.cljs")
[]
cljs.user=> (in-ns'main.core)
nil
main.core=> (swap!app-state update:textstr"UPDATED")
{:text"Hello world! UPDATED"}
(Check the app in the browser.)
If you use this project as a base for something, then edit.gitignore
and removepackage-lock.json
.
The reason the Leiningen project file is not including the shadow nrepl middleware configuration is that I thinkthe failure to inject via the command line is a bug in Leiningenand that it will eventually be fixed.