A beginner guide to compile ClojureScript with shadow-cljs

JiyinYiyong
Jul 21, 2017 · 3 min read

shadow-cljs provides everything you need to compile your ClojureScript code with a focus on simplicity and ease of use.

To install shadow-cljs, use npm:

npm install -g shadow-cljs

shadow-cljs requires Java, make sure you have Java installed. Don’t worry, shadow-cljs handles Java for you. If you still want to learn more about ClojureScript, checkout this list.

Compile to browser

Say you have a project:

.
├── README.md
├── assets
│ └── index.html
├── package.json
├── shadow-cljs.edn
├── src
│ └── app
│ ├── lib.cljs
│ └── main.cljs
└── yarn.lock

assets/index.html(please copy it to target/index.html in order that it can be accessed) looks like:

<script src="main.js"></script>

src/app/main.cljs may look like:

(ns app.main)(def value-a 1)(defonce value-b 2)(defn reload! []
(println "Code updated.")
(println "Trying values:" value-a value-b))
(defn main! []
(println "App loaded!"))

The namespace for this project is just app. To compile this project, first create a shadow-cljs.edn file, with configs:

{:source-paths ["src"]
:dependencies []
:dev-http {8080 "target/"}
:builds {:app {:output-dir "target/"
:asset-path "."
:target :browser
:modules {:main {:init-fn app.main/main!}}
:devtools {:after-load app.main/reload!}}}}

Here’s how it’s configured:

  • :source-paths is where you put source code

During development, we can compile with hot code swapping, watch how we use the build id :app :

shadow-cljs watch app

After initial compilation finished, shadow-cljs would generate code in target/main.js and serve target/ folder on http://localhost:8080. When you open the url, the page will connect to shadow-cljs’ server and listen for updates. As you modify code and save files, the app will be hot reloaded and then app.main/reload! will be called.

To compile and optimize code:

shadow-cljs release app

For the complete example, please clone this repo:

Compile to Node.js

It’s quite similar steps to compile ClojureScript targeting Node.js , for the project:

.
├── README.md
├── package.json
├── shadow-cljs.edn
├── src
│ └── server
│ └── main.cljs
└── yarn.lock

src/server/main.cljs may look like:

(ns server.main)(def value-a 1)(defonce value-b 2)(defn reload! []
(println "Code updated.")
(println "Trying values:" value-a value-b))
(defn main! []
(println "App loaded!"))

We can use shadow-cljs.edn with configurations:

{:source-paths ["src"]
:dependencies []
:builds {:app {:target :node-script
:output-to "target/main.js"
:main server.main/main!
:devtools {:after-load server.main/reload!}}}}

Now we use :node-script as the compilation :target . And there are two fields:

  • :output-to specifies the output file

Like in previous demo, we can start compilation in development mode, and run it with Node.js :

shadow-cljs watch app# in another terminal
node target/main.js

As Node.js runs, it will connect to shadow-cljs’ WebSocket server listening for updates. Some npm modules(wsand source-map-support) are required, please install them. It also does hot code swapping as well as calling reload! function.

To create a release bundle, use the sub-command:

shadow-cljs release app

You may also add :compiler-options {:optimizations :simple}} to disable mangling. To try the full example, clone this repo:

More

There are also examples you can browse in shadow-cljs, like using Macros:

Or like compile code with long term caching:

And some examples run in several environments of JavaScript:

Explore more on shadow-cljs and send feedbacks on GitHub :)

)

JiyinYiyong

Written by

FP, GUI & writing, tiye.me. Chinese Blog: https://segmentfault.com/blog/jiyinyiyong

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade