English · 00:46:56
Jan 23, 2026 7:38 PM

Clojure and Clojurescript Setup and Installation Tutorial (+ emacs/cider/shadow-cljs!)

SUMMARY

A developer shares a step-by-step tutorial on installing and configuring Clojure and ClojureScript environments using Leiningen, Emacs, CIDER, and Shadow-CLJS for interactive development on Ubuntu.

STATEMENTS

  • The tutorial focuses on setting up a clean Ubuntu instance on AWS to demonstrate Clojure and ClojureScript installation without prior assumptions.
  • Leiningen is a primary tool for building and organizing Clojure projects, and it conveniently installs Clojure itself.
  • Installing Leiningen via Debian instructions using sudo apt-get install leiningen also pulls in Java as a dependency.
  • Creating a new Clojure project with 'lein new test-project' generates a directory with src containing core.clj featuring a simple hello-world function.
  • Running the project uses 'lein run -m test-project.core/foo' with arguments to execute functions, downloading dependencies on first run.
  • Clojure's REPL enables interactive development, allowing code execution in a running program's context, similar to a Python interpreter.
  • The default namespace in Leiningen REPL is the project's core, enabling shorthand function calls without full qualification.
  • Emacs setup involves installing packages like CIDER for Clojure development, which includes Clojure mode for syntax highlighting.
  • CIDER connects Emacs to a REPL via 'M-x cider-jack-in', allowing evaluation of expressions with C-x C-e directly in files.
  • Interactive development in Clojure involves evaluating code snippets, defining variables and functions on-the-fly, and verifying behavior incrementally.
  • Placing development code in comment blocks allows experimentation without disrupting the main program flow.
  • Key Emacs bindings like C-M-u for backward, C-M-f forward, and C-M-b backward navigate s-expressions structurally.
  • Custom Emacs extensions, like remapping 9 and 0 to parentheses, and a personal 'cider-save-command' for rebinding expressions, enhance Clojure editing.
  • ClojureScript compiles Clojure code to JavaScript via the ClojureScript compiler, enabling browser execution.
  • deps.edn file specifies dependencies and source paths for the ClojureScript compiler.
  • Basic compilation with clj outputs to out/main.js, including debug info unsuitable for production.
  • Production builds use advanced optimizations in a separate options.edn file to minify and compress JavaScript.
  • Regular advanced compilation during development prevents issues that arise only in production builds.
  • Shadow-CLJS builds on the ClojureScript compiler, handling npm dependencies which the vanilla compiler does not.
  • Setting up Shadow-CLJS requires npm installation, then 'npx shadow-cljs init' to create shadow-cljs.edn for build configuration.
  • Shadow-CLJS uses deps.edn for ClojureScript dependencies to better handle local project interdependencies.
  • Builds in shadow-cljs.edn define targets like :browser with init functions for page loading.
  • A simple Ring web server in Clojure serves compiled ClojureScript for browser testing.
  • ClojureScript REPL connects via 'M-x cider-jack-in-cljs' with Shadow, requiring a running browser for JavaScript runtime.
  • Evaluating ClojureScript code translates to JavaScript executed in the browser's console, affecting page state like styles.
  • Shadow-CLJS auto-recompiles and refreshes on save, but disabling autobuild prevents errors during in-progress coding.
  • Custom reload strategy uses saved commands to re-execute init functions like ReactDOM render without full page refresh.
  • Importing npm packages like js-confetti in ClojureScript requires converting JavaScript imports to Clojure requires.

