Escherize (take (bake cake))

Quickstart Boot and ClojureScript

Why Clojurescript?

Clojurescript (cljs) is the most highly interactive way to do front-end development that I’m aware of. Quick feedback helps enormously when you’re not the kind of programmer who likes to ‘play computer’ in their head. If you’d like a deeper explanation for why cljs is so awesome (and it is), check out Clojurescript for skeptics:

Dive In

In this post we’ll go through the steps necessary to setup a live-reloadable cljs project!

Boot Kitty

Boot lets us easily setup our project scaffolding, with a live-reloader for dev mode, and painlessly deploy our Clojurescript code when it’s good to go.

Boot Time

You should have java 8 and boot installed. If you’re on Mac, you can brew install boot-clj. Otherwise check here!

Now with boot installed, we’ll get an app up and running using the Tenzing app template, with the +reagent option, and name it: escherize-cljs. :)

boot -d seancorfield/boot-new new \
     -t tenzing \
     -a +reagent \
     -n escherize-cljs
cd escherize-cljs

Here’s what a tree in that directory reveals:

tree
.
├── boot.properties
├── build.boot
├── resources
│   ├── index.html
│   └── js
│       └── app.cljs.edn
└── src
└── cljs
└── escherize_cljs
└── app.cljs

5 directories, 5 files

Everything we care about for now is in app.cljs. So let’s take a look:

(ns escherize-cljs.app
  (:require [reagent.core :as reagent
             :refer [atom]]))

(defn some-component []
  [:div
   [:h3 "I am a component!"]
   [:p.someclass
    "I have " [:strong "bold"]
    [:span {:style {:color "red"}} " and red"]
    " text."]])

(defn calling-component []
  [:div "Parent component"
   [some-component]])

(defn init []
  (reagent/render-component
   [calling-component]
   (.getElementById js/document "container")))

Ahh, at last some beautiful Hiccup flavored Reagent. You might be able to guess what kind of html that will output. Notice that we’re using calling-component to generate a data structure that our app (and Reagent) will turn into React.js components.

Let’s see the output already! Go to your project’s root directory (where build.boot is), and run:

boot dev

Your computer fans will probably spin up, as it takes some work to do the first compile of cljs->js. Next you’ll hear a DING which means “Hey, I compiled your cljs without an errors!”. Now open http://localhost:3000. And behold:

Sweet Justice

Feel free to right-click -> Inspect Element to see the html’s source. But the sexiest thing about the current setup is that the live-reload is actually currently working!

To try it out, let’s change some code in some-component.

(defn some-component []
  [:div
   [:h3 "I am a component!"]

   ;;; \/ \/ \/ Attention - Add this
   [:img {:src "http://45.media.tumblr.com/aa7e769f34261486bfb0e371d88268ee/tumblr_nghxngNY741rrx588o1_250.gif"}]
   [:h3 "I am a super hero!"]
   ;;; /\ /\ /\ Attention - Add this

   [:p.someclass
    "I have " [:strong "bold"]
    [:span {:style {:color "red"}} " and red"]
    " text."]])

You’ll hear DING, (or BUZZ if you typed something wrong), and your page will update automatically! Like OMG!

You really are a super hero, with live-refresh magically working!

Next Steps

You can now make changes to app.cljs, and see (and hear!!) the output. I’d recommend going through these Reagent Examples and re-implementing the examples work there. Another excellent resource is The Reagent Cookbook which has a bunch of interesting patterns like implementing drag and drop, google maps, etc.

Publishing to Production

With the way our system is setup, we just need to navigate to the project root, and call:

boot build

Now the escherize-cljs/target directory fully baked and is ready to host!

Diving Deeper

Clojurescript is a compiler. It compiles Clojurescript into JavaScript. The cljs compiler has multiple options for how to output JavaScript. A key option is :optimizations, which can be set to :none (for dev) or :advanced (for production) you can see this happening if you have the courage to peer into build.boot, where it takes place for you automatically using :none for boot dev and :advanced for boot build. Think of it as output hyper-minimization, because it uses a lot of fancy tricks to hyper-minify.

Thanks to:

Discuss on HN