Datascript and React.js for a Clojure web app30 Apr 2014
When building a web application with Clojure there are a lot of building blocks to choose from. For ClojureScript there has been a particularly interesting new offer with the release of Datascript. Datascript is a way to manage application state in ClojureScript following the database properties of Datomic (although not related to that project in any way). Together with React.js to handle the rendering of the user interface, this is a nice way to build dynamic, data-driven browser front-ends. It also fits in nicely with an example todo list application I have been working on.
Datascript is an immutable uniform state management solution, as explained by its author. The most difficult part of state management in ClojureScript apps for me was how to notify components of changes in the state. Clojure's standard reference types for state management such as refs, atoms and agents can nofity listeners of changes through watchers. Watchers include the old state and the new state, but I always found it difficult to derive from this what the actual change was, and why this change was made. Datascript is a nice improvement over this by providing the listen! functionality, that provides a transaction report for all changes to the state.
Front ends in browsers have always at least two components that need to read and write to the state and be notified of changes: the user interface components and the part that communicates with the back end. With Datascript these parts can be kept completely independent.
Of course, rendering a user interface based on a new state is what React.js is made for. Quiescent is ClojureScipt wrapper library around React.js that does rendering, without making any assumptions on how the state is managed. This makes it very nice to combine with Datascript.
Clojure web development
Recently I have been working on getting together a complete Clojure web application. Web development in Clojure is done by composing libraries. This works great for building web services in a controlled environment. But for building user facing web applications it is not apparent how these libraries should be composed. Great Clojure web applications exists, but sadly none of these are open source, which means that many developers need to repeat the struggle of trying to fit the libraries from the Clojure web ecosystem together. It is difficult to address the many details of a user facing web application when the details impact the many tiny libraries you use. This has been highlighted recently for the security aspect of Clojure web applications by Aaron Bedra, as summarized here.
Clj-crud as an example
Clj-crud is meant to be relatively feature complete example of a Clojure web application. A web application is defined here as a database backed website that can runs on Heroku, with a login system, an admin section, uses Bootstrap templates, has a ClojureScript front-end and supports repl-based development and has acceptance tests.
The libraries used in clj-crud are:
- Stuart Sierra's Component
- Liberator, for the common web request flow
- Enlive, for templating
- Friend, for authentication and authorization
- ring & compojure
- Kerodon/Peridot, for testing
A stand-alone demo of just the TodoMVC part with Datascript and React.js/Quiescent is here.
The front-end code is split up in Datascript transactions, the Quiescent rendering and client-server communications. Compilation of the ClojureScript requires a checkout of the Datascript library that includes support for transaction functions.
The back-end code is structured to use components. Most of the other code is to make all the libraries work together. This allows functionality to be written like this: todos request handling and todos database access.