Skip to content
AgileLogics
6 min read

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 (.clj or .cljc files) and used from ClojureScript.
  • .cljc files 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.