ClojureScript for absolute beginners

This post takes you through the process of writing a simple ClojureScript program and running it in a web browser. It’s in three parts: Writing, Compiling and Running the program. It assumes no prior experience with Clojure, ClojureScript, Java, or much else apart from a working knowledge of JavaScript and the command line. You’ll need to have the Clojure language installed (instructions here), because the ClojureScript compiler is implemented in Clojure.

Finally, you’ll need a clean working directory in which to keep the files you’ll create.

Writing the program

We’re not going to go into the syntax and semantics of ClojureScript here — we’re just demonstrating the end-to-end journey from ClojureScript source to your browser executing it — so the following code should do for a first program.

(ns beginner.core)
(js/document.write “I have been compiled to JavaScript!”)

When we compile and run this, we expect it to print “I have been compiled to JavaScript!” using the trusty document.write() function from JavaScript.

You’ll notice it declares a namespace using ns. This is obligatory for all ClojureScript files, and it matters for two reasons. Firstly, it’s necessary to put the file at a path which exactly reflects that namespace, i.e. beginner/core.cljs. Secondly, that path needs to be somewhere the ClojureScript compiler can find it. By default, the compiler looks in a folder called src/. So relative to the clean working directory we start with, the file needs to live at src/beginner/core.cljs.

At this point, your directory ought to look something like this:

└── src
    └── beginner
        └── core.cljs

Compiling the program

The ClojureScript compiler works like this: you tell it the namespace of the ClojureScript program you want to compile, it gathers the namespace’s files from their predicatable location on disk (see above), and it produces some more files which are that program translated into JavaScript.

Because the ClojureScript compiler is a Clojure library, we need to call it from Clojure, and to do that, we need to let Clojure know we want to take a dependency on the compiler.

When you run Clojure using the built-in clj tool, it loads any dependencies defined in a deps.edn file (more about that) in the current working directory. So all that’s required to declare a dependency on the ClojureScript compiler is to create that file and insert the following:

{:deps {org.clojure/clojurescript {:mvn/version "1.10.520"}}}

Now your working directory looks like this:

├── deps.edn
└── src
    └── beginner
        └── core.cljs

And it’s possible to invoke the compiler from the command line:

clj --main cljs.main --compile beginner.core

NB it looks like we’re passing two options to clj: --main and --compile. Actually, we are passing --main to clj and --compile to cljs.main 🙃. In practice, everything after cljs.main is an option for ClojureScript, not for clj.  You can find a list of the available options here.

If all is well, this will print nothing and exit, and you should find a new folder in your working directory called out/. This holds our program. Now: how to run it?

Running the program

We want a web browser to execute the JavaScript we’ve just compiled, and we can achieve that by including the compiled file in a web page. Create a file called index.html in your working directory and insert the following markup:

    <script src="out/main.js"></script>

Now your working directory looks like this:

├── deps.edn
├── index.html
└── out
    └── main.js
    └── *some other stuff*
└── src
    └── beginner
        └── core.cljs

Open this file in your web browser, and you should see the words “I have been compiled to JavaScript!”

You have just compiled some ClojureScript. You created a ClojureScript file, placed it in a predictable location, and gave its namespace to the ClojureScript compiler. The compiler found your file using the namespace and turned it into JavaScript. You included that JavaScript in a web page, and it executed.

Inside /out

We blindly included out/main.js to get the browser to pick it up. Let’s have a look inside the out/ folder.

out/ contains many more files than main.js. After compiling the very simple program from the previous post, my out/ folder contains no fewer than 35 files in 18 directories: a total of 4.7 megabytes of code. For comparison, the program itself in plain JavaScript would be 54 bytes.

To experience vertigo, have a look inside main.js:

var CLOSURE_NO_DEPS = true;
if(typeof goog == "undefined") document.write('<script src="out/goog/base.js"></script>');
document.write('<script src="out/goog/deps.js"></script>');
document.write('<script src="out/cljs_deps.js"></script>');
document.write('<script>if (typeof goog == "undefined") console.warn("ClojureScript could not load :main, did you forget to specify :asset-path?");</script>');

