ClojureScript compilation made easy!
Recent posts
shadow-cljs provides everything you need to compile your ClojureScript code with a focus on simplicity and ease of use.
  • 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)
  • Code splitting (via :modules)
  • To use shadow-cljs, add your configurations in a shadow-cljs.edn file, and run:
    npm install -g shadow-cljs # Node.js and JVM are required to be installed
    shadow-cljs compile app # `:app` is the build-id defined in shadow-cljs.edn
    shadow-cljs demo


    For a browser app, create a shadow-cljs.edn file like:
    {:source-paths ["src"]
     :dependencies [[reagent "0.8.1"]]
     :builds {:app {:target :browser
                    :output-dir "public/js"
                    :asset-path "/js"
                    :modules {:main {:init-fn app.main/main!}}}}}
    which means:
    {:source-paths ["src"] ; where you put source files
     :dependencies [[reagent "0.8.1"]] ; ClojureScript dependencies
            ; "app" is the build-id, in running "shadow-cljs compile app"
     :builds {:app {:target :browser ; compile code that loads in a browser
                    :output-dir "public/js"
                    :asset-path "/js" ; assets loaded from index.html are based on path "/js"
                            ; "main.js" is the name for the bundle entry
                    :modules {:main {:init-fn app.main/main!}}}}}
                                   ; function app.main.main! is called when page loads
    Use :target :node-script for compiling in Node.js and there are also more targets to try.
    To publish a ClojureScript package with dependencies from npm, add a dep.cljs file. shadow-cljs will read it and install those npm modules.

    CLI tools

    Some useful shadow-cljs commands during development are:
    # compile a build once and exit
    shadow-cljs compile app
    # compile and watch
    shadow-cljs watch app
    # connect to REPL for the build (available while watch is running)
    shadow-cljs cljs-repl app
    # connect to standalone node repl
    shadow-cljs node-repl
    Running a release build optimized for production use.
    shadow-cljs release app
    Find out more commands in the docs.

    Using modules from npm

    With shadow-cljs, most npm modules for browser can be imported with modules installed locally.
    (ns app.main
      (:require ["md5" :as md5]
                ["fs" :as fs]))
    (println (md5 "text"))
    (fs/readFileSync "deps.den" "utf8")

    Hot code swapping

    shadow-cljs watches for file changes and re-compiles code incrementally. Warnings and errors are displayed after being prettified.
    {:source-paths ["src"]
     :dependencies []
     :dev-http {8080 "target/"}
     :builds {:browser {:target :browser
                        :output-dir "target/browser"
                        :modules {:main {:init-fn app.main/main!}}
                        ; configure devtools to have hot code swapping
                        :devtools {:after-load app.main/reload!}}}}

    Non-code resources

    There are various use-cases where you’d want to use a static resource as part of the compilation of your source files. shadow-cljs provides a macro shadow.resource/inline for loading files from inside classpaths:
      (:require [shadow.resource :as rc]))
    (def docs (rc/inline "./")) ; docs is the string content of the file
    ; also like:
    ; (def docs (rc/inline "demo/"))
    This will resolve the ./ file relative to the current namespace, which means it will end up including demo/ from somewhere on the classpath.

    Long-term caching

    By setting in :module-hash-names field you may tell shadow-cljs to add MD5 hash in the filenames generated. It's a trivial feature in Webpack and now it's a one-liner config in ClojureScript. Meanwhile the assets.edn file can be emitted for indexing js files in HTML.
    {:source-paths ["src"]
     :dependencies [[mvc-works/hsl "0.1.2"]]
     :builds {:browser {:target :browser
                        :output-dir "target/browser"
                        :modules {:main {:init-fn app.main/main!}}
                        :release {:output-dir "dist/"
                                  :module-hash-names 8
                                  :build-options {:manifest-name "assets.edn"}}}}}
    After compilation, two files will be generated in dist/ with names:
    =>> l dist/
    assets.edn        main.9683CD2F.js

    Embedding in the JS Ecosystem — The :npm-module Target

    There is an additional target that is intended to help you use shadow-cljs as part of a project and provide seamless integration with existing JS tools (eg. webpack, browserify, babel, create-react-app, …​) with as little configuration as possible.
    Sample source for src/main/demo/foo.cljs
    (defn hello [who]
      (str "Hello, " who "!"))
    Compile code to `:npm-module` target
     ; ...
     :builds {:npm {:target :npm-module
                    ; ...
    The generated exports will be named shadow-cljs/ with the CLJS namespace.
    $ node
    > var x = require("shadow-cljs/");
    > x.hello("JS")
    'Hello, JS!'

    Other features

    There are more features in shadow-cljs, such as:
    Read the User Guide to learn about all the features.

    Getting started

    Here are some configurations you can start with:
    Site built with shadow-cljs and Respo. Contribute content at shadow-cljs/