└── README.md /README.md: -------------------------------------------------------------------------------- 1 | 2 | # The Missing Guide for ClojureScript 3 | 4 | When I started with ClojureScript and tried to follow the official [Quick Start Guide](https://clojurescript.org/guides/quick-start) 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. 5 | 6 | > ⚠ **DISCLAIMER** 7 | > 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: 8 | > * [Clojure CLI](https://clojure.org/guides/deps_and_cli) is a better alternative to Leiningen 9 | > * [shadow-cljs](https://github.com/thheller/shadow-cljs) is the best tool to compile ClojureScript replacing Fighweel, both for web and node.js apps 10 | > * [Babashka](https://github.com/babashka/babashka) is a best runtime for scripting instead of Lumo 11 | 12 | 13 | 14 | - [Quick Start](#quick-start) 15 | - [Create a project](#create-a-project) 16 | - [Documentation](#documentation) 17 | - [Resources](#resources) 18 | - [Tutorials](#tutorials) 19 | - [Books](#books) 20 | - [Exercises](#exercises) 21 | - [Cookbook](#cookbook) 22 | - [Libraries](#libraries) 23 | - [JS Interop](#js-interop) 24 | - [IO](#io) 25 | - [EDN](#edn) 26 | - [Editor setup](#editor-setup) 27 | - [Debugging](#debugging) 28 | - [Tools](#tools) 29 | - [Misc](#misc) 30 | 31 | 32 | 33 | ## Quick Start 34 | 35 | Try out some code using REPL. 36 | 37 | Under node.js install [Lumo](https://github.com/anmonteiro/lumo) with: 38 | ``` 39 | $ npm install -g lumo-cljs 40 | $ lumo 41 | cljs.user=> (println "hello clojure") 42 | hello clojure 43 | ``` 44 | 45 | For Java first install [Leiningen](https://leiningen.org/) and then: 46 | ``` 47 | $ lein repl 48 | user=> (+ 1 2) 49 | 3 50 | ``` 51 | 52 | ### Create a project 53 | 54 | #### Node.js server or CLI app 55 | 56 | Use [cljs-node-app](https://github.com/yanatan16/cljs-node-app-template) template: 57 | `lein new cljs-node-app ` 58 | 59 | Compile the project: `lein cljsbuild once main` 60 | 61 | Watch and recompile on changes: `lein cljsbuild auto main` 62 | 63 | #### Web app 64 | 65 | Use [re-frame](https://github.com/Day8/re-frame-template) template which uses React.js via [Reagent](https://github.com/reagent-project/reagent) under the hood: 66 | `lein new re-frame +test +routes +aliases` 67 | 68 | Start development mode with live reload: `lein dev` 69 | 70 | Compile the project: `lein build` 71 | 72 | ## Documentation 73 | 74 | Inside REPL: 75 | 76 | ```clojure 77 | ;; Show function docs in REPL 78 | (doc str) 79 | 80 | ;; Search in docs 81 | (find-doc "reduce") 82 | 83 | ;; Show function source code 84 | (source identity) 85 | ``` 86 | 87 | Browse [API documentation](https://clojuredocs.org/quickref) and refer to [Cheatsheet](http://clojure.org/cheatsheet) on the web. 88 | 89 | ## Resources 90 | 91 | - [Official Clojure Reference](https://clojure.org/reference/reader) 92 | - [Library Coding Standards](https://dev.clojure.org/display/community/Library+Coding+Standards) 93 | - [Clojure Styleguide](https://github.com/bbatsov/clojure-style-guide) 94 | - [clojure-doc.org](http://clojure-doc.org/articles/content.html) is community-driven documentation 95 | - [Anki deck](https://ankiweb.net/shared/info/3248915342) for spaced-repetition learning 96 | 97 | ### Tutorials 98 | 99 | - [Learn Clojure in Y minutes](http://learnxinyminutes.com/docs/clojure/) is a very concise indroduction to Clojure. 100 | - [ClojureScript Unraveled](http://funcool.github.io/clojurescript-unraveled/) is an online book and guide about ClojureScript. 101 | - [Brave Clojure – Chapter 3 Crash Course](http://www.braveclojure.com/do-things/) 102 | 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. 103 | - [Clojure – Functional Programming for the JVM](http://java.ociweb.com/mark/clojure/article.html) 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. 104 | - [Clojure from the ground up](https://aphyr.com/tags/Clojure-from-the-ground-up) is a collection of articles on various Clojure topics. 105 | 106 | ### Books 107 | 108 | - [Programming Clojure by Stuart Halloway](https://www.amazon.com/dp/1934356867) is a best book about Clojure for programmers, I recommend anyone learning Clojure(Script) to start with this one. 109 | - [Clojure Applied: From Practice to Practitioner](https://www.amazon.com/dp/1680500740) is a book focusing on more practical aspects of app development in Clojure. Includes chapters about domain modelling, managing state and application components. 110 | - [Mastering Clojure](https://www.amazon.com/dp/B017XSFL4Q/) describes in detail more advanced topics like paralelism, transducers, category theory, pattern matching and logic programming. 111 | 112 | Explore other [books](https://clojure.org/community/books) by the community. 113 | 114 | ### Exercises 115 | 116 | - [99 Lisp Problems](http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html) 117 | - [4Clojure](http://www.4clojure.com/problems) 118 | - [Clojure Koans](http://clojurekoans.com/) 119 | - [Project Euler Problems](https://projecteuler.net/archives) 120 | - [Simple Programming Problems](https://adriann.github.io/programming_problems.html) 121 | 122 | ## Cookbook 123 | 124 | ### Libraries 125 | 126 | Opinionated list of useful libraries. There are alternatives but if you are just starting you can't go wrong by picking these. 127 | 128 | **Frontend** 129 | - React wrapper framework: [re-frame](https://github.com/Day8/re-frame) 130 | - UI Components: [re-com](https://github.com/Day8/re-com) 131 | - Forms with validation: [Reforms](https://github.com/bilus/reforms) 132 | - HTTP requests: [cljs-ajax](https://github.com/JulianBirch/cljs-ajax) 133 | - Routing: [Secretary](https://github.com/gf3/secretary) 134 | - Date, Url and other utilities: [Google Closure Library](https://google.github.io/closure-library/api/goog.html) 135 | 136 | Check other libraries in [Awesome ClojureScript list](https://github.com/hantuzun/awesome-clojurescript). 137 | 138 | **Backend** 139 | - HTTP APIs: [Compojure](https://github.com/metosin/compojure-api) 140 | - Logging: [Timbre](https://github.com/ptaoussanis/timbre) 141 | 142 | ### JS Interop 143 | 144 | A great feature of ClojureScript is that you can work with native JS objects and use existing JS libraries. 145 | 146 | ```clojure 147 | ;; Use js/ prefix for global names, e.g. to print in browser console 148 | (js/console.log "Hello, world!") 149 | 150 | ;; Add dot to construct new objects 151 | (js/Date. "2017-10-16") ; new Date("2017-10-16") 152 | 153 | ;; Call methods 154 | (.toUpperCase s) ; s.toUpperCase() 155 | 156 | ;; Use treading macro to chain calls 157 | (-> "BOOM" (.toLowerCase) (.slice 0 -1)) ; "BOOM".toLowerCase().slice(0, -1) 158 | 159 | ;; Access attributes 160 | (.-length s) ; s.length 161 | 162 | ;; Nested attribute access 163 | (.-location.href js/window) ; window.location.href 164 | (aget window "location" "href") ; window["location"]["href"] 165 | 166 | ;; Set attributes 167 | (aset obj "attr" "val") ; obj["attr"] = "val" 168 | 169 | ;; create native js objects with #js macro 170 | #js {:a 1 :b 2} ; {a: 1, b: 2} 171 | #js [1 2 3] ; [1, 2, 3] 172 | 173 | ;; convert cljs data structures into js objects 174 | (clj->js obj) 175 | 176 | ;; convert js objects to cljs data structures 177 | (js->clj obj :keywordize-keys true)) 178 | ``` 179 | 180 | See a [post with more details](http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/) and [comparison of JS and Clojure](https://kanaka.github.io/clojurescript/web/synonym.html) idioms. 181 | 182 | 183 | Use node modules by [seamlessly requiring](https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules) them (starting with 1.9.854): 184 | ```clojure 185 | (ns example.core 186 | (:require [react :refer [createElement]] 187 | ["react-dom/server" :as ReactDOMServer :refer [renderToString]])) 188 | 189 | (js/console.log (renderToString (createElement "div" nil "Hello World!"))) 190 | ``` 191 | 192 | Some js libraries do not work with the compiler. In that case it is possible to bundle them with [webpack](https://github.com/roman01la/cljs-reagent-webpack). 193 | Or use externs: https://code.thheller.com/blog/shadow-cljs/2017/10/15/externs-the-bane-of-every-release-build.html 194 | Debug advanced compilation errors with [:pseudo-names](https://clojurescript.org/reference/compiler-options#pseudo-names). Also try [:infer-externs](https://clojurescript.org/reference/compiler-options#infer-externs). 195 | 196 | ### IO 197 | 198 | To print at ClojureScript REPL 199 | ```clojure 200 | (println "Hello, world!") 201 | ``` 202 | 203 | Working with filesystem – require `fs` from node and call native functions. 204 | ```clojure 205 | (def fs (js/require "fs")) 206 | (fs.readFileSync "foo.txt" "utf8") 207 | ``` 208 | 209 | When working in repl you can use `slurp` to read a file and `spit` to write a file. 210 | ```clojure 211 | ;; Read a file into one long string 212 | (def a-long-string (slurp "foo.txt")) 213 | 214 | ;; Write a long string out to a new file 215 | (spit "foo.txt" 216 | "A long 217 | multi-line string. 218 | Bye.") 219 | ``` 220 | 221 | Alternative approach is to use [cljs-node-io](https://github.com/pkpkpk/cljs-node-io) which is a port of [clojure.java.io](http://clojure-doc.org/articles/cookbooks/files_and_directories.html). 222 | 223 | ### EDN 224 | 225 | EDN is to Clojure what JSON is to Javascript. 226 | 227 | - parse: [cljs.reader/read-string](https://cljs.github.io/api/cljs.reader/read-string) 228 | - stringify: [prn-str](http://cljs.github.io/api/cljs.core/prn-str) 229 | 230 | ### State 231 | 232 | A state is the value of an identity at a point in time. 233 | 234 | Changes to shared state: 235 | - Refs - coordinated synchronous 236 | - Atoms - uncoordinated synchronous 237 | - Agents - asynchronous 238 | - Vars - thread-local private - def, defn 239 | 240 | Convention dynamic thread-wide bindings with asterisks `*in*` `*out*`. 241 | 242 | ## Editor setup 243 | 244 | **[Atom](https://atom.io)** 245 | 246 | Refer to [this guide](https://gist.github.com/jasongilman/d1f70507bed021b48625) for a good setup. Essential packages are: 247 | - [parinfer](https://atom.io/packages/parinfer) so that you don't have to worry about parentheses 248 | - [proto-repl](https://atom.io/packages/proto-repl) to evaluate code right within editor window 249 | 250 | **[Spacemacs](http://spacemacs.org/)** 251 | - Emacs distribution with Vim mode 252 | - Looks intriguing, it's on my list of things to try 253 | - Plugin for code refactoring: [clj-refactor](https://github.com/clojure-emacs/clj-refactor.el/wiki) 254 | 255 | **[Cursive](https://cursive-ide.com/)** 256 | - a great IDE based on IntelliJ 257 | 258 | 259 | ## Debugging 260 | 261 | **Debug with Chrome DevTools** 262 | 263 | - [Enable custom formatters](https://github.com/binaryage/cljs-devtools/blob/master/docs/installation.md#enable-custom-formatters-in-chrome) 264 | - Data formating is done with [cljs-devtools](https://github.com/binaryage/cljs-devtools) which is already included in the [web app template](#web-app) mentioned above 265 | - Add expressions to watches like: `cljs.core.pr_str(localvar)` 266 | 267 | For more functionality use [Dirac](https://github.com/binaryage/dirac), a DevTools fork with additional ClojureScript related features. 268 | 269 | **Debug node apps with Chrome DevTools** 270 | - Run `node --inspect-brk build/main.js` 271 | - In Chrome open `chrome://inspect` and select the session 272 | 273 | **Call tracing inside Atom** 274 | 275 | Use `proto-repl: save call` to record function calls and values of parameters, watch [video with instructions](https://youtu.be/buPPGxOnBnk?t=11m55s). 276 | 277 | **General call tracing** 278 | 279 | Trace calls with [Clairvoyant](https://github.com/spellhouse/clairvoyant) which is an alternative to [clojure.tools.trace](https://github.com/clojure/tools.trace). 280 | 281 | ## Tools 282 | 283 | To use Leiningen plugins globally across projects put them in `~/.lein/profiles.clj`, e.g. 284 | ```clojure 285 | {:user {:plugins [[lein-ancient "0.6.5"] 286 | [lein-plz "0.4.0-SNAPSHOT" :exclusions [[rewrite-clj] [ancient-clj]]]]}} 287 | ``` 288 | 289 | [List of Leiningen plugins](https://github.com/technomancy/leiningen/wiki/Plugins) 290 | 291 | **Packages management** 292 | - `lein search ` – Search for packages 293 | - `lein plz add ` – Add package as dependency into `project.clj` 294 | - `lein ancient` – List outdated dependencies 295 | - `lein ancient upgrade` – Upgrade outdated dependencies 296 | - [lein try](https://github.com/rkneufeld/lein-try) – Try out Clojure libraries in a REPL without creating a project or adding them to an existing project. 297 | 298 | **Code quality** 299 | - [kibit](https://github.com/jonase/kibit) – static analysis tool that offers suggestions for code improvement 300 | - [cljfmt](https://github.com/weavejester/cljfmt) or [lein-zprint](https://github.com/kkinnear/lein-zprint) or [boot-fmt](https://github.com/pesterhazy/boot-fmt) for code auto-formatting 301 | - [cloverage](https://github.com/cloverage/cloverage) – Test code coverage tool 302 | - [vanity](https://github.com/dgtized/lein-vanity) - Compute Lines of code statistics 303 | - [Overview of code quality tools](https://blog.jeaye.com/2017/08/31/clojure-code-quality/) 304 | 305 | **Code exploration** 306 | - [lein-ns-dep-graph](https://github.com/hilverd/lein-ns-dep-graph) or [lein-hiera](https://github.com/greglook/lein-hiera) – Explore and visualize namespace dependencies 307 | - [lein-gossip](https://github.com/actsasgeek/lein-gossip) or [clj-usage-graph](https://github.com/gfredericks/clj-usage-graph) – Visualize call-graphs in a codebase 308 | - [lein-instant-cheatsheet](https://github.com/cammsaul/lein-instant-cheatsheet) – Instant Cheatsheet instantly creates a cheatsheet for your project and its dependencies 309 | 310 | **Documentation generators** 311 | 312 | Recommended: 313 | - [cljdoc](https://cljdoc.xyz/) – documentation generator, includes hosting 314 | - [codeina](https://github.com/funcool/codeina) – api doc generator which is a nicer looking fork of codox 315 | - [codox](https://github.com/weavejester/codox) – with support for plugins and themes 316 | - [codox-md](https://github.com/hugoduncan/codox-md) 317 | - [marginalia](https://github.com/gdeer81/lein-marginalia) – documentation showing description and code side by side in a literate programming style 318 | 319 | Others: 320 | - [autodoc](https://github.com/tomfaulhaber/lein-autodoc) – generator that is used for official Clojure API docs 321 | - [cadastre](https://github.com/dakrone/cadastre) – extracts metadata in a way that is used on [clojuredocs.org](http://clojuredocs.org/) 322 | 323 | ## Misc 324 | 325 | [CrossClj](https://crossclj.info/) – Explore dependencies of Clojure packages among each other, see which function are called where and with what arguments: 326 | 327 | [JavaScript to ClojureScript translator](https://github.com/roman01la/javascript-to-clojurescript) 328 | 329 | 330 | Bootstrapping: 331 | - [calvin](https://github.com/eginez/calvin) – A minimalistic build tool for ClojureScript projects that does not require the JVM 332 | - [with Lumo](https://anmonteiro.com/2017/02/compiling-clojurescript-projects-without-the-jvm/) 333 | 334 | Articles about Lisp and Functional Programming: 335 | - https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f 336 | - http://www.paulgraham.com/icad.html 337 | - https://funcall.blogspot.cz/2009/03/not-lisp-again.html 338 | - http://calculist.org/blog/2012/04/17/homoiconicity-isnt-the-point/ 339 | - http://www.michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/ 340 | - http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html 341 | - http://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf 342 | --------------------------------------------------------------------------------