ClojureScript
Prerequisites: Namespaces, Atoms
ClojureScript is Clojure compiled to JavaScript. The language, the data structures, and most of the core library are the same, so the skills from this course transfer directly — you just target browsers and Node.js instead of the JVM.
What's different
- The host is JavaScript: interop uses
js/for globals ((js/alert "hi"),(.log js/console x)) and#js {...}for JavaScript object literals. - There's one thread, so no refs, agents, or blocking operations; atoms and core.async work.
- Macros are written in Clojure (
.cljor.cljcfiles) and used from ClojureScript. .cljcfiles can be shared between Clojure and ClojureScript, with reader conditionals for host-specific parts:
;; illustrative — src/shared/money.cljc
(ns shared.money)
(defn parse-amount [s]
#?(:clj (bigdec s)
:cljs (js/parseFloat s)))
Tooling: shadow-cljs
shadow-cljs is the most popular build tool. It integrates with npm, so you can use any JavaScript library.
;; illustrative — shadow-cljs.edn
{:source-paths ["src"]
:dependencies [[reagent "1.3.0"]]
:builds {:app {:target :browser
:output-dir "public/js"
:modules {:main {:init-fn app.core/init}}}}}
npx shadow-cljs watch app # compile, serve, and hot-reload on save
npx shadow-cljs release app # optimized production build
A Reagent component
Reagent is a minimal React wrapper: components are functions that return Hiccup vectors, and state lives in Reagent atoms.
;; illustrative — src/app/core.cljs
(ns app.core
(:require [reagent.core :as r]
[reagent.dom.client :as rdc]))
(defonce clicks (r/atom 0))
(defn counter []
[:div
[:p "Clicked " @clicks " times"]
[:button {:on-click #(swap! clicks inc)} "Click me"]])
(defonce root (rdc/create-root (js/document.getElementById "app")))
(defn init []
(rdc/render root [counter]))
When clicks changes, Reagent re-renders only the components that read
it. For larger apps, re-frame adds an event/subscription
architecture on top of Reagent; UIx and Helix are thinner,
hooks-first React wrappers.
When to choose ClojureScript
It shines for data-heavy front ends and for teams already using Clojure on the backend — one language and one data format (EDN) end to end. If you mostly need a conventional web front end, plain JavaScript or TypeScript has a much larger ecosystem.