A beginner guide to compile ClojureScript with shadow-cljs
--
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:dependencies
is ClojureScript deps of this projects:builds
is where you specify build configurations:app
is a build id named by us, we will need it to run specific compilations from command line tools or from APIs:output-dir
decides where the generated files are saved:asset-path
is the base path of files of the hot updated code:target
is short for “compilation target”,:browser
is for browser apps:modules
specifies the modules we want to generate,:main
also means the bundle will be namedmain.js
:init-fn
specifies the main function of the whole program:devtools
specifies configurations for development tools:dev-http
tells shadow-cljs to serve the foldertarget/
on port 8080.
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:main
specifies the main function
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(ws
and 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 :)