Tag Archives: ClojureScript

Navigation and Routing with Om and Secretary

After some quick experiments with Secretary and Enfocus, I decided to dive headfirst to Om.

Since I’m kind of restarting my pet project all the time, the first thing I lay down is routing and navigation. This time I’ll implement it by combining Secretary with Om and a little Bootstrap.

One of the key features of Om is strong separation of state from behavior from rendering. In a nutshell, state is defined in one place in an atom and is just, you know, state. You can manipulate it as you like without worrying about rendering. Finally, you install renders on top of it without worrying about the behavior.

Let’s start with a bunch of imports. We’ll need Secretary and goog.History from Closure as well as some Om for rendering. I’ll also keep a reference to History so I don’t instantiate it over and over.

(ns demo.navigation
  (:require [secretary.core :as secretary :include-macros true :refer [defroute]]
            [goog.events :as events]
            [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true])
  (:import goog.History
           goog.History.EventType))

(def history (History.))

Now, the state. Each route has a name that will appear on the navigation bar and path for routing.

(def navigation-state 
  (atom [{:name "Add" :path "/add"}
         {:name "Browse" :path "/browse"}]))

Time for some state manipulation. Enter Secretary and Closure history:

(defroute "/add" [] (js/console.log "Adding"))

(defroute "/browse" [] (js/console.log "Browsing"))

(defn refresh-navigation []
  (let [token (.getToken history)
        set-active (fn [nav]
                     (assoc nav :active (= (:path nav) token)))]
    (swap! navigation-state #(map set-active %))))

(defn on-navigate [event]
  (refresh-navigation)
  (secretary/dispatch! (.-token event)))

(doto history
  (goog.events/listen EventType/NAVIGATE on-navigate)
  (.setEnabled true))

It’s very similar to what I did before – two basic routes, gluing Secretary to Closure history with pretty much the same code that is in Secretary docs.

There’s one thing worth noting here. Every time the route changes, refresh-navigation will update the navigation-state atom. For each of the routes it will set the :active flag, making it true for the path we navigated to and false for all others. This will be used to render the right tab as active.

Now, somewhere in my HTML template I’ll put the div to hold my navigation bar:

<div id="navigation"></div>

Finally, let’s do the rendering in Om:

(defn navigation-item-view [{:keys [active path name]} owner]
  (reify
    om/IRender
    (render [this]
            (dom/li #js {:className (if active "active" "")}
                    (dom/a #js {:href (str "#" path)} name)))))

(defn navigation-view [app owner]
  (reify
    om/IRender
    (render [this]
            (apply dom/ul #js {:className "nav nav-tabs"}
                   (om/build-all navigation-item-view app)))))

(om/root navigation-view navigation-state
         {:target (. js/document (getElementById "navigation"))})

Let’s investigate it from the bottom.

om/root binds a component (navigation-view) to state (navigation-state) and installs it on the navigation element in DOM.

navigation-view itself is a composite (container) component. It creates a <ul class="nav nav-tabs"> containing a navigation-item-view for each route.

Finally, navigation-item-view renders <li class="active"><a href="#{path}">{name}</a></li> using the right pieces of information from the map representing a route.

That’s it. Like I said, state is as pure as it can be, routing doesn’t know anything about rendering, and rendering only cares about state. There is no explicit call to rerender anything anywhere. What’s more, reportedly Om is smart enough to figure out exactly what changed and keep the DOM changes to minimum.

Side note – Om looks like a big thing to learn, especially since I don’t know React. But it’s quite approachable thanks to its incredibly good tutorial. It also made me switch from Eclipse with CounterClockWise to LightTable, giving me more productive fun than I can remember.

ClojureScript Routing and Templating with Secretary and Enfocus

A good while ago I was looking for good ways to do client-side routing and templating in ClojureScript. I investigated using a bunch of JavaScript frameworks from ClojureScript, of which Angular probably gave the most promising results but still felt a bit dirty and heavy. I even implemented my own routing/templating mechanism based on Pedestal and goog.History, but something felt wrong still.

Things have changed and today there’s a lot buzz about React-based libraries like Reagent and Om. I suspect that React on the front with a bunch of “native” ClojureScript libraries may be a better way to go.

Before I get there though, I want to revisit routing and templating. Let’s see how we can marry together two nice libraries: Secretary for routing and Enfocus for templating.

Let’s say our app has two screens which fill the entire page. There are no various “fragments” to compose the page from yet. We want to see one page when we navigate to /#/add and another at /#/browse. The “browse” page will be a little bit more advanced and support path parameters. For example, for /#/browse/Stuff we want to parse the “Stuff” and display a header with this word.

The main HTML could look like:

<!DOCTYPE html>
<html>
<body>
	<div class="container-fluid">
		<div id="view">Loading...</div>
	</div>

	<script src="js/main.js"></script>
</body>
</html>

Then we have two templates.

add.html:

<h1>Add things</h1>
<form>
  <!-- boring, omitted -->
</form>

browse.html:

<h1></h1>
<div>
  <!-- boring, omitted -->
</div>

Now, all we want to do is to fill the #view element on the main page with one of the templates when location changes. The complete code for this is below.

(ns my.main
  (:require [secretary.core :as secretary :include-macros true :refer [defroute]]
            [goog.events :as events]
            [enfocus.core :as ef])
  (:require-macros [enfocus.macros :as em])
  (:import goog.History
           goog.History.EventType))

(em/deftemplate view-add "templates/add.html" [])

(em/deftemplate view-browse "templates/browse.html" [category]
  ["h1"] (ef/content category))

(defroute "/" []
  (.setToken (History.) "/add"))

(defroute "/add" []
  (ef/at 
    ["#view"] (ef/content (view-add))))

(defroute "/browse/:category" [category]
  (ef/at 
    ["#view"] (ef/content (view-browse category))))

(doto (History.)
  (goog.events/listen
    EventType/NAVIGATE 
    #(em/wait-for-load (secretary/dispatch! (.-token %))))
  (.setEnabled true))

What’s going on?

  1. We define two Enfocus templates. view-add is trivial and simply returns the entire template. view-browse is a bit more interesting: Given category name, alter the template by replacing content of h1 tag with the category name.
  2. Then we define Secretary routes to actually use those templates. All they do now is replace content of the #view element with the template. In case of the “browse” route, it passes the category name parsed from path to the template.
  3. There is a default route that redirects from / to /add. It doesn’t lead to example.com/add, but only sets the fragment: example.com/#/add.
  4. Finally, we plug in Secretary to goog.History. I’m not sure why it’s not in the box, but it’s straightforward enough.
  5. Note that in the history handler there is the em/wait-for-load call. It’s necessary for Enfocus if you load templates with AJAX calls.

That’s it, very simple and straightforward.

Update: Fixed placement of em/wait-for-load, many thanks to Adrian!

Clojure on Pedestal

Yesterday I gave a two-hour talk at Lambda Lounge Kraków on Pedestal (and some ClojureScript).

I talked only about the client side, and in that mostly about the dataflow engine and how it connects to rendering and services. We also had some unplanned discussion on testing.

Most of the talk was actually a tutorial, developing a basic monitoring application in a few steps. It probably doesn’t add much over the tutorial, but hopefully it was a faster introduction.

If you’re interested in resources:

Now that I’m on the Internet, I guess I have to explain myself. Yes, I am aware that there are better ways than that jQuery, that I could have created a library for time series, and that it would not run after advanced Closure compilation. It’s not even a perfect Pedestal app. But I think it did the job of explaining the concepts behind Pedestal without drowning the audience in details, using basic pieces that everyone was familiar with. Let’s say that I left ironing out the wrinkles as an exercise.

Despite my lack of experience from my point of view it went fairly well. Always an interesting experience. If you’ve been there, feel free to tell me what you think.

Client-Side Routing with Pedestal

It’s fairly common for rich web applications to use some kind of client-side routing: Load the application once, then navigate with special URLs like http://example.com/#/subpage. Browser doesn’t perform a round trip to server for them, but instead the right chunk of JavaScript can rebuild part of the page locally, hide and show elements etc.

JavaScript tools

There is a number of JavaScript tools to do it. I find two examples particularly inspiring.

Flatiron Director lets you do something like:

var author = function () { console.log("author"); };
var books = function () { console.log("books"); };
 var routes = {
  '/author': author,
  '/books': books
};</p>

<p>var router = Router(routes);
router.init();

Then when you visit page ending with #/books, it will call the books function. Very flexible, but then you need to write a lot of code yourself.

Another good example with completely different philosophy is the Angular JS Router. In your page you can bless a special section as the ngView, and configure router with:

$routeProvider
    .when('/author', {templateUrl: '/t_author.html', controller: "authorController"})
    .when('/books', {templateUrl: '/t_books.html', controller: "booksController"})
    .otherwise({redirectTo: '/books'});

When you go to #/author, Angular will replace the contents of ngView with the template and install the selected controller on it. It fits well in the Angular philosophy and has some benefits.

Pedestal

Anyway, how can we use routing with Pedestal? Turns out there is no built-in or even recommended way to do it, but you can plug in whatever you want. After some research I decided to use goog.History from Closure which comes free of charge with ClojureScript.

All code for these examples is in my GitHub repository. Note that there are 3 tags corresponding to each of the solutions.

Attempt 1: Simple, hardcoded

The first thing I did was a rather ugly, hardcoded solution using the entire Pedestal data flow.

First I installed a listener on goog.History that extracts the location token and pushes it to the :route topic in Pedestal input queue:

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

(defn configure-router 
  ([input-queue] (configure-router input-queue ""))
  ([input-queue default-route]
    (doto (goog.History.)
      (goog.events/listen (goog.object/getValues goog.history/EventType) 
                          (fn [e]
                            (let [token (.-token e)]
                              (if (= "" token)
                                (set-route input-queue default-route)
                                (set-route input-queue token)))))
    (.setEnabled true))))

I plugged in the default transform and emitter that basically push that message up to the application model:

(def count-app {:transform {:route {:init nil :fn #(:value %2)}}
                :emit {:router {:fn app/default-emitter-fn :input #{:route}}}})

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

The last step on the pipeline is renderer. This one here is fairly uninteresting, it basically replaces contents of some specific div with different text:

(defn route-changed [_ [_ _ old-value new-value] input-queue]
  (.log js/console "Routing from" old-value "to" new-value)
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" new-value "</p>"))))

The main function:

(defn ^:export main []
  (let [app (app/build count-app)
        render-fn (push/renderer "content" [[:value [:route] route-changed]])]
    (render/consume-app-model app render-fn)
    (configure-router (:input app) "first")
    (app/begin app)))

This solution is hardly reusable, but it’s also very flexible. At any point we can decide to do something specific when switching the location – change something in data or application model, make a server request, etc.

I wouldn’t recommend it, it’s just the very first attempt at the problem.

Attempt 2: Generic

It’s quite obvious that the above solution can be generalized. One way to do it is to generalize the renderer. We can initialize it with some configuration telling it what action to execute for each path. For instance, something like this:

(defn render-route [msg]
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" msg "</p>"))))

(defn route-first []
  (render-route "This is the first route"))

(defn route-second []
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [old-value new-value]
               (.log js/console "Routing from" old-value "to" new-value))})

There isn’t too much interesting stuff happening here, but it clearly is more reusable.

The renderer is now initialized with this config like:

(defn route-renderer [cfg]
  (fn [_ [_ _ old-value new-value] input-queue]
    (when-let [listener (:listener cfg)]
      (listener old-value new-value))
    (if-let [dispatcher (get-in cfg [:routes new-value])]
      (dispatcher)
      (.log js/console "Unknown route:" new-value))))

I’ll omit the history listener and main for clarity, but I hope the point is clear. Again, code is at Github under the generic tag.

All this solution does is bind a function call to each path. I could easily extract it to a tiny generic library. I could also make it more powerful – for instance, use higher order “constructor functions” that let each action access state or push to the input queue. I could use templating. And so on.

Attempt 3: Generic – light

As I was wrapping that up, I figured out one more way to do it. Remember, both solutions above use the entire Pedestal stack – the history listener pushes a message to input queue, and we need a transform and emitter to pass it up to renderer. Maybe I don’t need to involve the “lower layers” with navigation and rendering?

I realized I can just plug the rendering in the history listener itself:

(defn route-first [input-queue]
  (render-route "This is the first route"))

(defn route-second [input-queue]
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [new-value]
               (.log js/console "Routing to" new-value))})

(defn route-changed [{:keys [input]} route-config]
  (fn [e]
    (let [token (.-token e)
          token (if (= "" token) (:default-route route-config) token)]
      (when-let [listener (:listener cfg)]
        (listener token))
      (if-let [dispatcher (get-in route-config [:routes token])]
        (dispatcher input)
        (.log js/console "Unknown route:" token)))))

(defn configure-router 
  ([app route-config]
    (doto (goog.History.)
      (goog.events/listen 
        (goog.object/getValues goog.history/EventType) 
        (route-changed app route-config))
      (.setEnabled true))))

(defn ^:export main []
  (let [app (app/build)]
    (configure-router app router-config)
    (app/begin app)))

That’s it. It doesn’t even need Pedestal. The router is a generic little thing based only on Google Closure. However, in this case each action also has access to the input queue and it’s pretty obvious how you could expose any other things from Pedestal. You can still push messages to Pedestal, install renderers etc. – but that’s no longer required for routing itself.

Wrapping Up

In the end, I’m fairly satisfied with the last solution. Well, in a way – it still requires me to do a ton of manual work! Not for the routing itself, but for DOM rendering. It feels a lot like jQuery, with tons and tons of tedious, manual DOM manipulation.

I guess I became a little spoilt by Angular, and I’m already experimenting with marrying the two.

All the time I’m facing friction though – if I let Angular do too much, I don’t really have any use for Pedestal. On the other hand, there is quite some impedance mismatch between the Angular “pull-oriented model” and Pedestal’s differential pushes. If I ever come to any sane conclusions on this front I’ll write that up. But that’s another story.

Getting Started with Pedestal on Client Side

I finally got to spend a longer while with Pedestal. It is a pure Clojure web framework, where by pure I mean that you’ll see Clojure on back- as well as front end. For starters I only focused on the front end and that’s what this post is about.

What Is Pedestal?

The documentation is good, but it only explains the fundamental concepts. I think it lacks practical examples and more exhaustive API docs (like inputs and expected outputs of each function, options for each configuration etc.). Or maybe it lacks a tutorial (if I win some time on a lottery, I might write one). There are two good sample applications in their repository: helloworld and chat. Unfortunately, helloworld is very simplistic, and chat is a little bit too complicated for beginners. It does a great job showing off all of the features, but it was a little bit too much for me.

So, after a good while of reading the documentation and reverse engineering the samples, I think I’m finally starting to understand what Pedestal is all about.

On the client side Pedestal is a purely functional, reactive, message-oriented framework. All the state is defined in two pieces: the data model and application model. On the surface each of those models is just a single Clojure map, effectively a tree.

Most of the time you don’t operate on the state directly. You define functions (transforms) that react to messages on specific topics and get current state of data model as argument. They return the new value of the state, and the framework will make it the new data model. Another essential kind of function is emitter: In response to certain messages it emits commands (deltas) to update the application model (like “enable transform”, “disable transform”, “create node”, “set value of node”). Finally, in the application level, you can define functions that change something in the behavior or in DOM in response to those deltas.

Everything goes through this pipeline. If an event happens in GUI, or anywhere in the application, it appends a message to the queue and kicks off all the transforms that bubble up from data model through application model to DOM.

This is a simplistic view that doesn’t do justice to all the features, but I think it’s a good starting point.

Better Sample App for Beginners

During this exploration I wrote another sample application. It’s yet another reincarnation of the TODO app that has a single text entry and a list of everything that has been entered so far. It’s much simpler than the chat demo, and it has plenty of comments explaining what’s going on. This is the kind of application that would help me tremendously during in the learning process, and I hope it saves someone some trouble. You can find the source at Github.

Verdict

My initial verdict of Pedestal? It’s definitely worth a close look! I haven’t built any real apps with it yet, but it looks very promising. It’s a breath of fresh air – I’ve never seen anything similar, especially on the client side with JavaScript. And it feels very appropriate: composed of clean, small, well-defined and isolated pieces with sane flow of information. It appears to lead to much cleaner codebase than JS frameworks like Knockout or Angular with their shared state and dangling functions and callbacks everywhere.

Angular Tutorial Rewritten to ClojureScript

Over the last few months I learned some more ClojureScript and I finally came back to Angular. First I followed their excellent tutorial. Then I decided to rewrite it to plain Clojure and ClojureScript, and it went pretty well.

I made one change on the go – rather than load JSON files directly from disk, it talks to a Ring-provided service.

Raw files are below:

All code is available at GitHub.

It’s almost a one-to-one rewrite from JavaScript. Compared to the original, it is pretty ugly – for two reasons. The first is that I wanted it to work with advanced Closure compiler, so I had to use explicit dependencies. The second is that there is a lot JavaScript interop.

Many of those issues can be mitigated with a glue layer. It is possible to write functions or macros that would automatically generate array syntax for functions with injected dependencies, create functions automatically converting arguments with clj->js, and provide a better replacement for $scope.property = function(...){...}.

I may do that later, but firstly I wanted to have a one-to-one replacement.

ClojureScript Does Not (Always) Need Painkiller

A few weeks ago I shared my confusion about writing object-oriented ClojureScript and a little library called cljs-painkiller. Thanks to the awesome Clojure / ClojureScript community I soon learned much better ways to do it.

Painkiller Example

I complained that I had to write ClojureScript that looks like this:

(defn Bag []
  (this-as this
           (set! (.-store this) (array))
           this))
 
(set! (.. Bag -prototype -add)
      (fn [val]
        (this-as this
                 (.push (.-store this) val))))
 
(set! (.. Bag -prototype -print)
      (fn []
        (this-as this
                 (.log js/console (.-store this)))))
 
(def mybag (Bag.))
(.add mybag 5)
(.add mybag 7)
(.print mybag)

Wrong! Soon after that article appeared on DZone, David Nolen (@swannodette) showed me a few snippets in plain ClojureScript that do the same thing:

(deftype Bag [store]
  Object
  (add [_ x] (.push store x))
  (print [_] (.log js/console store)))

(defn bag [arr] (Bag. arr))
(defn bag [store]
  (reify
    Object
    (add [this x] (.push store x))
    (print [this x] (.log js/console store))))

Much better, isn’t it? And it compiles to fairly idiomatic, interoperable JavaScript, not some higher-level magic.

I am in two minds about the need to expose store like this. One one hand, it makes all the mutable things explicit. On the other, it means you’re exposing much “private” stuff to the consumer, even requiring it from him. To deal with that, you can hide array creation in constructor function:

(defn bag [] (Bag. (array)))
(defn bag []
  (let [store (array)]
    (reify
      Object
      (add [this x] (.push store x))
      (print [this x] (.log js/console store)))))

Backbone Example Revisited

When I was just starting with ClojureScript, I shared an example with Backbone integration. Then I complained it was downright unusable with any less trivial Backbone code.

Here’s what my sample looked like:

(def MyModel
  (.extend Backbone.Model
    (js-obj
      "promptColor"
      (fn []
        (let [ css-color (js/prompt "Please enter a CSS color:")]
          (this-as this
                   (.set this (js-obj "color" css-color))))))))
 
(def my-model (MyModel.))

It turns out it can be rewritten to:

(def MyModel
  (.extend Backbone.Model 
    (reify Object
      (promptColor [this] 
        (let [ css-color (js/prompt "Please enter a CSS color:")]
          (.set this (js-obj "color" css-color)))))))

(def my-model (MyModel.))

Much noise gone. It seems that such reify call is the way to go in this case.

Saved?

I love being proven wrong by the community, and clearly there are better ways to do it than I thought initially. Actually, when I started my adventure with ClojureScript I was quarreling with the compiler – now I finally am beginning to know what I’m doing.

ClojureScript requires some ceremony around object creation, separating behavior from state and its initialization. In some contexts it is too restrictive, in some it’s just fine.

My last example is the Knockout spike where I had JavaScript like this:

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
    this.capitalizeLastName = function() {
        var currentVal = this.lastName();
        this.lastName(currentVal.toUpperCase());
    };
 
}
 
ko.applyBindings(new AppViewModel());

To those unfamiliar with Knockout, firstName etc. are methods. Particularly interesting methods are fullName and capitalizeLastName. Here we have method created by call to ko.computed, wrapping a function that references other methods of this object. Not so bad in an OO language…

… but in ClojureScript apparently the best you can do is what I did back when I was getting started:

(def my-model
  (js-obj
    "firstName" (.observable js/ko "Bert")
    "lastName" (.observable js/ko "Bertington")
    "fullName" (this-as this (.computed js/ko 
                 (fn []  this (.firstName this)), this))))

(.applyBindings js/ko my-model)

I don’t like this at all. This is where I think macros are really necessary. Could be the painkiller, or some special macros just for Knockout integration.

ClojureScript does not always need painkiller, but as your code gets more interesting macroing your way out may be inevitable. I guess you don’t always need to write such OO code, but when you do – be ware.

ClojureScript Painkiller (for OOP)

When I learned and used ClojureScript, I really hated writing code that looks like this:

(defn Bag []
  (this-as this
           (set! (.-store this) (array))
           this))

(set! (.. Bag -prototype -add)
      (fn [val]
        (this-as this
                 (.push (.-store this) val))))

(set! (.. Bag -prototype -print)
      (fn []
        (this-as this
                 (.log js/console (.-store this)))))

(def mybag (Bag.))
(.add mybag 5)
(.add mybag 7)
(.print mybag)

That’s so much ceremony and repeated waste!

I know it’s not how you’re supposed to write ClojureScript, but sometimes you have to (for example when working with OO libraries).

What do you do with such code? Cover it with macros!

So I wrote two little macros that you can just pick up and use right away in your ClojureScript, so that it can look like:

(defn Bag []
  (this-as this
           (set! (.-store this) (array))
           this))

(set-obj-fn Bag.prototype.add [val]
            (.push (.-store this) val))

(set-obj-fn Bag.prototype.print [val]
            (.log js/console (.-store this)))

Or just a this-as shortcut:

(set! (.. Bag -prototype -add)
      (obj-fn [val]
        (.push (.-store this) val)))

Source with complete sample is on github. The library is on Clojars, so to use it all you need is [cljs-painkiller "0.1.0"] in your project.cljs. Enjoy!

Get Started with ClojureScript with Leiningen Templates

When I was about to get started with ClojureScript, I was discouraged by the fact that I apparently had to figure out so much before getting a trivial project up and running.

Eventually I learned, built and showed a minimal application running with just Leiningen and Ring, and a little bit of jQuery in ClojureScript.

Some time later Kyle Cordes showed me cljs-template. It’s a Leiningen template created by Chris Granger, also known as the guy behind Noir and Light Table. That was quite fun. All you need to get a project up and running is:

lein new cljs-template my-project
cd my-project
lein run

That’s it, you’re now running a Noir application with ClojureScript in client (jQuery included). You can start hacking at the CLJS source and see changes in browser immediately.

I soon discovered that it was a few months old, using Clojure 1.3, dated build of ClojureScript and pretty much everything. Eventually (thanks to Kyle and Raynes) I got push access to the project and updated everything, so it should be in even better shape now.

I am not sure where cljs-template is going though, with Noir itself going away. I also found one bit missing: That template is awesome to get up and running and show off a demo, but you would still need to do some manual plumbing to make such a project work for a real application (with leiningen hooks on compilation etc.).

That’s why I created another template: cljs-kickoff. Like my first steps, it’s really minimal: just Ring, lein-cljsbuild and ClojureScript. Fewer files, fewer dependencies, very easy to grasp.

To kick it off, just run:

lein new cljs-kickoff my-project
cd my-project
lein run

It will compile the ClojureScript file included in the project and start Ring server with it.

In another shell, you can run:

lein cljsbuild auto

This will start lein-cljsbuild in the auto-compile mode. Whenever the CLJS source changes, it will be automatically recompiled and the running application will pick it up after reload.

Compared to cljs-template, this template is much smaller and only uses very basic, popular and mature pieces (just Ring and CLJS). It also has all the “real” Leiningen hooks in place: CLJS compilation is included in lein run, lein jar and lein uberjar.

I hope it all makes someone’s life easier by making the first step on CLJS path as easy as possible. Happy hacking!

“ClojureScript Up and Running” (Book Review)

I’ve recently finished the “ClojureScript Up and Running” book by Stuart Sierra and Luke VanderHart. Here’s a quick review of it.

It opens with a quick introduction which attempts to present ClojureScript as the alternative to (or a matured “version” of) JavaScript. Then it immediately dives into gory technical details:

  • It shows how to set up a Leiningen project with lein-cljsbuild and explains the compilation process in detail (with all the possible parameters and modes).
  • It explains the development process – getting ClojureScript, working with browser REPL, testing, packaging for use with CLJS and plain JS applications.
  • It gives a basic introduction to the language, which really is a head-first guide to Clojure (though I suspect it’s far from enough for people who don’t know Clojure, and for those who do know it it’s no use).
  • It explains integration with JavaScript, but mostly on the level of Google Closure – exporting functions and namespaces for the world outside, or using external libraries with Closure advanced compilation.
  • It explains integration with Clojure, especially using EDN as an alternative to JSON.
  • It also introduces a few CLJS libraries (little code, just an idea of what a library does). Among others it includes C2, jayq, enfocus, core.logic, domina. Google Closure is on the list as well.
  •  

    There are many things I missed, though.

    First and foremost, it does not do enough to explain why we need ClojureScript. It does not really try to convince anyone, it’s pretty much a very technical “up and running” guide.

    It does not tell you how to write ClojureScript code. The explanation of setup, compilation and integration is great, but that’s all there is. Actually, there’s little about ClojureScript itself in the book. It’s like (unconvincingly) telling you that Java is the more robust and productive alternative to C++, showing how to use javac and Eclipse, “Hello World”, and a brief indication that there’s also JEE and Swing and this and that. I wish it had some case studies, chunks of actual ClojureScript code, some discussion of architecture, patterns, sample applications…

    One more thing I did not like is that it apparently ignores the JavaScript world (except for Google Closure). There are many rich and mature JavaScript libraries out there that solve many problems, and this book has not a word on the common ways to integrate them. I spent a good while experimenting with CLJS with Backbone, Knockout, Angular and jQuery, and it’s quite a difficult, frustrating task. I know I can write a CLJS library to do the same things that Knockout does, but I would prefer to learn how to integrate the existing library with my CLJS application to solve a real problem, or be introduced to a pure CLJS alternative that someone has already created.

    Perhaps it reflects the current state of ClojureScript – not yet very mature or stable, without mature and established libraries, patterns.

    All in all, I have mixed feelings. The book is very dense and concrete, and delivers much content on so few pages. It’s true to its title – gets you up and running, and does it very well. But then immediately leaves you alone in the woods. We are yet to see “The ClojureScript Book”.