Top Related Projects
Clojure to JS compiler
A minimalistic ClojureScript interface to React.js
A ClojureScript framework for building user interfaces, leveraging React
Quick Overview
Shadow CLJS is a build tool for ClojureScript, a dialect of Lisp that compiles to JavaScript. It provides a comprehensive set of features for developing, testing, and deploying ClojureScript applications, including hot reloading, optimized production builds, and integration with various JavaScript frameworks and libraries.
Pros
- Seamless ClojureScript Development: Shadow CLJS simplifies the process of building and managing ClojureScript projects, allowing developers to focus on writing code rather than configuring build tools.
- Hot Reloading: Shadow CLJS supports hot reloading, which enables instant updates to the application without the need to refresh the page, improving developer productivity.
- Optimized Production Builds: Shadow CLJS can generate highly optimized production builds, resulting in smaller file sizes and improved performance.
- Extensive Ecosystem Integration: Shadow CLJS integrates with a wide range of JavaScript libraries and frameworks, making it easier to use ClojureScript in a variety of web development projects.
Cons
- Steep Learning Curve: For developers new to ClojureScript or Lisp, the initial setup and configuration of Shadow CLJS may be challenging.
- Limited Tooling: Compared to some other JavaScript build tools, the tooling and ecosystem around Shadow CLJS may be less extensive, which could be a drawback for some developers.
- Dependency on ClojureScript: As a ClojureScript-specific tool, Shadow CLJS is inherently tied to the ClojureScript ecosystem, which may be a limitation for developers who prefer to work primarily in JavaScript.
- Performance Overhead: While Shadow CLJS aims to optimize production builds, the additional layer of abstraction and compilation process may introduce some performance overhead compared to a pure JavaScript setup.
Code Examples
Here are a few examples of how to use Shadow CLJS:
- Creating a new project:
npx create-cljs-project my-app
cd my-app
npm install
npx shadow-cljs watch app
This command creates a new ClojureScript project using Shadow CLJS and starts the development server.
- Defining a ClojureScript namespace:
(ns my-app.core
(:require [reagent.core :as r]))
(defn hello-world []
[:div "Hello, World!"])
(defn ^:export main []
(r/render [hello-world] (.getElementById js/document "app")))
This code defines a simple ClojureScript component that renders "Hello, World!" and exports a main
function to be used as the entry point for the application.
- Configuring Shadow CLJS:
{:source-paths ["src"]
:dependencies [[reagent "1.1.1"]]
:builds {:app {:target :browser
:output-dir "public/js"
:asset-path "/js"
:modules {:main {:entries [my-app.core]}}
:devtools {:http-root "public"
:http-port 8080}}}}
This is an example of a Shadow CLJS configuration file, which specifies the source paths, dependencies, and build settings for the application.
- Deploying a production build:
npx shadow-cljs release app
This command generates an optimized production build of the application, which can then be deployed to a web server.
Getting Started
To get started with Shadow CLJS, follow these steps:
-
Install Node.js and npm (the Node.js package manager).
-
Create a new project directory and navigate to it in your terminal.
-
Run the following command to create a new ClojureScript project using Shadow CLJS:
npx create-cljs-project my-app
-
Change into the project directory:
cd my-app
-
Install the project dependencies:
npm install
-
Start the development server:
npx shadow-cljs watch app
This command will start the Shadow CLJS development server and begin watching your source files for changes.
-
Open your web browser and navigate to `http
Competitor Comparisons
Clojure to JS compiler
Pros of ClojureScript
- Official implementation backed by Cognitect and the Clojure core team
- Tighter integration with Clojure ecosystem and libraries
- More extensive documentation and community resources
Cons of ClojureScript
- Slower build times, especially for large projects
- More complex configuration and setup process
- Less streamlined development experience for JavaScript interop
Code Comparison
ClojureScript:
(ns my-app.core
(:require [reagent.core :as r]))
(defn hello-world []
[:h1 "Hello, World!"])
(r/render [hello-world]
(js/document.getElementById "app"))
Shadow-cljs:
(ns my-app.core
(:require [reagent.dom :as rdom]))
(defn hello-world []
[:h1 "Hello, World!"])
(rdom/render [hello-world]
(js/document.getElementById "app"))
The code examples are very similar, with Shadow-cljs using reagent.dom
instead of reagent.core
for rendering. Shadow-cljs generally provides a more modern and streamlined development experience, with faster build times and easier JavaScript interop. However, ClojureScript offers tighter integration with the broader Clojure ecosystem and more extensive community resources.
A minimalistic ClojureScript interface to React.js
Pros of Reagent
- Focused specifically on React integration for ClojureScript
- Simpler API for creating React components
- Lightweight and easy to integrate into existing projects
Cons of Reagent
- Limited to React development
- Requires additional tooling for full-stack ClojureScript development
- Less comprehensive build and development environment
Code Comparison
Reagent component:
(defn hello-world []
[:div
[:h1 "Hello, World!"]
[:p "Welcome to Reagent"]])
Shadow-cljs component (using Reagent):
(ns my-app.core
(:require [reagent.core :as r]))
(defn hello-world []
[:div
[:h1 "Hello, World!"]
[:p "Welcome to Shadow-cljs"]])
(defn init []
(r/render [hello-world]
(.getElementById js/document "app")))
Summary
Reagent is a specialized library for React development in ClojureScript, offering a simpler API for creating components. Shadow-cljs, on the other hand, is a more comprehensive build tool and development environment for ClojureScript projects, which can be used in conjunction with Reagent. While Reagent focuses on React integration, Shadow-cljs provides a broader set of features for ClojureScript development, including npm integration, hot reloading, and support for various target environments.
A ClojureScript framework for building user interfaces, leveraging React
Pros of re-frame
- Provides a comprehensive architecture for building scalable ClojureScript applications
- Offers a well-defined data flow and state management system
- Includes built-in debugging and developer tools
Cons of re-frame
- Steeper learning curve for developers new to functional programming concepts
- More opinionated and less flexible compared to shadow-cljs
- Requires additional setup and configuration for non-React projects
Code Comparison
re-frame:
(rf/reg-event-db
:initialize-db
(fn [_ _]
{:name "re-frame"}))
(rf/reg-sub
:name
(fn [db]
(:name db)))
shadow-cljs:
(defn init []
(println "Initializing app"))
(defn ^:export main []
(init))
Summary
re-frame is a comprehensive framework for building ClojureScript applications with a focus on state management and data flow. It provides a structured approach to application development but may have a steeper learning curve.
shadow-cljs, on the other hand, is a build tool and runtime for ClojureScript that offers more flexibility and easier integration with JavaScript libraries. It's less opinionated about application architecture but requires more manual setup for state management.
The choice between the two depends on project requirements, team expertise, and desired level of structure in the application architecture.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME

shadow-cljs
provides everything you need to compile your ClojureScript code with a focus on simplicity and ease of use.
User's Guide | Quick Start | Tutorials | Browser Extension
Features
- Good configuration defaults so you don't have to sweat the details
- Seamless
npm
integration - Fast builds, reliable caching, ...
- Supporting various targets
:browser
,:node-script
,:npm-module
,:react-native
,:chrome-extension
, ... - Live Reload (CLJS + CSS)
- CLJS REPL
- Code splitting (via
:modules
)
Requirements
- Node.js or Bun
- npm (comes with Node.js), bun (comes with Bun), pnpm, or yarn
- Java SDK (Version 11+, Latest LTS Version recommended)
Quick Start
Creating your project can be done quickly using the npx create-cljs-project
utility. npx
is part of npm
and lets us run utility scripts quickly without worrying about installing them first. The installer will create a basic project scaffold and install the latest version of shadow-cljs
in the project.
$ npx create-cljs-project acme-app
npx: installed 1 in 5.887s
shadow-cljs - creating project: .../acme-app
Creating: .../acme-app/package.json
Creating: .../acme-app/shadow-cljs.edn
Creating: .../acme-app/.gitignore
Creating: .../acme-app/src/main
Creating: .../acme-app/src/test
----
Installing shadow-cljs in project.
npm notice created a lockfile as package-lock.json. You should commit this file.
+ shadow-cljs@<version>
added 88 packages from 103 contributors and audited 636 packages in 6.287s
found 0 vulnerabilities
----
Done.
----
The resulting project has the following structure
.
âââ node_modules (omitted ...)
âââ package.json
âââ package-lock.json
âââ shadow-cljs.edn
âââ src
âââ main
âââ test
shadow-cljs.edn
will be used to configure your CLJS builds and CLJS dependencies. package.json
is used by npm
to manage JS dependencies.
Everything is ready to go if you just want to start playing with a REPL
$ npx shadow-cljs node-repl
# or
$ npx shadow-cljs browser-repl
When building actual projects we need to configure the build first and create at least one source file.
The default source paths are configured to use src/main
as the primary source directory. It is recommended to follow the Java Naming Conventions to organize your CLJS namespaces. It is recommended to start all namespaces with a unique enough prefix (eg. company name, project name) to avoid conflicts with generic names such as app.core
. Suppose you were building a Web Frontend for Acme Inc. using acme.frontend.app
might be a good starting point as it can easily grow to include acme.backend.*
later on.
Using the above example the expected filename for acme.frontend.app
is src/main/acme/frontend/app.cljs
.
Lets start with a simple example for a browser-based build.
(ns acme.frontend.app)
(defn init []
(println "Hello World"))
Inside the shadow-cljs.edn
:builds
section add
{...
:builds
{:frontend
{:target :browser
:modules {:main {:init-fn acme.frontend.app/init}}
}}}
This config tells the compiler to call (acme.frontend.app/init)
when the generated JS code is loaded. Since no :output-dir
is configured the default public/js
is used. You can start the development process by running:
$ npx shadow-cljs watch frontend
...
a few moments later ...
...
[:frontend] Build completed. (134 files, 35 compiled, 0 warnings, 5.80s)
The compilation will create the public/js/main.js
we configured above (:main
becomes main.js
in the :output-dir
). Since we want to load this in the browser we need to create a HTML file in public/index.html
.
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>acme frontend</title>
</head>
<body>
<div id="root"></div>
<script src="/js/main.js"></script>
</body>
</html>
We also need a simple HTTP server to serve our HTML since modern Browsers all place a few restrictions on files loaded directly from disk which will lead to issues later. shadow-cljs
provides such a server but you can use anything you like at this point. It only matters that the files from the public
directory are served properly. To start the built-in web server just adjust the build config from above.
{...
:dev-http {8080 "public"}
:builds
{:frontend
{:target :browser
:modules {:main {:init-fn acme.frontend.app/init}}
}}}
Once the config is saved the server will automatically start and serve the content at http://localhost:8080. There is no need to restart shadow-cljs
. When opening the above URL the Browser Console should show "Hello World".
To be continued ...
Documentation
Please refer to the User Manual. (Work in Progress)
Video Courses
- [EN] Learn Reagent Free - reagent+firebase demo application built using shadow-cljs
- [EN] Learn Reagent Pro [Affiliate Link, 30$ discount] - reagent+firebase demo application built using shadow-cljs
- [EN] Learn re-frame [Affiliate Link] - re-frame SPA tutorial
- [EN] ClojureScript for React Developer - Building Conduit
Guides
- [EN] A beginner guide to compile ClojureScript with shadow-cljs
- [CN] shadow-cljs 2.x ä½¿ç¨æç¨
- [JA] Shadow CLJS Userâs Guide é¦è¨³
- [EN] ClojureScript with Middleman via Shadow-CLJS
- [EN] Clojurescript Development for JavaScript Developers in Atom with Shadow-cljs and ProtoREPL
- [EN] Confidence and Joy: React Native Development with ClojureScript and re-frame
- ... please let me know if you created something to include here
Examples
- Official Browser Example
- re-frame-template - Leiningen template that creates a re-frame project using the shadow-cljs build tool with many optional extras.
- mhuebert/shadow-re-frame - Usage of re-frame, re-frame-trace, and the shadow-cljs build tool. Live Demo
- jacekschae/shadow-reagent - shadow-cljs + proto-repl + reagent
- jacekschae/shadow-firebase - shadow-cljs + firebase
- ahonn/shadow-electron-starter - ClojureScript + Shadow-cljs + Electron + Reagent
- jacekschae/conduit - Real world application built with shadow-cljs + re-frame + re-frame-10x
Demo | Demo with re-frame-10x - quangv/shadow-re-frame-simple-example - a simple re-frame + shadow-cljs example.
- CryptoTwittos - reagent, re-frame, web3
- loganpowell/shadow-proto-starter - shadow-cljs, Atom, Proto-REPL, node.js library
- manuel-uberti/boodle - re-frame based Accounting SPA with
deps.edn
based backend - shadow-cljs-kitchen-async-puppeteer - Automated browser test with puppeteer and cljs.test, built with shadow-cljs
- baskeboler/cljs-karaoke-client - web karaoke player using shadow-cljs + reagent + re-frame + re-frame-10x + re-frame-async-flow-fx + build hooks for minifying css and generating seo pages (Demo)
- flexsurfer/ClojureRNProject - simple React Native application with ClojureScript, re-frame and react navigation v5
- jacekschae/shadow-cljs-devcards - how to configure devcards with shadow-cljs
- jacekschae/shadow-cljs-tailwindcss - shadow-cljs + tailwindcss-jit setup
- ertugrulcetin/racing-game-cljs - A 3D racing game built with ClojureScript, React and ThreeJS
- prestancedesign/pingcrm-clojure - A full stack SPA application built with Clojure + ClojureScript to illustrate how Inertia.js works.
- ... please let me know if you created something to include here
Libraries
- flexsurfer/rn-shadow-steroid - React Native with shadow-cljs on steroids
- re-frame-flow - A graph based visualization tool for re-frame event chains using shadow-cljs
- ... please let me know if you created something to include here
License
Copyright © 2024 Thomas Heller
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.
Top Related Projects
Clojure to JS compiler
A minimalistic ClojureScript interface to React.js
A ClojureScript framework for building user interfaces, leveraging React
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot