This post will be a quick note since it's too tedious to go into the details. For the inpatient, you may clone the repo below and start exploring:

Here's how it worked. Normally for a compiled-to-js language, it compiled to JavaScript files first. In order that Webpack can bundle it, these JavaScript files should follow CommonJS, which is the npm way of resolving modules and files.

The problem with ClojureScript was it did not emit CommonJS code using Google Closure Compiler. Instead, it uses namespaces to organize modules, which is incompatible with Webpack. Then we saw shadow-cljs.


Not into details either, you may find docs at: For short, it emits CommonJS code by compiling from ClojureScript. thheller may have more to say about it since shadow-cljs itself has many features even making it self a Webpack alternative for ClojureScript.

Before starting the compiler, we need a config file called shadow-cljs.edn , where :target :npm-module says we are compiling to npm compatible code:

{:source-paths ["src"]
 :dependencies [[mvc-works/hsl "0.1.2"]]
 :builds {:app {:target :npm-module
                :output-dir "compiled/"}}}

By calling shadow-cljs compile app we can generate ClojureScript into JavaScript in compiled/ . That file may look like:

var CLJS_ENV = require("./cljs_env");
var COMPILED = false;
var cljs=CLJS_ENV.cljs;
var client=CLJS_ENV.client || (CLJS_ENV.client = {});
console.log("Loading lib.cljs");
client.lib.lib_data = "Edit lib.cljs to change 2!";

module.exports = client.lib;

It's ugly but already JavaScript. Now it's familiar.

Webpack HMR

You may refer to the docs for details. But I made a repo trying to make it clear . Also for short, it's just Webpack's way to hot patch single JavaScript files in the runtime.

It's notable that JavaScript contains more side-effects compared to ClojureScript, which leads to a rougher solution in Webpack to replace code. I guess ClojureScript compiler is smarter to tell which files need to be updated. Anyway, for now, it works.


Many of us JavaScript developers are already familiar with Webpack, while it's always tough to pick up Leiningen or Boot in order to build apps. We want to reuse our existing knowledges even for new languages like ClojureScript. I consider shadow-cljs a big chance we make it better.

One thing to remember is that people chose Closure Compiler for a reason, dead code elimination! With CommonJS and Webpack, it's some not that possible. So be careful if size matters is you case.

Write your comment…

I won't argue about shadow-cljs, although it's self description doesn't say much about what it does (provide some good defaults). I assume your goal is to use CLJS library in an application bundled for the browser using Webpack. CLJS compiler has an option to emit node.js compatible code using :target :nodejs option. You would presumably use this to bundle up your CLJS project as CommonJS module. With this, you can annotate your public functions like so (defn ^:export do-somthing [a b] (...)) you could then use them in your JS code as, b) after require() or import your module. So that's how you would use your module in production build. If you want live coding, I think figwheel is amazing in what it can do, far more than Webpack's HMR (eg. CIDER, Fireplace, ...). If you want to use live-code your CLJS library in your Webpack JS application, you can comment out the require() or import in your JS client code, and include Figwheel enabled JS file in an extra <script> tag. Hence you won't use Webpack's HMR for CLJS code, you will get faster reloads, and you will be able to eval code from your editor, in your running Webpack app in the browser, and you won't need additional dependency on shadow-cljs

Show all replies

Yes you can always get better experience with Figwheel or boot-reload, and shadow-cljs itself provides better tooling too. The reason I use Webpack is I was from JavaScript side and have features and toolchains I liked in Webpack.

Need to mention that, by using Webpack, we no longer have correct SourceMaps, cljs REPL, head-up compilation error messages. It's an insufficient solution to senior cljs developers.

Reply to this…

Hashnode is building a friendly and inclusive dev community. Come jump on the bandwagon!

  • 💬 A beginner friendly place

  • 🧠 Stay in the loop and grow your knowledge

  • 🍕 >500K developers share programming wisdom here

  • ❤️ Support the growing dev community!

Register ( 500k+ developers strong 👊)

Just wanted to say that I think this is a good idea and would def use a mature and stable version of it. :)