|
| 1 | += 1.12.108 Release |
| 2 | +ClojureScript Team |
| 3 | +2025-11-25 12:00:00 |
| 4 | +:jbake-type: post |
| 5 | + |
| 6 | +ifdef::env-github,env-browser[:outfilesuffix: .adoc] |
| 7 | + |
| 8 | +We're happy to announce a new release of ClojureScript. If you're an existing |
| 9 | +user of ClojureScript please read over the following release notes carefully. |
| 10 | + |
| 11 | +This a major feature release with a significant number of enhancements. Before diving in note that Google Closure Compiler has been updated to `v20250820`. |
| 12 | + |
| 13 | +For a complete list of fixes, changes, and enhancements to |
| 14 | +ClojureScript see |
| 15 | +https://github.com/clojure/clojurescript/blob/master/changes.md#1.12.108[here] |
| 16 | + |
| 17 | +## ECMAScript 2016 Language Specification |
| 18 | + |
| 19 | +ClojureScript, outside of a few small exceptions, has generated ECMAScript 3rd edition (1999) compatible code. We avoided any newer constructs because they only presented two undesirable outcomes: increased code size due to polyfilling and decreased performance due to yet unoptimized paths in JavaScript virtual machines. |
| 20 | + |
| 21 | +Nine years have passed since the ECMAScript 2016 was released and the major JavaScript virtual machines now offer great performance across the specification. While language constructs like `let` https://vincentrolfs.dev/blog/ts-var[continue to fail] to deliver any value for ClojureScript, features like `Proxy` and `Reflect` solve real problems at low, low prices. |
| 22 | + |
| 23 | +ClojureScript will now generate ES2016. |
| 24 | + |
| 25 | +## `cljs.proxy` |
| 26 | + |
| 27 | +While ClojureScript always had a strong interop story, it was never as complete as Clojure on the JVM due to the lack of common interfaces, i.e. `java.util.Map`. ClojureScript values must be marshalled to JavaScript values, generating a significant amount of computational waste. |
| 28 | + |
| 29 | +Enter `cljs.proxy`. This new experimental namespace uses ES2016 Proxy to lazily bridge ClojureScript maps and vectors to JavaScript. JavaScript code can now see ClojureScript maps as objects and vectors as array likes. `cljs.proxy` was carefully written to add very little overhead for object access patterns over a direct `-lookup` call. |
| 30 | + |
| 31 | +[source,clojure] |
| 32 | +``` |
| 33 | +(require '[cljs.proxy :refer [builder]] |
| 34 | + '[goog.object :as gobj]) |
| 35 | +
|
| 36 | +(def proxy (builder)) |
| 37 | +(def proxied-map (proxy {:foo 1 :bar 2})) |
| 38 | +
|
| 39 | +(gobj/get proxied-map "foo") ;; => 1 |
| 40 | +``` |
| 41 | +
|
| 42 | +The feature needs significant tire kicking, but we believe this approach offers considerable value over existing practice. |
| 43 | +
|
| 44 | +## Clojure Method Values |
| 45 | +
|
| 46 | +ClojureScript now supports Clojure 1.12 method value syntax as well as static field syntax. `PersistentVector/EMPTY` works, but also `String/.toUpperCase` and `Object/new`. Thanks to ES2016 `Reflect` we do not need `:param-tags` hinting or involved compiler analysis for good performance and In many situations, like foreign libraries, the required type information would not be available. |
| 47 | +
|
| 48 | +[source,clojure] |
| 49 | +``` |
| 50 | +(refer-global :only '[String]) |
| 51 | +(map String/.toUpperCase ["foo" "bar" "baz"]) ;; => ("FOO" "BAR" "BAZ") |
| 52 | +``` |
| 53 | +
|
| 54 | +## `:refer-global` and `:require-global` |
| 55 | +
|
| 56 | +`:refer-global` lets a namespace declare what thing from the global environment are needed without `js` prefixing. It can also be combined with `:rename`. |
| 57 | +
|
| 58 | +[source,clojure] |
| 59 | +``` |
| 60 | +(refer-global :only '[Date] :rename '{Date my-date}) |
| 61 | +(my-date/new) |
| 62 | +``` |
| 63 | +
|
| 64 | +`:require-global` lets you use JavaScripy librares that you included as script tags on the page without any further build configuration. JavaScript build tooling brings a considerable amount of additional complexity. Hypermedia frameworks in particular have returned to the simpler world where at most you needed exactly one dependency to be productive. |
| 65 | +
|
| 66 | +Add the one script tag you need and use it from ClojureScript. |
| 67 | +
|
| 68 | +## `:lite-mode` and `:elide-to-string` |
| 69 | +
|
| 70 | +While ClojureScript enables writing ambitious programs for JavaScript targets, not allows are ambitious. There is light scripting, say for a blog, that is not currentlt well served by ClojureScript. |
| 71 | +
|
| 72 | +ClojureScript packs in a very large number of features and produces a small artifact, usually starting at 20K compressed. Thanks to Google Closure Compiler tree-shaking, you could use a lot functionality from Google Closure Library and expect your final artifact to increase slowly. |
| 73 | +
|
| 74 | +Still the hard 20K compressed wall remained. After some time in the hammock we decided to travel all the way back to 2011 and bring back the original data structures that Rich Hickey and Think Relevance included in the standard library. While not as efficient, they were more decoupled and involved less code. By tweaking the compiler to emit calls these instead under `:lite-mode` we could let tree-shaking sort it out. |
| 75 | +
|
| 76 | +The other code issue in ClojureScript programs is printing. While necessary to deliver the LISP experience at the REPL, for many smaller programs, the machinery is dead weight. `:elide-to-string` removes the `toString` implementations for the ClojureScript collection. |
| 77 | +
|
| 78 | +Combining these two new experimental flags cuts artifact size by a third. Note they cannot be used to make larger ClojureScript programs smaller - once you have enough dependencies or rely on enough features, the savings are a wash. |
| 79 | +
|
| 80 | +However for people who know that they want to build something ver small, yet not give up on the bits of `cljs.core` and Google Closure Library that they, these two new flags offer great value. |
| 81 | +
|
| 82 | +We're excited to hear feedback about all these new features! |
0 commit comments