IDEAS

  • Starting from a clean AWS Ubuntu instance ensures no missed steps in setup, simulating a new machine environment.
  • Leiningen's dual role in project management and Clojure installation simplifies the initial bootstrap process.
  • Interactive REPL development in Clojure allows variable persistence across evaluations, fostering exploratory coding unlike static compilation.
  • Emacs's CIDER enables seamless code evaluation within the editor, blurring lines between writing and testing.
  • Structural navigation keys in Emacs treat code as nested expressions, accelerating movement in parenthesis-heavy syntax.
  • Remapping keyboard keys for parentheses in Emacs reduces typing friction for Lisp-family languages.
  • Custom Emacs utilities like cider-save-command allow rebinding complex expressions, ideal for repetitive browser reloads in ClojureScript.
  • ClojureScript's compiler transforms functional code into optimized JavaScript, bridging Lisp paradigms to web constraints.
  • deps.edn's role in metadata configuration decouples build instructions from source, enabling flexible dependency management.
  • Advanced optimizations in ClojureScript compilation reveal hidden code issues ignored in dev mode, enforcing stricter correctness.
  • Shadow-CLJS's npm integration embeds JavaScript ecosystem access into Clojure workflows, eliminating toolchain silos.
  • Configuring Shadow-CLJS to defer to deps.edn for dependencies optimizes multi-project setups with local libraries.
  • Browser-targeted builds in Shadow-CLJS specify init functions that run on page load, mimicking application entry points.
  • A minimal Ring server demonstrates how Clojure backends can serve ClojureScript frontends, unifying full-stack development.
  • ClojureScript REPL requires a live JavaScript runtime, tying evaluation to actual browser contexts for realistic testing.
  • On-the-fly JavaScript execution from Emacs alters DOM state, enabling visual prototyping without manual refreshes.
  • Disabling Shadow-CLJS autobuild avoids disruptive errors during experimental coding, prioritizing developer flow.
  • Manual reload via saved init functions grants granular control over UI updates, avoiding full recompilation pitfalls.
  • Converting npm imports to Clojure requires in Shadow-CLJS democratizes access to vast JavaScript libraries.
  • Shoutouts to open-source maintainers highlight how community responsiveness shapes practical tool adoption.
  • Tutorial's focus on personal workflow acknowledges official docs' gaps, empowering users to adapt setups intuitively.

INSIGHTS

  • Clean-slate setups on virtual instances reveal foundational steps often overlooked in incremental installations, ensuring reproducibility.
  • Interactive REPLs transform programming into a conversational process, where code evolves through immediate feedback loops.
  • Editor-REPL integration in tools like CIDER eliminates context-switching costs, accelerating iterative development cycles.
  • Structural editing in Emacs aligns with Clojure's s-expression syntax, making navigation intuitive and error-resistant.
  • Custom key remappings and utilities personalize environments, turning potential frustrations into fluid interactions.
  • ClojureScript compilation bridges immutable functional logic to mutable web realities, optimizing for performance without paradigm loss.
  • Regular production-mode testing during development uncovers subtle errors, preventing late-stage deployment surprises.
  • Shadow-CLJS's layered architecture extends ClojureScript's core while resolving ecosystem incompatibilities like npm.
  • Dependency management via deps.edn promotes modularity, facilitating seamless integration across related projects.
  • Live browser evaluation in ClojureScript REPLs enables tangible UI experimentation, merging code and visual outcomes.
  • Disabling auto-features in build tools preserves creative momentum, allowing safe exploration of unfinished ideas.
  • Granular reload strategies in frontend development empower selective updates, enhancing control over application state.
  • Open-source tool evolution through maintainer engagement underscores the value of direct community contributions.

QUOTES

  • "This guide is my personal experience uh it's not an official manual or anything like that so you know obviously verify uh what you're doing and make sure it's up to date."
  • "What's really neat about closure and one of the things that people really like about it is the ability to start up a reple and then do some interactive development."
  • "This lets us sort of develop interactively and evaluate the program as we go along usually when I'm working on a piece of software I'll write bits and pieces of code and then evaluate them to make sure that they work in the way I expect."
  • "You really need to regularly compile your application with optimizations Advanced and this is something that I've run into before because if you work on a project for a really long time and you suddenly switch to compilations Advanced at the end you'll see a whole bunch of issues pop up."
  • "In my opinion uh because of the way that it handles npm modules Shadow cljs is sort of mandatory for a lot of closure script development."
  • "This is super super neat and super super useful it means we can use that same style as before where we kind of play around and build up expressions and function definitions sort of on the fly but actually do it with the visual View of our front-end application."
  • "I actually reached out over GitHub and Thomas holler responded almost immediately uh with an explanation of what to do so shout outs to him for running a very well supported and well-maintained project."

HABITS

  • Verify installations and commands against official sources before applying on local machines to avoid outdated procedures.
  • Evaluate code expressions incrementally in the REPL during development to confirm expected behavior before integration.
  • Use comment blocks for experimental code to isolate tests without affecting main program execution.
  • Navigate code structurally with Emacs bindings like C-M-f and C-M-b for efficient movement in nested expressions.
  • Remap keyboard keys, such as 9 and 0 to parentheses, to streamline typing in parenthesis-intensive languages.
  • Disable autobuild features during exploratory coding to prevent interruptions from compilation errors.
  • Save repetitive expressions to key bindings for quick re-execution, especially for UI reloads in frontend work.
  • Regularly switch to advanced optimization mode in compilations to catch dev-mode-tolerant issues early.

