You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
19
+
ClojureScript, outside of a few small exceptions, has generated ECMAScript 3rd edition (1999) compatible code. We avoided any newer constructs because historically they offered undesirable outcomes: increased code size due to polyfilling and decreased performance due to yet unoptimized paths in JavaScript virtual machines.
20
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.
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`surprisingly https://vincentrolfs.dev/blog/ts-var[fail] to deliver much value for ClojureScript, features like `Proxy` and `Reflect` solve real problems at low, low prices.
22
22
23
-
ClojureScript will now generate ES2016.
23
+
ClojureScript will use ES2016 moving foward where it delivers value and performance benefits.
24
24
25
25
##`cljs.proxy`
26
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.
27
+
ClojureScript interop story, while strong, was never as complete as Clojure on the JVM due to the lack of common interfaces, i.e. `java.util.Map`. ClojureScript values had to be marshalled to JavaScript values via `clj->js`, generating a significant amount of computational waste.
28
28
29
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
30
@@ -39,11 +39,11 @@ Enter `cljs.proxy`. This new experimental namespace uses ES2016 Proxy to lazily
39
39
(gobj/get proxied-map "foo") ;; => 1
40
40
```
41
41
42
-
The feature needs significant tire kicking, but we believe this approach offers considerable value over existing practice.
42
+
This feature needs commmunity tire kicking, but we believe this approach offers sizeable benefits over existing practice.
43
43
44
44
## Clojure Method Values
45
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.
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 manual `:param-tags` hinting for good performance, and it covers the many cases where type information will simply not be available to the ClojureScript compiler.
47
47
48
48
[source,clojure]
49
49
```
@@ -53,30 +53,49 @@ ClojureScript now supports Clojure 1.12 method value syntax as well as static fi
53
53
54
54
## `:refer-global` and `:require-global`
55
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`.
56
+
`:refer-global` lets a namespace declare what definitions from the global environment should available in the current namespace without `js` prefixing. It can be combined with `:rename`.
`: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.
64
+
`:require-global` lets you use JavaScript 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 and there is a growing population of developers moving to technologies that simplify tooling complexity. Hypermedia frameworks in particular have returned to more innocent times where at most you needed exactly one JavaScript dependency to be productive.
65
65
66
-
Add the one script tag you need and use it from ClojureScript.
66
+
ClojureScript now supports hypermedia-centric development approaches where you might have only one dependency and you are using ClojueScript / Google Closure Library primarily to build Web Components and want to side-step the JavaScript dependency churn and tooling burden entirely.
67
+
68
+
[source,clojure]
69
+
```
70
+
(require-global '[Idiomorph :as idio])
71
+
(idio/morph ...)
72
+
```
67
73
68
74
## `:lite-mode` and `:elide-to-string`
69
75
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.
76
+
While ClojureScript enables writing ambitious programs for JavaScript targets, not all programs we might want to write require ambition. There are light scripting use cases, say for a blog, that are not currently well served by ClojureScript.
77
+
78
+
ClojureScript always produced a reasonably small artifact, usually starting at 20K compressed. And thanks to Google Closure Compiler tree-shaking, you could leverage powerful functionality from Google Closure Library and expect the size of your final artifact to increase slowly.
71
79
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.
80
+
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 are decoupled and involve less code. By tweaking the ClojureScript compiler to emit calls to the older constructors instead under a new `:lite-mode` flag, tree-shaking can eliminate the now unused fancier data structures.
73
81
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.
82
+
The other code size issue in ClojureScript programs is printing. While necessary to deliver the LISP experience at the REPL, for less ambitious artifacts the machinery is just dead weight. `:elide-to-string` removes the `toString` implementations for the ClojureScript collections.
75
83
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.
84
+
Combining these two new experimental flags cuts the starting artifact size by a third. However, it's important to understand these flags cannot be used to make *large* ClojureScript programs smaller - once you have enough dependencies or rely on enough features, the savings provided by `:lite-mode` are a wash.
77
85
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.
86
+
Bu for people who know that they want to build something very compact, yet not give up on the bits of `cljs.core` and Google Closure Library that they need, these two new flags offer great value.
79
87
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.
88
+
The following program is 6K Brotli compressed with `:lite-mode` + `:elide-to-string`
89
+
true.
90
+
91
+
[source,clojure]
92
+
```
93
+
(->> (map inc (range 10))
94
+
(filter even?)
95
+
(partition 2)
96
+
(drop 1)
97
+
(mapcat identity)
98
+
into-array)
99
+
```
81
100
82
101
We're excited to hear feedback about all these new features!
0 commit comments