Convert Figma logo to code with AI

thheller logoshadow-cljs

ClojureScript compilation made easy

2,301
181
2,301
34

Top Related Projects

Clojure to JS compiler

4,811

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:

  1. 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.

  1. 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.

  1. 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.

  1. 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:

  1. Install Node.js and npm (the Node.js package manager).

  2. Create a new project directory and navigate to it in your terminal.

  3. Run the following command to create a new ClojureScript project using Shadow CLJS:

    npx create-cljs-project my-app
    
  4. Change into the project directory:

    cd my-app
    
  5. Install the project dependencies:

    npm install
    
  6. 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.

  7. 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.

4,811

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 Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

npm Clojars Project

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)

overview-img

Requirements

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

Guides

Examples

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.

NPM DownloadsLast 30 Days