When I started with ClojureScript and tried to follow the official Quick Start Guide it did not seem very straightforward to me. It is a good read though after a bit of hands on experience. This guide is a compilation of things I wished to know at the beginnings.
⚠ DISCLAIMER
I wrote down these notes as I was learning Clojure/Script in 2017. The tooling ecosystem changed significantly since then, but I did not manage to update the guide to reflect that. Here is the gist:
- Clojure CLI is a better alternative to Leiningen
- shadow-cljs is the best tool to compile ClojureScript replacing Fighweel, both for web and node.js apps
- Babashka is a best runtime for scripting instead of Lumo
Try out some code using REPL.
Under node.js install Lumo with:
$ npm install -g lumo-cljs
$ lumo
cljs.user=> (println "hello clojure")
hello clojure
For Java first install Leiningen and then:
$ lein repl
user=> (+ 1 2)
3
Use cljs-node-app template:
lein new cljs-node-app <project-name>
Compile the project: lein cljsbuild once main
Watch and recompile on changes: lein cljsbuild auto main
Use re-frame template which uses React.js via Reagent under the hood:
lein new re-frame <project-name> +test +routes +aliases
Start development mode with live reload: lein dev
Compile the project: lein build
Inside REPL:
;; Show function docs in REPL
(doc str)
;; Search in docs
(find-doc "reduce")
;; Show function source code
(source identity)
Browse API documentation and refer to Cheatsheet on the web.
- Official Clojure Reference
- Library Coding Standards
- Clojure Styleguide
- clojure-doc.org is community-driven documentation
- Anki deck for spaced-repetition learning
- Learn Clojure in Y minutes is a very concise indroduction to Clojure.
- ClojureScript Unraveled is an online book and guide about ClojureScript.
- Brave Clojure – Chapter 3 Crash Course Clojure for the Brave and True is a book available online. I find chapter 3 a very good intro to Clojure. If you like more chatty style and humor in programming books then also give a read to other chapters.
- Clojure – Functional Programming for the JVM is an introductory article to functional programming and Clojure. It is aimed for Java programmers but contains interesting bits of information and goes into more low-level details.
- Clojure from the ground up is a collection of articles on various Clojure topics.
- Programming Clojure by Stuart Halloway is a best book about Clojure for programmers, I recommend anyone learning Clojure(Script) to start with this one.
- Clojure Applied: From Practice to Practitioner is a book focusing on more practical aspects of app development in Clojure. Includes chapters about domain modelling, managing state and application components.
- Mastering Clojure describes in detail more advanced topics like paralelism, transducers, category theory, pattern matching and logic programming.
Explore other books by the community.
Opinionated list of useful libraries. There are alternatives but if you are just starting you can't go wrong by picking these.
Frontend
- React wrapper framework: re-frame
- UI Components: re-com
- Forms with validation: Reforms
- HTTP requests: cljs-ajax
- Routing: Secretary
- Date, Url and other utilities: Google Closure Library
Check other libraries in Awesome ClojureScript list.
Backend
A great feature of ClojureScript is that you can work with native JS objects and use existing JS libraries.
;; Use js/ prefix for global names, e.g. to print in browser console
(js/console.log "Hello, world!")
;; Add dot to construct new objects
(js/Date. "2017-10-16") ; new Date("2017-10-16")
;; Call methods
(.toUpperCase s) ; s.toUpperCase()
;; Use treading macro to chain calls
(-> "BOOM" (.toLowerCase) (.slice 0 -1)) ; "BOOM".toLowerCase().slice(0, -1)
;; Access attributes
(.-length s) ; s.length
;; Nested attribute access
(.-location.href js/window) ; window.location.href
(aget window "location" "href") ; window["location"]["href"]
;; Set attributes
(aset obj "attr" "val") ; obj["attr"] = "val"
;; create native js objects with #js macro
#js {:a 1 :b 2} ; {a: 1, b: 2}
#js [1 2 3] ; [1, 2, 3]
;; convert cljs data structures into js objects
(clj->js obj)
;; convert js objects to cljs data structures
(js->clj obj :keywordize-keys true))
See a post with more details and comparison of JS and Clojure idioms.
Use node modules by seamlessly requiring them (starting with 1.9.854):
(ns example.core
(:require [react :refer [createElement]]
["react-dom/server" :as ReactDOMServer :refer [renderToString]]))
(js/console.log (renderToString (createElement "div" nil "Hello World!")))
Some js libraries do not work with the compiler. In that case it is possible to bundle them with webpack. Or use externs: https://code.thheller.com/blog/shadow-cljs/2017/10/15/externs-the-bane-of-every-release-build.html Debug advanced compilation errors with :pseudo-names. Also try :infer-externs.
To print at ClojureScript REPL
(println "Hello, world!")
Working with filesystem – require fs
from node and call native functions.
(def fs (js/require "fs"))
(fs.readFileSync "foo.txt" "utf8")
When working in repl you can use slurp
to read a file and spit
to write a file.
;; Read a file into one long string
(def a-long-string (slurp "foo.txt"))
;; Write a long string out to a new file
(spit "foo.txt"
"A long
multi-line string.
Bye.")
Alternative approach is to use cljs-node-io which is a port of clojure.java.io.
EDN is to Clojure what JSON is to Javascript.
- parse: cljs.reader/read-string
- stringify: prn-str
A state is the value of an identity at a point in time.
Changes to shared state:
- Refs - coordinated synchronous
- Atoms - uncoordinated synchronous
- Agents - asynchronous
- Vars - thread-local private - def, defn
Convention dynamic thread-wide bindings with asterisks *in*
*out*
.
Refer to this guide for a good setup. Essential packages are:
- parinfer so that you don't have to worry about parentheses
- proto-repl to evaluate code right within editor window
- Emacs distribution with Vim mode
- Looks intriguing, it's on my list of things to try
- Plugin for code refactoring: clj-refactor
- a great IDE based on IntelliJ
Debug with Chrome DevTools
- Enable custom formatters
- Data formating is done with cljs-devtools which is already included in the web app template mentioned above
- Add expressions to watches like:
cljs.core.pr_str(localvar)
For more functionality use Dirac, a DevTools fork with additional ClojureScript related features.
Debug node apps with Chrome DevTools
- Run
node --inspect-brk build/main.js
- In Chrome open
chrome://inspect
and select the session
Call tracing inside Atom
Use proto-repl: save call
to record function calls and values of parameters, watch video with instructions.
General call tracing
Trace calls with Clairvoyant which is an alternative to clojure.tools.trace.
To use Leiningen plugins globally across projects put them in ~/.lein/profiles.clj
, e.g.
{:user {:plugins [[lein-ancient "0.6.5"]
[lein-plz "0.4.0-SNAPSHOT" :exclusions [[rewrite-clj] [ancient-clj]]]]}}
Packages management
lein search <pkg-name>
– Search for packageslein plz add <pkg-name>
– Add package as dependency intoproject.clj
lein ancient
– List outdated dependencieslein ancient upgrade
– Upgrade outdated dependencies- lein try – Try out Clojure libraries in a REPL without creating a project or adding them to an existing project.
Code quality
- kibit – static analysis tool that offers suggestions for code improvement
- cljfmt or lein-zprint or boot-fmt for code auto-formatting
- cloverage – Test code coverage tool
- vanity - Compute Lines of code statistics
- Overview of code quality tools
Code exploration
- lein-ns-dep-graph or lein-hiera – Explore and visualize namespace dependencies
- lein-gossip or clj-usage-graph – Visualize call-graphs in a codebase
- lein-instant-cheatsheet – Instant Cheatsheet instantly creates a cheatsheet for your project and its dependencies
Documentation generators
Recommended:
- cljdoc – documentation generator, includes hosting
- codeina – api doc generator which is a nicer looking fork of codox
- codox – with support for plugins and themes
- marginalia – documentation showing description and code side by side in a literate programming style
Others:
- autodoc – generator that is used for official Clojure API docs
- cadastre – extracts metadata in a way that is used on clojuredocs.org
CrossClj – Explore dependencies of Clojure packages among each other, see which function are called where and with what arguments:
JavaScript to ClojureScript translator
Bootstrapping:
- calvin – A minimalistic build tool for ClojureScript projects that does not require the JVM
- with Lumo
Articles about Lisp and Functional Programming:
- https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f
- http://www.paulgraham.com/icad.html
- https://funcall.blogspot.cz/2009/03/not-lisp-again.html
- http://calculist.org/blog/2012/04/17/homoiconicity-isnt-the-point/
- http://www.michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/
- http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html
- http://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf