View deps.edn

Code Splitting

NOTE: This gist uses the master branch of ClojureScript. Clone ClojureScript and from the checkout run ./script/bootstrap and ./script/uberjar. This will produce target/cljs.jar which you can use to follow this guide.

As client applications become larger it becomes desirable to load only the code actually required to run a particular logical screen. Previously ClojureScript :modules compiler option permitted such code splitting, but this feature only worked under :advanced compilation and users would still have to manage loading these splits. :modules also required manual

View test.cljs
(ns async-test.core
(:require-macros [cljs.core.async.macros :as async])
(:require [cljs.core.async :as async]))
(defn looper [ch handler-fn]
(async/go-loop []
(handler-fn (async/<! ch))

Externs Inference

Integrating third party JavaScript libraries not written with Google Closure Compiler in mind continues to both be a source of error for users when going to production, and significant vigilance and effort for the the broader community (CLJSJS libraries must provide up-to-date and accurate externs).

In truth writing externs is far simpler than most users imagine. You only need externs for the parts of the library you actually intend to use from ClojureScript. However this isn't so easy to determine from Closure's own documentation. Still in the process of writing your code it's easy to miss a case. In production you will see the much dreaded error that some mangled name does not exist. Fortunately it's possible to enable some compiler flags :pretty-print true :pseudo-names true to generate an advanced build with human readable names. However debugging missing externs means compiling your production build for each missed case. So much time wasted for such simple mistakes damages our sen

View figwheel_client_socket_repl.clj
(require 'tubular.core)
(tubular.core/connect "" REPL_PORT)
View spec2.cljs
(:require [cljs.spec :as s]
[clojure.test.check :as tc]
[ :as tcp]))
(s/def ::statics
:static '#{static}
:protocol-name '#{}
:impls (s/* seq?)))
View spec.cljs
(:require [cljs.spec :as s]))
(s/def ::ident (s/and vector? (s/cat :ident keyword? :value #(not (coll? %)))))
(s/def ::join-key (s/or :prop keyword? :ident ::ident))
(s/def ::join (s/and (s/map-of ::join-key ::query) #(= (count %) 1)))
(s/def ::union (s/and (s/map-of keyword? ::query) #(> (count %) 1)))
(s/def ::param-expr
(s/cat :query-expr ::query-expr
View socket-repl.clj
(ns socket-repl-test.core
(:require [cljs.repl :as repl]
[cljs.repl.node :as node]
[clojure.core.server :as server]))
(defn node-repl []
(repl/repl (node/repl-env)))
(defn cljs-repl-server []
View closure.js
var ArrayList =,
File =,
jscomp =,
SourceFile = jscomp.SourceFile,
BasicErrorManager = jscomp.BasicErrorManager,
DepsGenerator = jscomp.deps.DepsGenerator,
InclusionStrategy = DepsGenerator.InclusionStrategy;
function jsFilesInDir(dir) {
var ret = new ArrayList(),
View check.cljs
(defn my-get
"@param {*} m
@param {*} k
@return {nil|Object}"
[m k]
(get m k))
(defn foo
"@param {!Object} x" ;; non-nullable
[x] x)