FACTS

  • Leiningen installation on Debian-based systems automatically resolves Java as a dependency for Clojure runtime.
  • Clojure projects generated by Leiningen include a src directory with core.clj featuring a namespaced hello-world function.
  • CIDER package installation pulls in Clojure mode, providing automatic syntax highlighting for .clj and .cljs files.
  • ClojureScript compiler outputs include dependencies in the out directory, requiring full access for browser serving.
  • Advanced optimizations in ClojureScript reduce bundle sizes significantly, improving web load times.
  • Shadow-CLJS handles npm modules by converting JavaScript requires to Clojure namespaces seamlessly.
  • Ring and Compojure libraries enable lightweight HTTP servers in Clojure for serving static assets.
  • ClojureScript REPLs demand a JavaScript runtime, typically a browser, to evaluate code affecting DOM elements.
  • Thomas Heller, Shadow-CLJS maintainer, provides rapid GitHub responses, enhancing tool adoption.

REFERENCES

  • https://github.com/sstraust (personal GitHub for custom Emacs extensions).
  • https://wiki.leiningen.org/Packaging (Leiningen installation instructions).
  • https://clojure.org/guides/install_clojure (Clojure installation guide).
  • Clojure mode (Emacs package for syntax highlighting).
  • CIDER (Emacs package for interactive Clojure development).
  • clj-refactor (Melpa package for Clojure refactoring tools).
  • cider-save-command (custom Emacs utility for saving and re-executing expressions).
  • deps.edn (Clojure dependency and build configuration file).
  • shadow-cljs.edn (Shadow-CLJS build configuration file).
  • Ring (Clojure web server library).
  • Compojure (Clojure routing library).
  • Hiccup (Clojure HTML generation library).
  • ReactDOM (JavaScript library for rendering UI components).
  • js-confetti (npm package for confetti effects).
  • Shadow-CLJS user guide (instructions for importing JavaScript modules).

HOW TO APPLY

  • Spin up a clean Ubuntu instance on AWS or open a terminal on a local machine to start with a blank slate for installations.
  • Install Leiningen using sudo apt-get install leiningen, verifying Java installation with java -version, and create a project with lein new project-name.
  • Open Emacs, use M-x package-list-packages to install CIDER, which auto-includes Clojure mode, and clj-refactor from Melpa by adding (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) to .emacs.
  • Connect to REPL with M-x cider-jack-in, then evaluate expressions in .clj files using C-x C-e at the end of forms or C-c C-c for top-level definitions.
  • For structural navigation, employ C-M-u to jump to expression start, C-M-f to move forward one s-expression, and C-M-b backward for precise positioning.
  • Create a ClojureScript project by making src with core.cljs, add deps.edn with :paths [:src] and :deps {org.clojure/clojurescript {...}}, install compiler via clj script instructions.
  • Compile with clj -M -m cljs.main -co deps.edn -t browser -s src, or for production, create prod-options.edn with :optimizations :advanced and run clj -M -m cljs.main --config prod-options.edn.
  • Set up Shadow-CLJS by installing npm, running npm init -y, npm install shadow-cljs, npx shadow-cljs init, configure shadow-cljs.edn with :source-paths ["src"] and :deps true, add build {:app {:target :browser :output-dir "out" :init-fn cljs-project.core/load-page}}.
  • Compile Shadow build with npx shadow-cljs compile app, or release with npx shadow-cljs release app, and serve out directory via a Ring server using lein new server, adding Ring/Compojure deps.
  • For ClojureScript REPL, run M-x cider-jack-in-cljs selecting shadowcljs for both clj and cljs, ensure browser loads the served page, then evaluate with C-x C-e to execute in browser console.
  • Disable autobuild by adding :devtools {:autobuild false} to shadow-cljs.edn, use custom saved commands for manual reloads of init functions.
  • Import npm libs like npm install js-confetti, convert to (:require ["js-confetti$default" :as confetti]) in namespace, evaluate to use in ClojureScript.

ONE-SENTENCE TAKEAWAY

Master Clojure and ClojureScript setups with Emacs, CIDER, and Shadow-CLJS for seamless interactive web development.

RECOMMENDATIONS

  • Begin setups on isolated environments to capture every essential step without legacy interference.
  • Prioritize Leiningen for Clojure projects due to its integrated installation and robust dependency handling.
  • Integrate CIDER early in Emacs for real-time evaluation, transforming coding into an interactive dialogue.
  • Customize Emacs bindings for s-expression navigation to exploit Clojure's syntactic structure fully.
  • Compile ClojureScript regularly with advanced optimizations to preempt production pitfalls.
  • Adopt Shadow-CLJS over vanilla compiler for npm compatibility in modern web projects.
  • Configure deps.edn as the central dependency hub to streamline multi-library workflows.
  • Build minimal Ring servers for testing ClojureScript outputs, simulating full-stack scenarios.
  • Connect ClojureScript REPLs only after browser runtime setup to ensure contextual evaluations.
  • Turn off Shadow-CLJS autobuild during ideation to maintain uninterrupted creative flow.
  • Leverage saved expression commands for targeted UI reloads, avoiding unnecessary full recompiles.
  • Experiment with npm imports in ClojureScript to tap into JavaScript's extensive library ecosystem.

MEMO

In a detailed walkthrough from a fresh AWS Ubuntu instance, the developer demystifies Clojure setup, emphasizing Leiningen's role as a build tool that doubles as an installer. Starting with a simple 'lein new' command, a project skeleton emerges, complete with a core.clj file boasting a hello-world function. Running it via 'lein run' downloads dependencies and executes code, but the real magic unfolds in the REPL—Leiningen's interactive shell—where variables persist and functions invoke seamlessly, akin to a debugger on steroids. This interactive paradigm, a hallmark of Clojure's appeal, invites developers to tinker iteratively, far removed from rigid compile-run cycles of traditional languages.

Emacs enters as the editor of choice, bolstered by CIDER for Clojure integration. Installing packages like CIDER and clj-refactor via the package list activates syntax highlighting and refactoring aids. Jacking into the REPL with 'cider-jack-in' links editor and runtime, enabling C-x C-e to evaluate expressions directly—place the cursor at a form's end, and it computes in context. Custom tweaks shine here: remapping keys for parentheses eases Lisp typing, while a homemade 'cider-save-command' binds reusable snippets, perfect for repetitive tasks. Structural navigation commands (C-M-f, C-M-b) treat code as nested trees, streamlining edits in parenthesis-laden files.

Transitioning to ClojureScript, the tutorial addresses frontend challenges by compiling Lisp-like code to JavaScript for browsers. A basic project with core.cljs and deps.edn specifies paths and deps; the compiler, installed per official guides, outputs to out/main.js. Development mode includes debug info, but production demands advanced optimizations via a dedicated edn file—minifying bundles and stripping extras for faster loads. Caution abounds: dev-lenient code often breaks under advanced scrutiny, so habitual production compiles ward off surprises.

Shadow-CLJS elevates this, layering npm support atop the core compiler—essential for JavaScript interop. After npm setup and 'npx shadow-cljs init', shadow-cljs.edn configures builds for browser targets with init functions like load-page. Using deps.edn for Clojure deps ensures local library harmony. Compilation via 'npx shadow-cljs compile app' generates assets, served by a quick Ring/Compojure backend on port 8000. This unifies stack: Clojure server hosts ClojureScript client, alerting success on load.

Development workflow peaks with ClojureScript REPLs: 'cider-jack-in-cljs' targets Shadow builds, but requires an open browser for JavaScript runtime. Evaluations translate to console executions, altering DOM—like setting body text red—merging code tweaks with visual feedback. Shadow's auto-recompile on save mimics hot-reloading, yet disabling autobuild via :devtools {:autobuild false} prevents error spam during experiments. Instead, saved commands re-run init functions, selectively refreshing UI elements without full saves.

Npm imports cap the toolkit: 'npm install js-confetti' followed by Clojure requires unleashes JavaScript libs effortlessly. Though fiddly, Shadow's guides smooth conversions, enabling confetti bursts from Clojure code. The developer's personal hacks, open-sourced on GitHub, underscore community-driven refinement—shoutouts to maintainer Thomas Heller highlight responsive support. This ecosystem, while labyrinthine, rewards persistence with a fluid bridge from functional purity to web dynamism.

Like this? Create a free account to export to PDF and ePub, and send to Kindle.

Create a free account