This doesn’t even contain our program code — just some jargon and a series of calls to document.write to load yet more scripts. The program is here somewhere, because it runs when we include main.js, but it’s not immediately obvious where.

What makes this file complicated is that our original program has a single enormous implicit dependency: the ClojureScript language itself. The JavaScript implementation of that depends in turn on another library called Google Closure (GCL). Therefore our out/ folder includes the entirety of the GCL as well as the JavaScript translation of the ClojureScript standard library, and main.js loads the lot via those document.write calls which are including other scripts.

All of them are interesting in different ways. A good place to start poking around in /out is cljs_deps.js. Its job is to declare all our dependencies: the GCL, whichever bits of ClojureScript we need in the form of .js files in the out/cljs folder, and finally our program:

goog.addDependency("base.js", ['goog'], []);
goog.addDependency("../cljs/core.js", ['cljs.core'], ['goog.string', 'goog.Uri', 'goog.object', 'goog.math.Integer', 'goog.string.StringBuffer', 'goog.array', 'goog.math.Long']);
goog.addDependency("../process/env.js", ['process.env'], ['cljs.core']);
goog.addDependency("../beginner/core.js", ['beginner.core'], ['cljs.core']);

It now seems pretty clear that we can look inside out/beginner/core.cljs and find our ClojureScript code as JavaScript, and here it is:

// Compiled by ClojureScript 1.10.520 {}
document.write("I have been compiled to JavaScript");


That’s the journey of a .cljs file into a .js file. Useful? Interesting? Wrong? Please leave a comment!

Join the Conversation


  1. That’s a really great intro.
    JS will need to keep an open mind though about all these dependencies.
    It’s a price to be paid for gains in productivity that will pay off later.

    It would be good to tackle shadow-cljs next, which provides a seamless transition to using npm modules (which most JS devs should be familiar with) as well as hot code reloading, which is the killer app of CLJS.

    1. Thank you! What do you mean by “JS will need to keep an open mind though about all these dependencies” — that existing JS users might be put off by the weight of GCL etc?

      I’m planning to have a go at `shadow-cljs` in a future post :).

  2. Hello and thank you for the post, it’s really great intro 🙂

    What would be the optimal path to learn ClojureScript in your opinion?

  3. Dear user

    If you want to win $6000 !!! 100% Deposit Match up to $300 !!!
    An Online Claw Machine that reveals your randomly generated answers in a fun and effective way! The Claw Machine is a great way to generator names, words and numbers. Homepage slot cars online store slot machine free apps casino slot machine winners slots you can win real money online casino slot strategy Click Here The goal of playing online slots for real money is to win and win big. get redirected here No code required Bonus: First Deposit Bonus Game types: Keno, Slots Players.
    No Deposit Casino Bonus or free sign up bonus is offered to new players who wish to join a casino the first time. his explanation 2 reviews of Port Jefferson Raceway “This is the last surviving Slot Car Raceway in Suffolk County. my explanation Bush Telegraph, South Park, Ancient Egypt Classic, Book of Dead, Gladiator: Road to Rome may also be among the best slots to . try these out Free spins are the most popular bonus option. i was reading this The revenue of a casino is an important factor, as bigger casinos shouldn’t have any issues paying out big wins, while smaller casinos could potentially struggle if you manage to win really big.
    % Bonus up to $ 40X Wager requirements No Max CashOut Games allowed: slots, keno and scratch cards Minimum deposit: $ Slots Capital Casino No Deposit Bonuses EXCLUSIVE $15 No Deposit Bonus Code $2, deposit bonus. All of our Slots games are % free, all day, every day! Free premium casino-style slots and classic video poker by the creators of authentic PC & Mac casino slots from IGT, WMS Gaming, and Bally! Your game will start after this ad. slots of vegas mod apk slot canyon grand staircase slot games for windows 10 casino slot machines apps slot of vegas no deposit

Leave a comment

Your email address will not be published. Required fields are marked *