David Nolen targets automated externs to cut ClojureScript friction

The Next Five Years of ClojureScript - David Nolen — Metosin

Metosin

ClojureScript aims to eliminate its largest source of incidental complexity by automating extern inference, forcing third-party JavaScript libraries to conform to its optimization standards.

AI-assisted summary of The Next Five Years of ClojureScript - David Nolen — original source. Check the original for full context.

Source published:

Key ideas

  • Five years after its launch, ClojureScript achieved near-total standard library parity with Clojure on the JVM, powered by cross-platform reader conditionals (.cljc) and a fully self-hosting compiler that eliminated JVM dependencies. (34:21)
  • Manual Google Closure externs remain the single largest source of incidental complexity in ClojureScript, driving active compiler prototyping toward automated extern inference for third-party JavaScript interop. (45:10)
  • Early ClojureScript work on persistent data structures inspired Mori, which directly influenced Facebook's design of Immutable.js after React popularized reference-equality checks for virtual DOM diffing. (53:40)
  • Targeting WebAssembly directly remains a long-term goal projected 6 to 10 years out due to the initial specification's lack of native runtime garbage collection. (58:10)

Detailed notes

## Background Published by Metosin on YouTube on September 16, 2016, this talk features ClojureScript lead developer David Nolen reflecting on the language's first five years. The presentation aims to document key architectural milestones before early community lore is forgotten and outline a pragmatic roadmap for the next five years of compiler development.

## TL;DR David Nolen details the evolutionary milestones of ClojureScript since its 2011 launch, including the migration to persistent data structures, source map implementation, self-hosting via reader conditionals, and validation through real-world tools like Light Table. He addresses major friction points, highlighting how Google Closure Compiler advanced compilation and manual externs historically burdened frontend developers. Looking ahead, Nolen outlines priorities centered on clojure.spec integration, automated extern inference, compiler optimization passes, and seamless modern JavaScript module interop.

## Atmosphere & style The presentation is candid, technically rigorous, and conversational, marked by Nolen's genuine awe at the power of the tooling alongside self-deprecating humor about past development burnouts. Rather than presenting a rigid corporate roadmap, the narrative feels like an affectionate, community-centered retrospective that credits countless volunteer contributors for solving thorny compiler problems. The vibe is energizing and pragmatic, balancing deep architectural discussions with an enthusiastic call for everyday developers to dive into open-source compiler work.

## Bulletin - [34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) Five years after its launch, ClojureScript achieved near-total standard library parity with Clojure on the JVM, powered by cross-platform reader conditionals (.cljc) and a fully self-hosting compiler that eliminated JVM dependencies. - [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) Manual Google Closure externs remain the single largest source of incidental complexity in ClojureScript, driving active compiler prototyping toward automated extern inference for third-party JavaScript interop. - [53:40](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3220s) Early ClojureScript work on persistent data structures inspired Mori, which directly influenced Facebook's design of Immutable.js after React popularized reference-equality checks for virtual DOM diffing. - [58:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3490s) Targeting WebAssembly directly remains a long-term goal projected 6 to 10 years out due to the initial specification's lack of native runtime garbage collection.

## Key takeaways - [05:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=313s) Rich Hickey announced ClojureScript in July 2011 to expand Clojure's reach into environments barring the JVM, architecting the compiler in Clojure with protocols at the base. - [09:55](https://www.youtube.com/watch?v=mty0RwkPmE8&t=595s) Adoption initially stumbled over unfamiliar Google Closure tooling until Evan Mezeske created the lein-cljsbuild plugin, integrating ClojureScript compilation into standard Leiningen workflows. - [14:31](https://www.youtube.com/watch?v=mty0RwkPmE8&t=871s) Porting persistent data structures to JavaScript took over a year, but benchmarking and compiler tuning brought ClojureScript vector performance to within 20% to 30% of handwritten JavaScript on V8. - [16:48](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1008s) Chris Granger's Light Table demonstrated that ClojureScript could power large-scale, desktop-grade developer tooling, disproving widespread skepticism around client-side immutable data structures. - [19:32](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1172s) Implementing Source Maps took over two years due to Clojure's Java reader lacking column metadata, requiring Nicola Mometto's tools.reader and Sean Grove's Base64 VLQ implementation to resolve. - [31:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1905s) Mobile toolkits like Mike Fikes's Ambly established untethered iOS REPL workflows over Wi-Fi direct to JavaScriptCore without requiring Xcode after the initial build. - [34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) Clojure 1.7 introduced reader conditionals (.cljc), allowing David Nolen to port the ClojureScript analyzer and compiler to ClojureScript itself, unlocking standalone tools like Plank, Replete, and KLIPSE. - [38:30](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2310s) The emergence of React eliminated mainstream skepticism about immutable data by shifting UI paradigms away from mutable DOM manipulation to pure state-driven rendering. - [41:46](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2506s) ClojureScript development follows a user-need-driven organic path rather than a rigid roadmap, with language parity with Clojure remaining the overarching priority. - [41:46](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2506s) Serial compiler optimizations could yield an estimated 2x speedup, shortening build times significantly when paired with parallel compilation. - [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) Google Closure externs cause frequent production breakages under advanced optimizations, making native extern inference and module processing primary development targets. - [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) Translating clojure.spec definitions into Google Closure type annotations offers compile-time type verification to catch defects before production. - [57:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3454s) Whole-program dead-code elimination via Google Closure enables ClojureScript to discard unused code from upstream dependencies, obviating the need for micro-modular JavaScript packaging. - [58:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3490s) Full WebAssembly adoption for ClojureScript will take 6 to 10 years because bundling a custom garbage collector without native host GC support would cause severe performance issues.

## Detailed walkthrough ### [00:02](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2s) Introduction and the Early Horizon of ClojureScript

Opening the final talk of the day at a conference in Finland, David Nolen explains that rather than giving a deeply technical presentation, he wants to chronicle the history of ClojureScript. Stepping back is critical because with five years having elapsed since its inception, the early history is already fading from collective memory. A quick poll of the audience underscores this: while almost no hands go up for five or four years of experience, a few appear for three, and the vast majority have only adopted it within the last one to two years. Because so many are newcomers, Nolen hopes that walking through this long, winding road will give developers perspective on how ClojureScript is built and how its development philosophy works.

Nolen briefly introduces himself as a software engineer at Cognitect, a software consultancy that stewards Clojure and ClojureScript, where he serves as the lead developer of ClojureScript (alongside working with products like Datomic). He highlights a major milestone that had occurred just weeks earlier: ClojureScript finally launched an official, dedicated website. Repurposing the infrastructure and design of `clojure.org`, Alex Miller led the effort to create content targeted specifically to the language. While existing developers had long known ClojureScript to be reliable and capable, having a polished public face gives newcomers the sense that the technology has fully grown up. Reflecting on his daily work, Nolen remarks:

> “Even though I work on the compiler, every time I have Figwheel or I'm building my project, it's like this is like magic, this is amazing.”

Even to the people building it, the distance the ecosystem has traveled feels like scaling an immense mountain.

---

[02:56](https://www.youtube.com/watch?v=mty0RwkPmE8&t=176s) Pre-History (2011): The Search for a Frontend Lisp

Five years prior, in 2011, Nolen was not working with Clojure professionally. He worked in the newsroom at *The New York Times* on the Interactive News team building news applications using a standard stack of Ruby on Rails, JavaScript, and jQuery. He shared an office with Jeremy Ashkenas, who had created CoffeeScript. At the time, compiling to JavaScript was widely dismissed by mainstream web developers; although tools like Google Web Toolkit (GWT) could compile Java down to JavaScript, the broader JavaScript community viewed source-to-source compilation as an oddity. CoffeeScript fundamentally changed that mindset by demonstrating to frontend developers that compiling down to JavaScript was a viable, elegant way to write web software.

Nolen was personally drawn to Lisp rather than Ruby or JavaScript and began searching for a dialect that could compile down to JS. Clojure was merely a hobby language for him at the time, and an early experimental project called ClojureScript by Chris Houser existed but was nowhere near ready for real-world usage. Nolen evaluated Scheme2Js, a nearly fully compliant Scheme R5RS compiler written by Florian Loitsch (who later joined Google to build Dart's `dart2js` compiler). However, Scheme2Js lacked macros. Being completely committed to the power of Common Lisp, Scheme, and Clojure, Nolen felt macros were non-negotiable and resigned himself to sticking with CoffeeScript.

- Mainstream web dev stack in 2011: Ruby on Rails, JavaScript, jQuery. - CoffeeScript served as the cultural turning point that normalized compiling to JavaScript. - Florian Loitsch's Scheme2Js offered near-R5RS compliance, but its lack of macro support made it a dead end for Nolen's needs.

---

[05:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=313s) The Launch of ClojureScript: Reach and Self-Hosting Roots

In July 2011, Relevance held a meetup at Clojure NYC—one of the most heavily attended meetups in the group's history—where Rich Hickey officially unveiled ClojureScript. The core motivation behind the language was *reach*. Clojure developers loved targeting the JVM, but the JVM could not run everywhere. Apple strictly prohibited JVM environments on iOS, and web browsers had long abandoned Java applets. To write client-side software and target platforms where the JVM was locked out, JavaScript was the only viable runtime.

Rich Hickey also positioned ClojureScript as a groundbreaking conceptual experiment: it was the first pass at writing Clojure in Clojure itself. Clojure on the JVM had an implementation written almost exclusively in Java, from its compiler to its persistent data structures. ClojureScript broke with that architecture by being written in Clojure, with abstractions driven by Clojure protocols at the lowest level of the language. This realized a cryptic teaser Rich Hickey had dropped on IRC back in January 2011 when he briefly asked:

> “What if there was a version of Clojure with protocols at the bottom?”

```mermaid flowchart TD accTitle: Clojure JVM versus ClojureScript Implementation Architectures accDescr: Diagram contrasting Clojure JVM's Java-based implementation with ClojureScript's self-hosting Clojure implementation.

subgraph JVM ["Clojure (JVM)"] JCompiler["Compiler (written in Java)"] JDS["Core Data Structures (written in Java)"] JTarget["Runtime Target: JVM"] JCompiler --> JTarget JDS --> JTarget end

subgraph CLJS ["ClojureScript (2011)"] CCompiler["Compiler (written in Clojure)"] CProtocols["Core Data Structures via Protocols"] CTarget["Runtime Target: JavaScript Engine"] CCompiler --> CTarget CProtocols --> CTarget end ```

---

[07:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=454s) First Contributions and Early Adoption Hurdles

ClojureScript had been public for two or three months before Nolen got involved. After cloning the repository to try out the REPL, he attempted to run `reify` and hit an immediate error because the macro had not been implemented. After asking on the mailing list, he learned it was simply waiting for someone to write it. Expecting compiler work to require weeks of grueling effort, he dug into the source and was surprised by how approachable and simple the codebase was because it was written in Clojure. He drafted a clean implementation in just eight lines of code:

> “Rich Hickey and Chris Houser both [were] like, 'Wow, that's so cool, only eight lines of code to get `reify`,' and this was my—this got me commit rights to ClojureScript.”

From that point on, Nolen became a primary committer, triaging Jira issues and shepherding patches to sustain community momentum, knowing the language would only survive if early adopters believed it would succeed.

Despite its technical elegance, ClojureScript faced steep friction with the broader web ecosystem. While the 2011 frontend world was centered around jQuery and lightweight scripts, ClojureScript arrived tied to Google tools that web developers rarely encountered: the Google Closure Compiler for aggressive minification and dead-code elimination, and the Google Closure Library for standard browser utilities. The steep learning curve and unfamiliar ecosystem prompted Relevance to create "ClojureScript One," an opinionated starter suite designed to help newcomers navigate this novel architecture.

[09:55](https://www.youtube.com/watch?v=mty0RwkPmE8&t=595s) Google Closure Library and the Arrival of `lein-cljsbuild`

ClojureScript One was never meant to be a full-blown developer tool; it was a template project built to demonstrate that developers could create a viable application and find everything they missed from jQuery already present in the Google Closure Library. David Nolen highlights that Google Closure Library remains heavily developed by Google, serving as the actual foundation behind their production JavaScript applications alongside the Closure Compiler. While seeing the depth of Closure Library opened people's eyes, getting work done remained awkward because ClojureScript One was still just a template. Developers had to clone repositories and execute clunky custom scripts. By 2011, Leiningen had completely taken over the Clojure ecosystem:

> “By 2011 Leiningen had taken the Clojure world by storm. I mean, it's basically if it wasn't a Leiningen plugin, chances are nobody was going to use your thing.”

Around eight or nine months into ClojureScript’s lifecycle, Evan Mezeske introduced `lein-cljsbuild`. This plugin lowered the barrier to entry by making it straightforward to stand up a Ring application and add ClojureScript compilation directly into an existing Leiningen workflow. That development marked the moment Clojure programmers finally began giving ClojureScript a chance, creating real community momentum. Maintenance of `lein-cljsbuild` later shifted to Maria Geller.

[11:58](https://www.youtube.com/watch?v=mty0RwkPmE8&t=718s) Porting Persistent Data Structures to JavaScript

Many developers do not realize that ClojureScript launched without persistent data structures. For almost its entire first year, it relied on naive, slow copy-on-write collections that exposed standard Clojure interfaces without the underlying efficiency. In 2011, skepticism was high, but the JavaScript performance landscape shifted when Google assembled an elite compiler team led by Lars Bak—known for his decades of work on the Self language and the Java HotSpot VM. Google's work on V8 prompted the ClojureScript team to explore what would happen if they hand-ported Clojure's Java implementations to JavaScript.

László Török took Clojure’s persistent vector—roughly 400 lines of Java—and created a direct JavaScript port to benchmark on V8. The results were startling: the JavaScript port was only about 4x slower than the JVM, comfortably within an order of magnitude. Török then wrote a 200-line ClojureScript version of that JavaScript port, initiating the effort to implement all persistent data structures directly in a Clojure dialect rather than host-level Java.

```mermaid flowchart TD accTitle: Evolution of Persistent Vectors in ClojureScript accDescr: Diagram showing the porting sequence of persistent vectors from Java to JavaScript to ClojureScript, followed by compiler optimizations. subgraph Implementation["Vector Implementations"] A["Original Java PersistentVector (JVM)<br>~400 lines"] B["László Török's JS Port<br>~4x slower than JVM"] C["László Török's ClojureScript Port<br>~200 lines (initially 3x slower than JS)"] end subgraph Optimization["Compiler Refinement"] D["David Nolen Optimizes Code Gen<br>(Inlining arithmetic, reducing call overhead)"] E["Optimized CLJS Persistent Vector<br>~20-30% slower than handwritten JS"] end

A --> B B --> C C --> D D --> E ```

[14:31](https://www.youtube.com/watch?v=mty0RwkPmE8&t=871s) Compiler Tuning and Full Ecosystem Ports

Using persistent data structures as a performance baseline proved to be a practical way to diagnose compiler inefficiencies. Rather than relying on synthetic benchmarks that meant little in practice, Nolen used Török’s ClojureScript vector port to reveal flaws in ClojureScript’s code generation:

> “The cool thing about using persistent data structures to drive ClojureScript perf was that this is something that everybody's going to depend on. If we make this fast, then we know that we're actually delivering on performance.”

Investigating why the initial ClojureScript code ran three times slower than handwritten JavaScript exposed missing arithmetic inlining and extraneous function call overhead. Once the compiler was tuned, the ClojureScript implementation ran only 20% to 30% slower than pure JavaScript without requiring changes to Török’s source code.

Seeing that V8 handled these algorithms well—and knowing competitors like JavaScriptCore and SpiderMonkey would race to match V8's pace—Polish mathematician and programmer Michał Marczyk took on porting the rest of Clojure's persistent collections. Over roughly fourteen months, each newly ported data structure was benchmarked against the JVM to uncover further code generation flaws. When users updated their ClojureScript applications, they regularly reported immediate 10x, 20x, or 30x performance improvements.

[16:48](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1008s) The Light Table Breakthrough

Despite internal excitement within the Clojure community, mainstream adoption remained elusive throughout 2011 and 2012. While libraries like Facebook’s Immutable.js later popularized immutability, outside engineers at the time dismissed persistent data structures as academic curiosities, repeatedly asking for real-world proof of what could be built with a Lisp targeting the browser.

The perception shifted dramatically when Chris Granger unveiled Light Table. Pitching an interactive, responsive coding environment that originally planned support for Clojure, ClojureScript, Python, and Ruby, Light Table caught the attention of the broader programming world. Many of its UI and interactive ideas were subsequently adopted by mainstream tools like Swift Playgrounds, Xcode, and IntelliJ. Crucially, Granger constructed the entire desktop application out of 11,000 to 12,000 lines of ClojureScript running on Node-Webkit.

Seeing a complex, desktop-grade development environment built entirely in ClojureScript convinced skeptical developers both inside and outside the Clojure ecosystem that the language was mature enough for production software. With that validation established, the community shifted its attention to compiling Clojure in Clojure itself.

[19:32](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1172s) Debugging Woes and the Reader Column Problem

As ClojureScript reached its two-year mark, a critical bottleneck emerged around debugging and compiler bootstrapping. Developers coming from Clojure would see tools like `lein-cljsbuild` and Light Table, get excited, and start building applications. However, as soon as an error occurred, they were thrown into baffling JavaScript code. David Nolen emphasizes that unlike CoffeeScript, ClojureScript never aimed to emit human-readable output: “the only thing we cared about is how fast is it going to be you know like that's all we cared about was performance we didn't care about is this something for humans to look at”. Debugging that raw JavaScript was intensely painful, making Source Maps an absolute necessity.

For its first two years, ClojureScript lacked Source Map support entirely. While early browser implementations were slow to mature, the deeper technical obstacle lay within the compiler's reliance on Clojure's standard reader. Because ClojureScript piggybacked heavily on Clojure's original Java-based reader, it inherited an unexpected gap: the reader annotated symbols and s-expressions with file and line metadata, but it did not record the column numbers. Accurate Source Maps in modern web browsers required column precision, meaning ClojureScript was completely blocked until the reader infrastructure evolved.

```mermaid flowchart TD accTitle: The Source Map Column Resolution Flow accDescr: Diagram illustrating how tools.reader bypassed Clojure's Java reader to enable column tracking for Source Maps.

subgraph Legacy ["Legacy Clojure Reader"] A["Clojure Java Reader"] -->|"tracks file & line only"| B["No Column Data"] B --> C["Blocked Source Maps"] end

subgraph Modern ["tools.reader Migration"] D["Nicola Mometto's 'blind' (Clojure)"] -->|"ported to contrib"| E["tools.reader"] E -->|"adds column metadata"| F["Accurate AST Locations"] F --> G["Browser Source Maps"] end ```

[21:26](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1286s) The Community Delivers: `tools.reader` and Source Maps

The breakthrough came from community member Nicola Mometto, who created a project called Blind—a faithful, pure-Clojure implementation of the Clojure reader. This offered two enormous advantages: being written in Clojure rather than Java meant it could eventually run in ClojureScript itself, and it decoupled reader development from the core Clojure release cycle. Because the Clojure core team was busy juggling higher-priority concerns, getting column metadata into the official Java reader would have taken an extended timeline. With Mometto as the sole maintainer of Blind, Nolen convinced him to move the project under Clojure Contrib as `tools.reader`. Mometto added column tracking, allowing ClojureScript to swap out the Java reader entirely.

With column metadata in place, Nolen spent two exhausting weeks tackling Source Maps during his off-hours while working full-time at *The New York Times*. The specification—a complex, MIDI-inspired Base64 Variable-Length Quantity (VLQ) encoding format—was miserable to implement and debug. Feeling burned out and unsupported, Nolen shelved the branch for two months. The project was rescued when Sean Grove appeared on IRC. Grove was building a commercial product in ClojureScript, was losing his mind reading generated JavaScript, and offered to help. Grove pushed the branch 98% of the way to completion, leaving Nolen to wrap up the final 2%. Roughly two years and one month after ClojureScript's initial launch, Source Maps officially landed. The result allowed developers to inspect syntax-highlighted Clojure code, set breakpoints, and step-debug directly inside Chrome DevTools, prompting Nolen to marvel that “it's like your browser is a lisp machine”.

- Nicola Mometto created the pure-Clojure reader `blind`, which transitioned into the official `tools.reader` library. - David Nolen worked on Source Maps on nights and weekends while employed at *The New York Times* in 2012. - The Source Map format's bit-level Base64 VLQ compression made manual debugging notoriously frustrating. - Sean Grove contributed roughly 98% of the remaining implementation work needed to finish the initial Source Map support.

[24:52](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1492s) JavaScript Modules and Maria Geller's Compiler Work

While improvements like Source Maps addressed immediate pain points, David Nolen also looked ahead to long-term ecosystem shifts, specifically JavaScript module compatibility. The broader JS ecosystem was rapidly fragmenting across competing module specifications—ES6 modules, AMD, standard CommonJS, and Node.js's custom dialect of CommonJS—while developers increasingly wanted to consume libraries published to npm. Predicting that module consumption would become a critical requirement years down the road, Nolen proposed JS module integration as a Google Summer of Code project.

The project was picked up by Maria Geller, who had only been writing Clojure for about three months. Despite her relative newcomer status, Geller tackled compiler internals and emerged as a ClojureScript compiler authority. She even accomplished a rare feat among outside contributors: getting patches accepted upstream into Google's Closure Compiler. Nolen noted that Google maintains automated infrastructure to immediately roll back any commit that breaks Google's internal codebases, making upstream contributions exceptionally challenging. Geller's work successfully improved module handling, illustrating Nolen's broader message about contributing:

> “...it's really not it's it's if you're writing closure or closure script programs it's the same stuff you know we we have multi methods and and we have maps and we have vectors it's all the same stuff it's really not any more complicated than what you're doing...”

He strongly urged the audience to watch Geller's talk from Clojure/conj, where she deconstructs the compilation pipeline into approachable, understandable phases.

[28:09](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1689s) The Realities of Open Source and the `clojure.pprint` Delay

Turning to the less glamorous side of open-source maintenance, Nolen noted that progress often mirrors maintainer interest: “open source is is a funny thing you know basically what happens with open source is you work on stuff when you want to work on it because nobody's paying you to do it right”. A consequence of unpaid, volunteer development is that unappealing tasks can sit neglected for years.

A prime example was `clojure.pprint` (pretty printing). Although widely used across tools and daily developer workflows in Clojure, `pprint` remained completely unported to ClojureScript for four full years simply because Nolen could never bring himself to dig into its dense implementation.

[28:50](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1730s) Porting pprint and Filling Core Library Gaps

David Nolen recalls that one of the most frustrating omissions in early ClojureScript was `clojure.pprint`. The Clojure version was written in 2009-era Clojure code, ported from an ancient Common Lisp pretty printer, and relied heavily on legacy constructs like `defstruct`. Spanning roughly 3,000 lines of arcane code, it was so intimidating that Nolen admits he could never bring himself to tackle it: “every time I would look at it I would close my tab right I was like cannot bring myself to do this”. This missing namespace was a major source of friction for newcomers who loved Clojure's standard library and could not understand why such a fundamental tool was missing when trying to inspect large application state atoms in frameworks like Reagent, Rum, or Om.

The impasse was finally broken when the community took the initiative. Jonathan Boston and Shaun Lebron authored what Nolen describes as perhaps the single biggest patch in the project's history—a massive 3,000-line patch implementing pretty printing in ClojureScript. Having native `pprint` meant developers debugging complex state in modern client-side apps could finally inspect their data structures without tearing their hair out, marking another milestone where volunteer open-source contributions rescued an essential piece of tooling from languishing.

[30:18](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1818s) Native Testing Support: Closing the Standard Namespace Gap

Another critical feature that remained unaddressed for nearly four years was built-in testing. Clojure had prioritized testing before version 1.0 when Rich Hickey added support for `:test` metadata directly on functions, treating testing as an essential first-class language feature. ClojureScript, however, lagged behind without an official out-of-the-box solution. While Chas Emerick (co-author of O'Reilly's *Clojure Programming*) had created a widely used third-party testing library, relying on external dependencies for baseline capabilities created unnecessary friction for developers expecting language parity.

Nolen eventually stepped in to build what became `cljs.test`, rounding out the core namespaces. With native testing in place alongside the earlier standard library additions, ClojureScript finally provided all core Clojure functionality that did not explicitly depend on JVM multi-threading. Nolen notes that developers arriving in 2016 entered a much smoother ecosystem, reflecting that “if you're coming to closure script right now in like in 2016 you're really lucky you missed you missed some a lot of turbulence”.

- **Clojure parity milestone:** With `cljs.test` resolved, the core namespaces reached near-total parity with Clojure, excluding JVM-specific multi-threading primitives. - **Timeline:** Key features like pretty printing and standard testing took roughly four full years of effort before achieving built-in status.

[31:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1905s) Delivering on "Reach": Mike Fikes and Untethered iOS Development with Ambly

When Rich Hickey originally unveiled ClojureScript, a central thesis was "reach"—providing a single language that could target not just the web, but mobile platforms like iOS and Android. Yet for four years, practical mobile implementations remained elusive. That changed when Mike Fikes, known as the creator of Plank, shipped a production application to the Apple App Store using ClojureScript and built foundational open-source tooling for mobile development.

To solve the mobile workflow, Fikes created Ambly, a custom REPL server that reimagined the iOS development loop. Because Ambly required specialized capabilities, the ClojureScript compiler team refactored the core REPL abstractions to make building custom REPL environments easier. Ambly uses Bonjour/ZeroConf (multicast DNS) to discover an iOS device automatically across the local Wi-Fi network. Once the developer selects the device from the desktop terminal REPL, Ambly establishes a direct socket connection to JavaScriptCore on the device and synchronizes compiled assets over WebDAV. This setup enabled genuine interactive live coding directly on iOS hardware, untethering developers completely from Xcode after the initial bootstrapping phase and fulfilling the early vision of reaching mobile environments.

```mermaid flowchart TD accTitle: Ambly REPL Architecture for iOS accDescr: Diagram showing desktop compiler connecting to iOS device over Bonjour, WebDAV, and socket to JavaScriptCore.

subgraph Desktop["Developer Workstation"] D_REPL["Ambly REPL Client"] D_COMP["ClojureScript Compiler"] end

subgraph Discovery["Network Discovery"] M_DNS["Bonjour / ZeroConf (Multicast DNS)"] end

subgraph Mobile["iOS Device"] APP["Host App Running JavaScriptCore"] DAV["Embedded WebDAV Server"] end

APP -.->|"Broadcast presence"| M_DNS M_DNS -.->|"Discover device"| D_REPL D_REPL -->|"Socket connection (Eval/Read)"| APP D_COMP -->|"Sync compiled JS files"| DAV DAV -->|"Load runtime code"| APP ```

- **Zero-configuration connection:** Ambly automatically locates target devices on the local Wi-Fi network, allowing users to enter a device number and instantly connect. - **Untethered workflow:** Xcode is only required once to compile and launch the initial host runner; all subsequent development happens interactively via the ClojureScript REPL and live file syncing. - **React Native horizon:** These mobile breakthroughs laid the groundwork for integrating ClojureScript with emerging platforms like React Native.

[34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) Reader Conditionals and Self-Hosting: Compiling the Compiler

Nolen recounts that for the first four years, ClojureScript did not use conventional semantic versioning, relying instead on raw Git build numbers up to revision 3225. The shift to standard version numbers coincided with the release of Clojure 1.7, which introduced reader conditionals and the unified `.cljc` file extension. Previously, sharing logic across `.clj` and `.cljs` files required awkward, unofficial third-party preprocessors. The arrival of reader conditionals provided an official mechanism for cross-platform code sharing, prompting Nolen to immediately attempt an ambitious goal: self-hosting the compiler.

As soon as Clojure 1.7 landed, Nolen updated ClojureScript's dependencies and set to work porting the compiler and analyzer to `.cljc` so ClojureScript could compile itself. Nolen spent a month methodically fixing analyzer and compiler incompatibilities until the pipeline could successfully process its own codebase. The result was a fully self-hosted ClojureScript implementation that could run in pure JavaScript environments without any dependency on the JVM, realizing a classic Lisp milestone.

[36:20](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2180s) The Bootstrapping Breakthrough and Its Ecosystem Impact (Plank, Replete, KLIPSE)

Nolen highlights that bootstrapping ClojureScript proved surprisingly elegant because of how ClojureScript strictly separates phases. In ClojureScript, macro expansion occurs strictly at compile time, completely decoupled from runtime execution: “there are two distinct phases in closure script there's macro time and there's runtime and they'll never meet but that means bootstrapping closure script was a very very very straightforward affair”. In the macros file (`cljs.core`), macros require the analyzer and standard library to tie the metacircular knot. Because compilation and runtime do not cross-talk dynamically, self-hosting only required compiling the analyzer and compiler to JavaScript and concatenating them with the standard library.

This self-hosted compiler opened up an entire ecosystem of standalone ClojureScript tools that boot instantly without the JVM:

- **KLIPSE:** A web-based tool enabling live code evaluation and interactive documentation demos entirely inside the browser. - **Plank:** A fast, lightweight command-line REPL for macOS and Linux built on top of JavaScriptCore. - **Replete:** A full-featured ClojureScript REPL running natively on iOS devices. - **Parinfer integration:** Tools like Replete incorporated Parinfer, an editor innovation from the Clojure community that automatically manages Lisp parentheses based on line indentation, making mobile REPL hacking seamless on standard on-screen keyboards.

Nolen concludes this retrospective by emphasizing how many people, architectural iterations, and quiet multi-year efforts were required to take ClojureScript from an experimental offshoot to a mature, self-hosted, multi-platform language ecosystem.

[38:30](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2310s) Community Contributions and the React Revolution

David Nolen reflects on the broader ClojureScript ecosystem, emphasizing that while he cannot showcase every photograph or name, the project owes its success to a collective effort of approximately 141 contributors. No contribution has been too small: anyone who opened an issue, logged into IRC to ask if a feature was working as intended, filed a ticket, or submitted a patch shares credit for making the language what it is today. As Nolen asserts: “ClojureScript is as good as it is today because everybody that's worked on it.”

The trajectory of the language changed dramatically with the introduction of React. Previously, ClojureScript faced skepticism because having immutable data structures felt pointless when developers still had to manipulate the mutable DOM. React opened the floodgates, creating a Cambrian explosion of UI libraries and pushing ClojureScript far ahead of mainstream web development. Nolen recalls attending a React conference where developers were pitching Flux, eliciting an unenthusiastic reaction from ClojureScript developers who had already leapfrogged those design patterns. Beyond UI frameworks, other community tools transformed the day-to-day workflow:

- **binaryage/cljs-devtools**: Created by an author known online as Darwin, this Chrome extension hooks into browser custom object formatters. Instead of forcing developers to inspect tangled, raw JavaScript objects when logging vectors or stepping through the debugger, it prints native ClojureScript data structures cleanly in the console. - **Shadow-build (shadow-cljs)**: Developed by Thomas Heller as an alternative build tool, it pioneered several major features long before ClojureScript core implemented them, proving that competing out-of-tree experiments are vital sources of innovation.

```mermaid flowchart LR accTitle: Shadow-build Innovations Adopted by ClojureScript Core accDescr: Diagram illustrating features originating in Thomas Heller's shadow-build and later making their way into ClojureScript core.

subgraph SB["shadow-build (Thomas Heller)"] M["Google Closure Modules<br/>(Code Splitting)"] I["Macro vs. Runtime<br/>Var Inference"] end

subgraph Core["ClojureScript Core"] CSM["Native Module Code Splitting<br/>(Months later)"] CSI["Automatic Macro Inference<br/>(Removed need for:refer-macros)"] end

M -->|"Pioneered"| CSM I -->|"Pioneered"| CSI ```

- Thomas Heller's shadow-build included Google Closure module support for code splitting months before core ClojureScript adopted it. - Shadow-build pioneered inferring whether a symbol was a macro var or a runtime var, eliminating the long-standing requirement for developers to manually write `:refer-macros`.

---

[41:46](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2506s) The Next Five Years: Priorities and Core Compiler Improvements

Looking toward the future, Nolen describes ClojureScript's development philosophy not as a rigid five-year master plan, but as an organic evolution: “It's sort of a random walk in the right direction right, so you can expect the next five years it's probably going to be a random walk in the right direction; things will happen when people want them to happen.”

Historically, parity with Clojure has remained the single highest priority because discrepancies between the two languages represent the biggest source of user frustration. The main effort focuses on `clojure.spec`, where ClojureScript has matched features up to Alpha 11, with ongoing work to maintain parity as new versions land. Nolen expects the community will spend the next two years exploring what spec makes possible. Beyond language parity, several concrete compiler improvements are high on the agenda:

- **Google Closure Compiler Integration**: Staying current with Google's upstream changes to the Closure Compiler and module systems, which require constant adaptation because Google optimizes primarily for internal users rather than external consumers. - **Compiler Performance**: In five years, no dedicated pass had been made on serial compiler performance. While Nolen previously implemented a parallel build feature to split compilation across multiple CPU cores for production builds, single-threaded throughput had never been optimized. Nolen estimates an untapped 2x speedup in serial compilation, which could take a 30-second build down to 15 seconds, and down to 7 seconds when combined with parallel builds. - **Windows Support**: Despite a smaller Windows user base, Nolen welcomes contributions and pledges immediate review: “If you're a Windows user and you have a patch, there's a chance I will apply it immediately, the moment I get a Windows patch it'll probably get applied because we care; we want our stuff to work great everywhere.” - **Testing Infrastructure**: ClojureScript needs more automated test coverage across its various compiler flag combinations, generative tests for runtime behavior, and a long-term runtime performance benchmark harness to monitor generated code over time.

---

[45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) Spec-Driven Type Checking, Public APIs, and the Externs Problem

Turning to forward-looking compiler architecture, Nolen highlights how `clojure.spec` could directly improve ClojureScript’s output. Although full recursive validation is unsuitable for compile-time checking, simple specs could trivially translate into Google Closure type annotations. If the ClojureScript compiler knows whether an argument is nillable, a number, a map, or a vector, it can emit static type assertions that Google Closure Compiler uses to catch errors before code reaches production.

Nolen also emphasizes the necessity of maintaining robust, public compiler APIs. Tools like Bruce Hauman's Figwheel—widely used across the audience—depend entirely on compiler hooks to offer polished experiences, including detailed, Elm-style compiler error messages that pinpoint exact problem locations in the source code.

```mermaid flowchart TD accTitle: Spec Validation and Externs Pipeline accDescr: Shows how clojure.spec feeds type checks into the Google Closure Compiler and highlights the pain point of externs.

subgraph Compile["ClojureScript Compilation"] Spec["clojure.spec Metadata"] -->|"Emit basic static checks<br/>(nillable, map, vector)"| GCC["Google Closure Compiler"] Hooks["Public Compiler APIs"] -->|"Expose error locations"| Tools["Figwheel / Tooling<br/>(Elm-quality errors)"] end

subgraph Problem["External JS Ecosystem"] JS["Third-party JS / React Libs"] -.->|"Name minification without externs"| Break["Broken Production Builds"] end

GCC --> Break ```

The final hurdle Nolen introduces before pivoting is the persistent frustration of JavaScript interop: “Probably the largest source of incidental complexity in ClojureScript—ClojureScript is awesome, but there's things that are not awesome—is externs.” Whenever a developer incorporates an external library such as React, Highcharts, or a third-party npm package, advanced optimizations in the Google Closure Compiler rename unreferenced properties and break production releases unless explicit externs declarations instruct the minifier to preserve those exact symbol names. Nolen has begun prototyping native compiler solutions to remove this friction once and for all.

[47:17](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2837s) Eliminating Externs and Getting Involved in ClojureScript

David Nolen identifies externs as one of the last major pain points when integrating ClojureScript with third-party JavaScript libraries. Because Google Closure Compiler's advanced optimizations rename properties aggressively, missing an extern breaks production builds in subtle ways. Nolen admits that even he falls victim to this trap: “It's extremely error-prone, even I run into this: I do an advanced build, oh my god, I'm ready to go to production and it doesn't work because I missed an extern, right? It's a huge source of incidental complexity.” He views this as an entirely solvable problem and places automated extern inference on the near-term roadmap, noting that eliminating handwritten extern files will be a gigantic leap forward for seamless interoperability with the broader JavaScript ecosystem.

Achieving these milestones, however, depends on growing the contributor base. Nolen demystifies the contribution workflow, urging community members to submit a Clojure Contributor Agreement (CA) preemptively. He explains that unexpected edge-case bugs surface even after half a decade in production—such as persistent maps unexpectedly breaking past nine entries under specific conditions—and fixing them often requires just a trivial patch that any Clojure developer can write. For those wanting to collaborate, Nolen points to the `#cljs-dev` channels on IRC and the Clojurians Slack, encouraging newcomers to lurk, pick low-hanging fruit in JIRA, test open patches, and leave confirming comments.

- **Externs Roadmap**: The explicit goal is to completely remove the requirement of writing manual extern files for third-party JavaScript dependencies. - **Contributor Agreement**: Submitting a CA early ensures that when developers encounter a small bug, there is zero administrative friction preventing a patch submission. - **Low-Hanging Fruit**: Contributing does not require tackling complex compiler internals; testing existing JIRA patches or submitting trivial bug fixes provides immense value.

---

[49:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2953s) Normalizing Lisp, Giving Talks, and "Alien Technology"

Looking out at the audience of roughly 300 people, Nolen expresses excitement at the size of the gathering, observing that it rivals or exceeds many mainstream JavaScript conferences he attends. He reflects on his journey starting around 2008 with Common Lisp, which felt too eccentric and isolated for mainstream development. Clojure and ClojureScript fundamentally altered that perception. Today, seeing Clojure code discussed routinely on Hacker News, Reddit, and personal engineering blogs is completely normal. Nolen emphasizes that non-code advocacy—authoring blog posts about experiences with libraries like Reagent, Rum, or React Native—is among the most impactful contributions anyone can make toward technology adoption.

He also encourages developers to present ClojureScript at regional meetups and conferences. When the wider community actively promotes the language, core maintainers are freed from having to travel constantly to evangelize. In Nolen's view, pragmatic demonstrations matter far more than abstract rhetoric: “You can talk about fancy language features all day, but really developers are convinced when you show them something cool.” Concluding his talk, Nolen marvels that despite his years of working directly on the codebase, ClojureScript never loses its magic: “The reason I love ClojureScript is that every time I fire it up it really feels, even though I've contributed so much to it, it feels like alien technology; it feels like I can't believe you can do this stuff, it's so cool.”

- **Community Advocacy**: Writing tutorials and giving presentations at local meetups relieves the core team from carrying the entire promotional burden. - **Shared Tooling**: Nolen highlights that the core team dogfoods the exact same ecosystem tools as everyday users, including `lein-cljsbuild`, Boot, and Figwheel.

---

[51:50](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3110s) Q&A: Backporting ClojureScript Concepts into Clojure

An audience member asks whether the Clojure core team has considered backporting parts of ClojureScript into Clojure itself—specifically rewriting Clojure compiler internals in Clojure rather than Java, migrating Java-based persistent data structures, or moving protocols deeper into core.

```mermaid flowchart TD accTitle: Clojure and ClojureScript Compiler Relationship accDescr: Diagram illustrating how Rich Hickey's original ClojureScript implementation informs future Clojure-in-Clojure compiler designs. subgraph ClojureHistory["Historical Foundation"] C1["Rich Hickey writes original ClojureScript compiler"] C2["First concrete vision of Clojure-in-Clojure"] end subgraph Evolution["ClojureScript Evolution"] CS1["ClojureScript implemented in Clojure"] CS2["Refined protocol architecture & optimizations"] end subgraph FutureLoop["Future Architecture"] SPEC["Current focus: clojure.spec"] NEXT["Future Clojure compiler revisitation"] end

C1 --> C2 C2 --> CS1 CS1 --> CS2 CS2 -.->|"Feedback loop & lessons learned"| NEXT SPEC -.->|"Pushed to future cycles"| NEXT ```

Nolen explains that while there have been no formal discussions about copying code directly, ClojureScript's architecture is bound to influence future compiler designs. With `clojure.spec` serving as the primary engineering focus for the core Clojure team at the time, fundamental compiler redesigns remain on the back burner. However, Nolen points out that Rich Hickey himself authored the original ClojureScript compiler as his initial exploration of what Clojure written in Clojure would look like: “Rich wrote the first version of the ClojureScript compiler, so that was his idea of what a Clojure-in-Clojure would look like; so I'm convinced that whenever they go back to do it again, it's going to be heavily informed by how we did it in ClojureScript.”

---

[53:40](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3220s) Q&A: Mori and Its Influence on Immutable.js

Asked about where Mori fits into the history of ClojureScript, Nolen recounts extracting ClojureScript’s persistent data structures in 2012 to create a standalone library with an idiomatic JavaScript API for Node.js and browsers. The performance was striking: benchmarks demonstrated that constructing a persistent transient vector in Mori was faster than building a native mutable JavaScript array of one million elements on V8. Despite these numbers, JavaScript developers showed little interest for nearly two years.

That dynamic shifted dramatically with the emergence of React in 2014. Once developers realized that immutable data structures made component re-rendering checks trivial via reference equality (`===`), Mori suddenly gained traction. Nolen notes that Mori and his associated conference talks directly inspired Facebook to create Immutable.js: “It took two years before anybody in the JavaScript community cared about Mori, but with Mori, because I talked about Mori and I talked about React, I think a lot of that influenced Facebook to do Immutable.js.” He emphasizes that benchmarks alone rarely sway programmers; adoption usually requires an external catalyst like React to make the benefits immediately tangible.

- **Mori Origin (2012)**: Packaged ClojureScript persistent vectors, maps, and sets into an idiomatic npm/browser module. - **Benchmark Anomaly**: Transient vector instantiation outpaced native JavaScript mutable array creation at scale (1,000,000 elements). - **The React Catalyst (2014)**: Fast reference comparisons in virtual DOM architectures provided the missing real-world motivation for JavaScript developers to embrace immutable collections.

---

[55:47](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3347s) Q&A: The Status of JavaScript Module Support

An attendee asks about the status of native JavaScript module support worked on by Maria Geller during Google Summer of Code (GSoC) and whether that project still has momentum. Nolen clarifies that Geller is heavily committed maintaining `lein-cljsbuild` as well as Mori, leaving limited bandwidth for ongoing module development. While her GSoC implementation functions as originally presented—allowing developers to bundle AMD and CommonJS modules with measurable success—it faces maintenance challenges, including breaking interface changes introduced upstream by Google Closure Compiler that must be addressed when ClojureScript updates its compiler dependency.

Beyond compatibility fixes, Nolen articulates a far more ambitious end goal for module integration. The real benchmark is complete compatibility with Closure's dead-code elimination. Under this model, an engineer could import a single module like `react.Component`, and Google Closure Compiler would automatically strip away every unused line of React from the final production bundle. Nolen sums up the overarching vision: “That's the actual target, that we basically make the rest of the JavaScript world conform to us, which is that their code becomes optimizable. That's the real goal here, right? Is that you can take some random JavaScript library and you can now apply all the benefits that we have with ClojureScript code.”

[57:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3454s) Dead Code Elimination and Third-Party JavaScript

David Nolen explains the unique power of ClojureScript's compilation model when paired with Google Closure. Unlike the prevailing mindset in the broader JavaScript ecosystem, ClojureScript developers do not have to worry about fine-grained packaging just to keep bundle sizes manageable. If a developer pulls in a large ClojureScript library but only calls a single function, the compiler ensures that only that single function ends up in the final output. This whole-program dead code elimination frees developers from what Nolen terms the "myopic view of the world where you have micro-modules."

The ultimate goal is extending this exact same capability to code outside the ClojureScript ecosystem. Third-party JavaScript libraries—whose upstream architecture ClojureScript authors cannot control—should ideally be processed through Google Closure Compiler in the same aggressive way. Nolen emphasizes: “This is awesome we don't have this this myopic view of the world where you have micro modules we don't care because Google Closure eliminates all the stuff you don't use and I would like to be able to know that even third-party JavaScript libraries that we cannot control the development of we are able to apply this same optimization techniques to.”

[58:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3490s) Q&A: WebAssembly as a Potential Target

An audience member asks whether WebAssembly (Wasm) represents good news for ClojureScript. Nolen confirms that it is certainly not bad news, noting immediate and practical possibilities. Developers writing performance-sensitive numerical calculations or game engines could construct a specialized domain-specific language (DSL) that compiles directly to WebAssembly to yield hyper-optimized functions alongside standard ClojureScript code.

However, adopting WebAssembly as a full compilation target for ClojureScript presents significant technical hurdles. The fundamental constraint is garbage collection. Like Clojure on the JVM, ClojureScript fundamentally assumes the availability of an integrated, high-performance runtime garbage collector. Because WebAssembly lacks native GC integration, anyone targeting it directly would currently have to bundle and run their own garbage collector, which Nolen characterizes as a potential "performance nightmare." While the WebAssembly committee is well aware of this constraint and actively addressing it, any shift will take time. Nolen remarks: “If it becomes a desirable target there's no question we will target it if it if it's the right thing but it's cool it's is absolutely cool it definitely closes the gap in the types of performance you would get expect to get out of a browser environment.”

- Immediate potential: specialized DSLs for numeric computation or browser game engines. - Primary architectural obstacle: absence of built-in garbage collection in the early WebAssembly specification. - Long-term horizon: estimated at six to ten years (or sooner, depending on how fast the WebAssembly specification matures).

[59:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3574s) Q&A: Maria Geller's Work vs. Externs Inference

Another attendee asks whether Maria Geller’s Google Summer of Code project on module processing and the recently discussed externs inference work are competing, identical, or complementary approaches. Nolen clarifies that both efforts are complementary strategies attacking the broader JavaScript interop problem from different sides.

If a developer can directly consume modern ES6 modules through Google Closure Compiler, Google Closure understands the symbol references natively, which removes the need for externs altogether. However, the ecosystem remains messy: one ES6 library might work seamlessly out of the box, whereas another library might fail under advanced compilation. In cases where a stubborn library must simply be bundled as an un-optimized foreign dependency kept outside of advanced compilation, automated externs inference steps in to ensure ClojureScript code can call it without hand-writing error-prone extern files. David Nolen summarizes the unified goal of these tools: “All of these things are designed to make integration with the wider ecosystem better um but they're sort of attacking it from two different ways.”

```mermaid flowchart TD accTitle: JavaScript Ecosystem Integration Strategies accDescr: Diagram illustrating how Module Processing and Externs Inference handle third-party JavaScript libraries under Advanced Compilation.

subgraph Input["Third-Party JS Library"] JS["JavaScript Dependency"] end

subgraph Strategies["Integration Pathways"] MProcess["Module Processing (Maria Geller's Work)<br/>Direct ingestion of ES6/CommonJS modules"] ExtInf["Externs Inference<br/>Automatic inference of external JS calls"] end

subgraph Pipeline["Closure Compilation"] AdvComp["Google Closure Advanced Compilation<br/>Dead code elimination & symbol minification"] Foreign["Foreign Dependency Build<br/>Excluded from minification"] end

JS -->|"Supported ES6 Module"| MProcess MProcess --> AdvComp

JS -->|"Incompatible / External Script"| Foreign ExtInf -->|"Protects interop symbols"| Foreign AdvComp -.->|"Safely references"| Foreign ```

With the final questions answered, David Nolen closes the session by thanking the audience for their patience and attention over the presentation.

## Notable quotes > [49:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2953s) You can talk about fancy language features all day, but really developers are convinced when you show them something cool. — David Nolen

> [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) Probably the largest source of incidental complexity in ClojureScript—ClojureScript is awesome, but there's things that are not awesome—is externs. — David Nolen

> [14:31](https://www.youtube.com/watch?v=mty0RwkPmE8&t=871s) The cool thing about using persistent data structures to drive ClojureScript perf was that this is something that everybody's going to depend on. If we make this fast, then we know that we're actually delivering on performance. — David Nolen

## Mentioned Alex Miller, Ambly, AMD, binaryage/cljs-devtools, Boot, Bruce Hauman, Chas Emerick, Chris Granger, Chris Houser, Clojure, Clojure Contributor Agreement, ClojureScript, ClojureScript One, clojure.spec, Clojurians Slack, CoffeeScript, Cognitect, Common Lisp, CommonJS, Dart, Darwin, David Nolen, ES6, Evan Mezeske, Facebook, Figwheel, Florian Loitsch, Google Closure Compiler, Google Closure Library, Google Summer of Code (GSoC), Google Web Toolkit (GWT), Hacker News, Highcharts, Immutable.js, IRC, Java, Jeremy Ashkenas, JIRA, Jonathan Boston, JVM, KLIPSE, Lars Bak, László Török, Leiningen, lein-cljsbuild, Light Table, Maria Geller, Michał Marczyk, Mike Fikes, Mori, Nicola Mometto, Node-Webkit, Node.js, npm, Om, Parinfer, Plank, React, React Native, Reagent, Reddit, Relevance, Replete, Rich Hickey, Rum, Scheme2Js, Sean Grove, shadow-build (shadow-cljs), Shaun Lebron, The New York Times, Thomas Heller, tools.reader, V8, WebAssembly (Wasm), Windows

## Video description With five years behind us, the history of ClojureScript is already becoming murky. This talk attempts to document the many interesting landmarks along the way before we forget them. By pausing to reflect on how much ground we have collectively covered, we also hope to form a clearer picture of the next five years ahead of us. Spoiler alert: the best is yet to come!

[Source](https://www.youtube.com/watch?v=mty0RwkPmE8)

中文简报

David Nolen拟推自动化extern以降低ClojureScript使用阻力 ClojureScript旨在通过自动化extern推断来消除其最大的附带复杂性来源,使第三方JavaScript库符合其优化标准。 David Nolen详细阐述了ClojureScript自2011年推出以来的演进里程碑,包括向持久化数据结构的迁移、source map的实现、通过reader conditionals实现自举宿主,以及通过Light Table等实际工具完成验证。他指出了主要的痛点,强调Google Closure Compiler的高级编译和手动编写extern在过去曾给前端开发者带来沉重负担。展望未来,Nolen概述了以clojure.spec集成、自动化extern推断、编译器优化流程以及现代JavaScript模块无缝互操作为核心的重点方向。 推出五年后,ClojureScript在跨平台reader conditionals(.cljc)和完全消除JVM依赖的自举宿主编译器支持下,实现了与JVM上Clojure标准库的几乎完全对齐。 (34:21) 手动编写Google Closure extern仍是ClojureScript中最大的单一附带复杂性来源,这促使团队积极进行编译器原型设计,推进面向第三方JavaScript互操作的自动化extern推断。 (45:10) ClojureScript早期在持久化数据结构方面的成果启发了Mori,并在React普及了用于虚拟DOM diffing的引用相等性检查之后,直接影响了Facebook对Immutable.js的设计。 (53:40) 由于最初的技术规范缺乏原生运行时垃圾回收支持,直接面向WebAssembly仍被视作一项预计需6至10年的长期目标。 (58:10)

Detailed notes — zh

## Background 本内容由频道 Metosin 于 2016 年 9 月 16 日在 YouTube 平台发布。视频记录了 ClojureScript 首席开发者 David Nolen 在芬兰技术会议上的演讲,旨在梳理 ClojureScript 诞生前五年间鲜为人知的关键里程碑,并为接下来的五年演进方向描绘清晰蓝图。 ## TL;DR David Nolen 回顾了 ClojureScript 从 2011 年伴随 Rich Hickey 提出的“触达能力”(Reach)愿景诞生,一路克服写时复制低效、借助 Google V8 攻克原生持久化数据结构的艰辛历程。演讲详细记录了社区如何接力补齐 Source Maps、通过 Amble 涉足 iOS 移动端交互式编程,以及在读入器条件表达式推动下实现脱离 JVM 的编译器自举(Self-hosting)。同时,他剖析了 React 带来的生态爆发与 shadow-build 等独立项目的反哺作用,并明确指出未来五年将围绕 Clojure spec 语义对齐、编译器串行性能调优以及彻底消灭 Externs 文件以实现更无缝的 JavaScript 生态互操作展开深入探索。 ## Atmosphere & style 整场演讲洋溢着一种深沉却又充满激情的极客复盘氛围。David Nolen 既有身为核心掌舵人的从容坦诚,也有普通开源黑客在遭遇倦怠与技术瓶颈时的真实无奈;现场时不时穿插幽默自嘲与对社区同行者的由衷敬意。听众能够切身体会到一门前沿小众技术在面对主流质疑时,如何凭借一群纯粹开发者的浪漫执着,一步步跨越工程天堑并创造出如“外星科技”般的开发体验。 ## Bulletin - [05:20](https://www.youtube.com/watch?v=mty0RwkPmE8&t=320s) ClojureScript 诞生初期的核心使命是解决平台“触达能力”(Reach),突破 JVM 无法涉足的浏览器和移动端限制,并成为 Rich Hickey 践行“用 Clojure 实现 Clojure”与全协议化设计的首次实践。 - [11:58](https://www.youtube.com/watch?v=mty0RwkPmE8&t=718s) 早期因缺乏高效数据结构而采用写时复制,直到 V8 性能突破后将持久化数据结构移植并优化代码生成,使应用性能直接暴增 10 到 30 倍。 - [16:48](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1008s) Light Table 的开源展示了万行级大型桌面应用的构建能力,而 React 的兴起与不可变数据理念契合,促成了 ClojureScript 生态的大爆发并反哺催生了 Immutable.js。 - [34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) 随着 Clojure 1.7 读入器条件表达式(cljc)落地,ClojureScript 成功实现完全自举,摆脱 JVM 依赖并催生了 Klipse、Plank 及移动端 REPL 工具 Replete。 - [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) 未来核心演进聚焦消除 Externs 带来的附带复杂性,结合 spec 推进类型推断,并利用 Google Closure Compiler 实现第三方 JavaScript 依赖的死代码消除(DCE)。 ## Key takeaways - [02:56](https://www.youtube.com/watch?v=mty0RwkPmE8&t=176s) 2011 年前端主流技术被 jQuery 和 Rails 垄断,CoffeeScript 改变了社区对“编译到 JS”的偏见,但已有 Lisp 转译工具普遍缺失宏系统支持。 - [05:20](https://www.youtube.com/watch?v=mty0RwkPmE8&t=320s) Rich Hickey 确立了 ClojureScript 的战略核心为“触达能力”(Reach),以协议(Protocols)作为最底层基石,成为 Clojure-in-Clojure 雏形。 - [07:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=454s) David Nolen 凭借 8 行优雅的 `reify` 宏补丁赢得了提交权限,早期技术选型押注 Google Closure 体系,虽技术严密但在当时前端认知中门槛极高。 - [09:55](https://www.youtube.com/watch?v=mty0RwkPmE8&t=595s) 社区工具 `lein-cljsbuild` 的出现降低了手动克隆和脚本配置门槛,推动 Clojure 开发者正式接纳 ClojureScript 进行项目开发。 - [11:58](https://www.youtube.com/watch?v=mty0RwkPmE8&t=718s) 从手写 JS 原型到纯 CLJS 实现,数据结构的移植推动了编译器算术运算内联与代码生成优化,全面替代了低效的写时复制机制。 - [16:48](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1008s) Chris Granger 开发的 Light Table 开源了逾万行 CLJS 代码,以硬核事实向外界证明该语言具备承载复杂生产级桌面应用的能力。 - [19:32](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1172s) 早期 Java Reader 缺失列号信息导致浏览器 Source Maps 陷入死局,社区通过 pure Clojure 的 `tools.reader` 重写并接力攻关 Base64 VLQ 格式破局。 - [24:52](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1492s) Maria Geller 突破性地向严格的 Google Closure Compiler 主干合入补丁,为 ClojureScript 接入 AMD 与 CommonJS 模块铺平道路。 - [28:09](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1689s) 开源项目的志愿开发模式导致高难度旧代码如 `clojure.pprint` 和官方单元测试框架被搁置长达四年,最终依靠社区补丁补全标准库。 - [31:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1905s) Mike Fikes 打造的 Amble 结合 Bonjour 发现与 WebDAV 编译同步,让基于套接字的热重载开发体验首次原生地延伸至 iOS 设备终端。 - [34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) 读入器条件表达式(.cljc)使编译器得以自编译,自举不仅摆脱了 JVM 依赖,还催生出轻量 REPL(Plank、Replete)和网页端交互工具(Klipse)。 - [38:30](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2310s) React 的虚拟 DOM 与不可变数据结构的天然契合引发了 UI 库的寒武纪爆发,使 ClojureScript 在前端架构理念上反向领跑主流生态。 - [40:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2445s) Thomas Heller 开发的独立竞品 shadow-build 先行探索了代码分割和宏自动推断,成为官方编译器汲取创新的重要灵感池。 - [41:46](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2506s) 团队将“与 Clojure 保持一致”(如跟进 clojure.spec)列为最高优先级,同时在编译器上寻求 2 倍以上的单核串行编译性能优化空间。 - [47:17](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2837s) 消灭手动编写 Externs 声明文件的附带复杂性是近期研发核心,旨在彻底打通全量 JavaScript 生态并在 Advanced 构建下自动保护外部属性。 - [53:40](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3220s) Mori 库的基准测试虽然证明了不可变结构的极致性能,但直到 React 面世才真正引爆认知,并直接启发了 Facebook 团队打造 Immutable.js。 - [55:47](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3347s) JavaScript 模块支持的终极目标是对大型第三方库(如 React)应用高级死码消除(DCE),实现按需打包而非被迫拆分微模块。 - [58:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3490s) WebAssembly 短期内适合作为 DSL 目标用于高性能密集计算,但受制于缺乏原生内置 GC 支持,短期内尚不能作为 ClojureScript 的直接宿主编译目标。 ## Detailed walkthrough ### [00:02](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2s) 开场与 ClojureScript 的五年回顾 David Nolen 在芬兰的会议上作为当天的最后一位演讲者登台。他表示这次会议非常棒,自己也是第一次来到芬兰,体验十分愉快。这场演讲并非纯技术细节的深剖,而是聚焦于 ClojureScript 走过的历史道路。为了摸底听众对这门技术的涉猎时长,David 让现场观众举手示意:使用 ClojureScript 达到五年、四年、三年、两年的开发者依次递减,而绝大多数举手者都集中在最近的一到两年内。David 指出,这意味着大多数人并不熟悉 ClojureScript 早期的发展史。这是一段曲折漫长的历程,梳理这些早期的历史亮点不仅有趣,也能让大家看清 ClojureScript 到底是如何演进的。 关于个人背景,David Nolen 是 Cognitect 的软件工程师兼 ClojureScript 的首席开发者。Cognitect 作为一家软件咨询公司,负责维护和掌舵 Clojure 与 ClojureScript 的发展,同时还推出了分布式数据库产品 Datomic。在演讲前几周,ClojureScript 终于上线了自己的独立官网(clojurescript.org)。David 特别向推动此事的 Alex Miller 致谢:他们复用了 clojure.org 的基础设施与页面设计,并针对 ClojureScript 的特性调整了内容。对于长期使用者而言,ClojureScript 的技术实力和稳定性早已无需多言,但这样一个崭新的官方门户,标志着它终于拥有了一个对初学者友好的公开门面,“让人觉得 ClojureScript 真的成熟长大了”。每当 David 自己在工作中使用 ClojureScript 时,不论是配合 Figwheel 进行交互式开发还是构建项目,尽管身为编译器开发者,他依然觉得这一切如同魔法般不可思议。团队翻越了一座难以置信的技术高山,而早期的诸多探索细节更是鲜为人知。 - 参会听众大多是在最近 1 到 2 年才开始接触 ClojureScript,对 5 年前的早期历史知之甚少。 - Cognitect 统筹管理 Clojure 和 ClojureScript 的开发,核心产品包括 Datomic。 - Alex Miller 主导利用 clojure.org 现有的架构和设计,推出了 ClojureScript 专属的官方网站。 --- ### [02:56](https://www.youtube.com/watch?v=mty0RwkPmE8&t=176s) 2011年的前端环境与追寻 Lisp 的前端足迹 回溯到 2011 年,David 当时还没有全职从事 Clojure 开发,而是在《纽约时报》(The New York Times)编辑部的新闻互动团队(Interactive News)编写新闻应用。当时团队的主流技术栈是 Ruby on Rails、原生 JavaScript 以及盛极一时的 jQuery。巧合的是,David 当时与 Jeremy Ashkenas 处于同一个团队,而 Jeremy 正是因开发了 CoffeeScript 而名声大噪。在那个时期,虽然 Google 推出了可以将 Java 编译为 JavaScript 的 GWT(Google Web Toolkit),但“编译到 JavaScript”这一概念在广大主流前端工程师眼中仍然显得格外边缘和疯狂。 Jeremy 的 CoffeeScript 彻底改变了前端圈的偏见,让人们意识到将其他语言编译到 JavaScript 并不是异想天开的怪念头,《纽约时报》内部也开始在项目中间歇性地尝试 CoffeeScript。作为一名坚定的 Lisp 爱好者,David 对 Ruby 并没有特别深厚的热情,只是用它来完成日常工作,他真正渴望的是一款能编译到 JavaScript 的优雅 Lisp。当时 Clojure 还只是他的业余爱好,尽管 Chris Houser(Chouser)曾写过一个极早期的实验性原型也叫 ClojureScript,但那还远未达到可以用于生产的成熟度。随后 David 发现了 Florian Loitsch 开发的 scheme2js——一个几乎完全符合 R5RS 规范的 Scheme 到 JS 编译器(Florian Loitsch 后来加入 Google 并参与了 Dart 到 JavaScript 的 dart2js 编译器研发)。然而 scheme2js 存在一个令 David 无法接受的硬伤:它缺乏宏系统(macros)。 > “我彻底被 Clojure、Common Lisp 以及正统 Scheme 给征服了,我就想:‘哎,我才不要用这个,它连宏都没有。’”——David Nolen 失望之余,David 本打算继续忍耐使用 CoffeeScript。但就在 2011 年 5、6 月份刚调研完 scheme2js 不久,Relevance 公司便预告即将在纽约当地的 Clojure NYC 用户组 Meetup 上发布重磅消息。 - 2011 年的主流前端以 jQuery 和 Ruby on Rails 为绝对核心。 - Jeremy Ashkenas 在《纽约时报》与 David 同组期间打造了 CoffeeScript,打破了业界对“JS 转译语言”的抗拒。 - scheme2js 实现了极高标准的 R5RS Scheme 规范,但由于缺失宏系统,未能满足 David 对现代 Lisp 的需求。 --- ### [05:20](https://www.youtube.com/watch?v=mty0RwkPmE8&t=320s) 触达、自举雏形与协议:ClojureScript 的诞生 2011 年 7 月,在 Clojure NYC 史上参会人数最多的聚会之一上,Rich Hickey 正式向世界发布了 ClojureScript。Rich 在演讲中阐述的宏大愿景,在历经五年后依然字字珠玑。ClojureScript 最核心的出发点就是“触达能力”(Reach)。虽然 Clojure 依托 JVM 取得了巨大成功,甚至让很多原本排斥 JVM 的开发者重新认识了这套运行时的强大,但 JVM 存在不可忽视的生态边界。在很多平台上,JVM 根本不可能获得入场券——例如苹果对 iOS 原生应用开发有着极度严苛的限制,而在浏览器端,Java Applet 早已退出历史舞台。想要跨越这些物理限制渗透到客户端与网页,JavaScript 成为了唯一的通用载体。 ```mermaid flowchart TD accTitle: ClojureScript 早期架构与愿景 accDescr: 展示 Rich Hickey 在 2011 年提出的 Reach 愿景及自举编译器技术构成 subgraph Platform["运行平台触达 (Reach)"] JVM["JVM 平台<br/>(Clojure 既有阵地)"] NonJVM["JVM 无法触及的宿主<br/>(浏览器 / iOS / Web 客户端)"] JS["编译目标: JavaScript"] JVM -.->|"无法直接运行"| NonJVM JS -->|"无缝渗透"| NonJVM end subgraph Implementation["ClojureScript 核心实现"] CljLang["完全使用 Clojure 编写<br/>(Clojure-in-Clojure 雏形)"] ProtoCore["以 Protocols (协议) 为最底层核心"] CljLang --> ProtoCore end Implementation -->|"编译输出"| JS ``` 另一个颠覆性的核心思路在于,Rich Hickey 将 ClojureScript 视作“用 Clojure 实现 Clojure”(Clojure in Clojure)的首次大练兵。以往 Clojure 的底层实现、编译器以及核心数据结构绝大部分都是用 Java 编写的,而 ClojureScript 则是首个完全使用 Clojure 语言自身构建的方言分支。更重要的是,Rich 将协议(Protocols)作为了整个语言构建的最底层基石。早在 2011 年 1 月,Rich 就在 IRC 频道里突兀地抛出过一句:“如果存在一个以协议为底层基础的 Clojure 版本会怎样?”随后他便悄然隐退,直到六个月后的这次发布,社区才彻底看懂他当时埋下的伏笔。 > “Rich 谈到 ClojureScript 时,把它视作这种‘用 Clojure 编写 Clojure’理念的第一次尝试。”——David Nolen - ClojureScript 的核心使命是打破 JVM 在客户端(如 iOS、现代 Web 浏览器)的禁锢,实现最大化的运行环境“触达”(Reach)。 - Clojure 依托 Java 编写底层,而 ClojureScript 是首个完全由 Clojure 编写编译器与数据结构的 Clojure 方言。 - 语言运行时全面建立在多态协议(Protocols)基础之上,实现了高度模块化和可扩展的基础层。 --- ### [07:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=454s) 提交 reify 补丁与早期技术落差 在 ClojureScript 正式发布两到三个月后,David Nolen 开始上手折腾。他拉取了代码仓库,运行起内置脚本和 REPL,想要写代码时敲下了一个 `reify`,结果终端立刻报错崩溃——当时的实现里根本还没有支持 `reify`。David 跑到邮件列表里询问为什么没有 `reify`,得到的回复轻描淡写:“只是还没来得及做而已。”David 随即表示自己愿意提交补丁。起初他十分惶恐,以为 ClojureScript 编译器的内部一定极其艰深晦涩,可能需要耗费数周时间才能摸清门道。然而当他打开宏定义文件仔细查阅后,惊喜地发现里面的代码完全就是平实纯粹的 Clojure,逻辑干净利落。 David 最终仅用了大约八行代码(除去空行)就写出了 `reify` 的 `defmacro` 宏实现。这份简洁优雅的补丁让 Rich Hickey 和 Chris Houser 赞不绝口,也正是这八行代码直接为 David 赢得了 ClojureScript 代码仓库的提交权限(commit rights)。从那时起,David 顺理成章地承担起了审查 JIRA 工单、确保社区补丁平稳合并的日常维护工作。在最初的两年里,项目的生机完全维系在人们对它的信念上:初版 ClojureScript 虽然展现出了巨大的潜力,但整体功能还非常羸弱,很多基础设施亟待补齐。 更棘手的挑战在于技术选型与主流认知的脱节。在典型的一贯风格下,Rich Hickey 坚持做出了在技术层面上极其坚实周密的架构决策,但代价是这些选择完全背离了当时主流前端工程师的认知习惯。2011 年的前端世界几乎被 jQuery 统治,而 Rich 却引入了绝大多数普通前端开发者听都没听过的重型工具链:Google Closure Compiler 与 Google Closure Library。这种巨大的陌生感构筑了高耸的学习门槛。为了打破这堵高墙、拉近与大众开发者的距离,Relevance 随后着手推出了名为 ClojureScript One 的集成项目。 > “最初发布出来的那个东西,虽然展现出了巨大的希望,但并没有具备多少功能;前路漫漫,但在当时它实际上已经挺有用了。”——David Nolen - David Nolen 凭借仅 8 行代码的 `reify` 宏补丁,一举赢得了 ClojureScript 项目的长期提交权限。 - 项目早期开发节奏平缓,极度依赖社区先锋开发者在 JIRA 上的稳定贡献与维护。 - 架构全面押注 Google Closure Compiler 和 Google Closure Library,技术上极其严谨优秀,但在 2011 年的前端 jQuery 生态中显得非常前卫且晦涩,促使 Relevance 后来打造了 ClojureScript One 来降低上手难度。 ### [09:55](https://www.youtube.com/watch?v=mty0RwkPmE8&t=595s) Google Closure 的正名与 lein-cljsbuild 带来的生态拐点 早期的 ClojureScript 示例项目并不是现成的工具,而只是一个用来证明“可以用它构建合理应用”的模板项目。这个模板展示了当时很多开发者向往的 jQuery 等库的功能,其实在 Google Closure Library 中早已一应俱全。David Nolen 强调,Google Closure Library 至今仍由 Google 重度维护与使用,Google 几乎所有的 JavaScript 应用程序都是靠 Closure Library 和 Closure Compiler 搭建的,里面蕴含着海量的工程积累。这一示范让一部分开发者开始转变观念,意识到“依托 Closure Library 也许并不是个坏主意”。 然而在当时,使用体验依然非常别扭。到了 2011 年,构建工具 Leiningen 已经在 Clojure 社区席卷全场,如 David Nolen 所言:“如果一个东西不是 Leiningen 插件,大家基本就不会去用它”(“if it wasn't a Leiningen plugin chances are nobody was going to use your thing”)。在没有顺手集成工具前,开发者想把 ClojureScript 接入项目,就必须手动克隆仓库并运行一堆自定义脚本,极其繁琐且毫无乐趣。后来,Evan Mezeske 开发了 `lein-cljsbuild` 插件,允许开发者在 Ring 应用中通过添加一个插件即可轻松构建 ClojureScript,极大地拉低了门槛。直到发布后大概八九个月,Clojure 开发者们才真正抱着“那我来试试看”的心态投入进来,社区的势头才真正开始汇聚。 - Google Closure Library 蕴藏着巨大的工程财富,直接覆盖了原本需要借助 jQuery 才能完成的大多数功能。 - `lein-cljsbuild` 解决了集成 ClojureScript 编译器需要克隆源码、执行自定义脚本的痛点,后来该项目交由 Maria Geller 维护。 --- ### [11:58](https://www.youtube.com/watch?v=mty0RwkPmE8&t=718s) 突破性能藩篱:从“写时复制”到原生持久化数据结构 很多人可能不知道,ClojureScript 在诞生后的近第一年里,并没有真正的持久化数据结构(Persistent Data Structures)。当时它为了提供与 Clojure 相同的接口,采用的是非常简单、低效且笨重的完整写时复制(copy-on-write)机制。2011 年前后,由于 JavaScript 性能革命刚起步,外界对在 JS 引擎上跑高性能不可变结构充满怀疑。但 Google 当时组建了一支由顶级编译器专家领衔的攻坚团队,其中的负责人 Lars Bak 曾主导开发过 JVM 的 HotSpot 虚拟机和 Self 语言系统,深耕优化编译器达数十年之久。在 V8 引擎带来的巨大性能跨越背景下,ClojureScript 团队开始思考:如果将 Clojure 中相对简单、约 400 行 Java 代码的 `PersistentVector` 手工移植为原生 JavaScript,在 V8 上跑出的基准测试会是怎样? László Török 动手完成了这份 JS 手写移植。测试结果令人惊喜:手写实现的性能甚至没有比 JVM 差出一个数量级,大概只比 JVM 慢 4 倍左右。紧接着,László 又用 200 行 ClojureScript 代码对该 JS 版本进行了镜像移植,拉开了在宿主方言中用自身语言编写不可变数据结构的序幕。在排查“为什么移植成 ClojureScript 后比手写 JS 慢了 3 倍”的过程中,David Nolen 顺藤摸瓜优化了编译器的代码生成(Codegen),补齐了算术运算内联和函数调用开销优化,最终将差距压缩到仅比手写 JS 慢 20% 到 30%。这不仅证明了持久化数据结构在 V8 上的可行性,也让编译器优化落到了最核心的基础设施上,因为正如 David Nolen 所说:“如果把这个做快了,我们就确信自己兑现了性能承诺”(“if we make this fast then we know that we're actually delivering on performance”)。 随后,波兰数学家兼 Clojure 程序员 Michał Marczyk 接过了重担,逐一将 Clojure 的所有持久化数据结构完整移植为 ClojureScript 版本。经过一年零几个月的打磨,当开发者们更新自己的应用时,惊喜地发现程序性能直接暴增了 10 倍、20 倍乃至 30 倍。 ```mermaid flowchart TD accTitle: Persistent Data Structure Porting and Optimization accDescr: Flowchart showing how Persistent Vector went from Java to JavaScript, then into ClojureScript, driving compiler optimizations. subgraph Phase1["第一阶段:可行性验证"] A["Clojure 的 Java 实现<br/>(约 400 行代码)"] -->|"手写移植到 JavaScript"| B["László Török 的 JS 原型"] B -->|"在 V8 引擎上测试"| C{"基准测试表现良好<br/>(仅比 JVM 慢 4 倍)"} end subgraph Phase2["第二阶段:CLJS 原生化与编译器调优"] C -->|"移植为 ClojureScript<br/>(约 200 行代码)"| D["CLJS 原生实现"] D -->|"发现比手写 JS 慢 3 倍"| E["David Nolen 优化编译器<br/>(内联算术运算、削减调用开销)"] E -->|"性能缩小至仅慢 20-30%"| F["CLJS 编译器 Code-Gen 升级"] end subgraph Phase3["第三阶段:全面移植"] F --> G["Michał Marczyk 负责全部移植"] G --> H["全套持久化数据结构落地<br/>(整体应用提速 10-30 倍)"] end ``` - 早期写时复制机制性能低下,直到 2011 年 Google V8 的突破让高性能不可变数据成为可能。 - 移植工作形成了良性循环:编写最核心的数据结构反向暴露了 ClojureScript 代码生成器的软肋,从而倒逼编译器底层大幅优化。 --- ### [16:48](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1008s) 主流视角的困惑与 Light Table 的破局震撼 尽管持久化数据结构的完成让 Clojure 社区内部群情激奋,但在 2011 年,主流开发圈对此毫无感知。在当时,Facebook 尚未推出 Immutable.js,普通开发者对“持久化数据结构”毫无概念。David Nolen 形象地描绘了主流开发者的漠然心态:“他们会觉得‘行吧,听上去挺计算机科学的,挺高深,可你们到底用这玩意儿做出了啥?这不就是一堆括号的 Lisp 么?拿个东西出来给我瞧瞧’”(“they're like okay that sounds cool it's computer sciency that's neat but like what are you doing with this thing this is this list what are you actually making show me something”)。正经的工程师只关心新技术能否帮他们解决现实问题,并展示它如何比手头的工作流更加优秀。 打破这一困局的关键转折点是 Light Table 的横空出世。Light Table 由 Chris Granger 打造,凭借革命性的交互式开发理念和行内求值特性席卷了整个编程界,其大量创新理念甚至被后来的 Swift Playgrounds、Xcode 以及 IntelliJ 争相借鉴借鉴。最令外界震惊的是,Chris Granger 将整套庞大复杂的编辑器完全用 ClojureScript 写就,开源时包含了大约 1.1 万到 1.2 万行 ClojureScript 代码,并且深度集成了 Node-WebKit。这一硬核实例向全世界证明了 ClojureScript 完全能够驾驭严肃、复杂且令人惊叹的真实桌面级大型应用,一举打破了内外部的技术偏见,推动更多人开始认真审视并采用这门语言。在这一里程碑之后,话题开始转向更深入的“用 Clojure 构建 Clojure”(Clojure-in-Clojure)构想。 - 在 Immutable.js 诞生之前,主流编程界缺乏对数据不可变性的认知,CLJS 急需杀手级应用证明实用性。 - Light Table 开源时拥有约 1.1 万至 1.2 万行 ClojureScript 代码,结合 Node-WebKit 构建,彻底证明了该语言在超大前端与桌面项目上的承载能力。 ### [19:32](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1172s) 自举雏形、调试困境与 Clojure Reader 的列号缺失 自 ClojureScript 诞生之初,自举(Bootstrap)就一直是一个隐约可见的可能性,但前路困难重重。在项目迈入两周年之际,一个直接影响日常调试的严重障碍暴露了出来。当时开发者们看着 Light Table 的演示惊叹不已,开始用 `cljsbuild` 尝试 ClojureScript,但只要运行时报错,开发者看到的尽是一堆像天书般不可读的生成代码。David Nolen 强调,ClojureScript 不是 CoffeeScript,从没打算生成可供人阅读的 JavaScript:“I specifically said earlier the only thing we cared about is how fast is it going to be you know like that's all we cared about was performance we didn't care about is this something for humans to look at.” 为了让代码变得可调试,引入 Source Maps 成为了迫切需求。 然而,ClojureScript 在头整整两年中完全没有 Source Maps 支持。除了早期浏览器本身支持不够成熟之外,更深层的瓶颈出在编译器架构上:ClojureScript 直接复用了 Clojure 用 Java 编写的标准 Reader。负责把文本转换成数据结构的 Reader 会给每个符号(Symbol)和 S-表达式(S-expression)附加上文件和行号信息,却唯独没有记录列号(Column)。没有精准的列号,浏览器里的 Source Maps 映射根本无法正常工作。由于寄生在主干 Clojure 的 Java Reader 上,而 Clojure 官方核心团队有自己的优先级考量,增加列号并非当务之急,整个 Source Maps 的工作因此彻底卡死。 ```mermaid flowchart TD accTitle: Source Maps 前置依赖与协作流程 accDescr: 展示 ClojureScript 解决 Source Maps 阻塞问题中社区成员的分工协作流 subgraph Bottleneck["原架构瓶颈"] A["Clojure Java Reader"] -->|"仅标注文件名与行号"| B["缺少列号 (Column) 信息"] B -->|"无法生成精确 Source Maps"| C["浏览器调试体验极差"] end subgraph CommunitySolutions["社区接力解决"] D["Nicola Mometto (Br读者项目)"] -->|"重构为纯 Clojure 实现"| E["tools.reader (支持列号)"] E -->|"David Nolen 耗时两周攻关"| F["Source Maps 基础实现 (遭遇 Base64 VLQ 瓶颈)"] F -->|"Sean Grove 接棒推进至 98%"| G["两周年节点: 完整 Source Maps 落地"] end B -.->|"替换底层"| D ``` ### [21:26](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1286s) Nicola Mometto 与 Sean Grove 的社区接力拯救计划 僵局最终由社区破局。当时 Nicola Mometto 开发了一个名为 Breader 的项目,完全用纯 Clojure(而非 Java)原汁原味地重写了一遍 Reader。这一成果带来了双重利好:一方面,纯 Clojure 代码日后移植到 ClojureScript 会变得极其平滑;另一方面,它脱离了 Clojure 核心库的发布周期限制。David Nolen 于是说服 Nicola 将其转为官方 Contrib 项目 `tools.reader`,并请求他在其中补齐了列号记录。解决 Reader 的阻塞后,编译器底层直接无缝替换掉了原有的 Java Reader。 接下来是恶梦般的编码过程。2012 年时 David Nolen 还在《纽约时报》(The New York Times)任职,只能靠业余的夜晚和周末推进。Source Maps 底层采用了类似 MIDI 编码思想的 Base64 VLQ(Variable-Length Quantity)位压缩格式,调试起来极其折磨人。在连续高强度死磕了两周后,因感到孤立无援与筋疲力尽,David 陷入了严重倦怠,直接将这个项目搁置了两个月:“ debugging it's really ter a terrible experience and I got burned out even after two weeks of like doing this and the week like ah nobody's helping me I'm just like the only person that cares about this working and no there nobody's helping me and so I I set it aside for like two months even though made like a lot of progress”. 随后,社区再次站了出来。开发者 Sean Grove 正在用 ClojureScript 编写商业产品,同样快被底层混乱的 JavaScript 代码逼疯,他在 IRC 上主动向 David 询问:“I see that you basically did all the foundational work for Source mapping what is it going to take to finish it”。Sean Grove 接棒直接把进度推到了 98%,David 随后收尾完成了最后的 2%。就在两周年刚过一个月时,ClojureScript 终于迎来了完整的 Source Maps 支持。如今在 Chrome 中,开发者能直接看到带有语法高亮的 Clojure 代码并自由下断点、单步调试,在浏览器里重现了类似 Lisp 机器的开发体验。 ### [24:52](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1492s) 前瞻性布局:Maria Geller 与 JS 模块生态互操作 除了应对当务之急,ClojureScript 也必须进行长远布局。当时前端领域出现了严重的模块格式碎片化:ES6 规范逐渐普及并被越来越多库采用,而外部生态中又充斥着 AMD、CommonJS 以及 Node.js 定制的 CommonJS 变体。如果想无缝使用 npm 模块或 ES6 库,编译器就必须拥有一套通用的模块支持机制。David Nolen 预料到这在未来几年内将是生死攸关的能力,于是借由 Google Summer of Code(GSoC)设立了该研究课题。 当时刚学 Clojure 仅三个月的 Maria Geller 揽下了这项艰巨的任务。在短短一个夏天的周期里,她迅速成长为编译器的核心专家,甚至成功向 Google 内部极其严格的 Google Closure Compiler 主干提交了补丁: - Google 内部高度依赖 Closure Compiler,任何导致内部测试失败的 PR 都会被自动化流水线直接回滚,向其合并补丁门槛极高。 - Maria Geller 成为极少数甚至可能是唯一一位成功将代码合并入 Google Closure Compiler 官方仓库的 ClojureScript 贡献者。 - David Nolen 借此鼓励大家参与贡献,指出编译器内部其实也是常规的 Clojure 数据结构(如 Multi-methods、Maps、Vectors),并不像大家想象的那样高深莫测,并极力推荐观看 Maria Geller 去年在 Clojure/conj 上关于编译流水线剖析的精彩演讲。 ### [28:09](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1689s) 开源的另一面:被搁置四年的 clojure.pprint 讲完社区并肩作战的高光时刻,David Nolen 话锋一转谈到了开源软件残酷现实的一面。他引用了关于 Rich Hickey 的观点指出:“basically what happens with open source is you work on stuff when you want to work on it because nobody's paying you to do it right um and sometimes that means things things get left undone for a very very long time”。因为没有人为此付费,开发者全凭个人意愿驱动,一旦某个关键功能缺乏足够的乐趣或难度过高,它就会被长年搁浅。 其中最典型的例子就是 `clojure.pprint`(代码格式化打印库)。在 Clojure 生态中,几乎所有的外围开发工具都在间接或直接依赖它,但这个极其核心的库在 ClojureScript 里竟被足足搁置了四年没有人去移植。David Nolen 直言不讳地承认,之所以自己一直硬不下心去碰它,完全是因为如果有人亲自翻开过那份原始实现的代码库,就会明白那是一件多么令人望而生畏且头疼的事情。 ### [28:50](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1730s) 补齐核心标准库:pprint 迁移与官方测试框架的落地 Clojure 的漂亮打印库(`clojure.pprint`)最初是在 2009 年用 Clojure 编写的,深植了当年的编程风格,甚至还使用了现在许多人从未听说过的 `defstruct`。它本质上是从一段 Common Lisp 漂亮打印机移植过来的 3000 行 Clojure 代码。David Nolen 直言,过去每次打开那段代码的标签页,都会因为望而生畏而默默关掉页面:“每次我看它,我都会关掉标签页,我心里想‘我实在没法逼自己干这事’。”因此这个功能搁置了很久。这给转到 ClojureScript 的开发者带来了极糟糕的体验:大家习惯了 Clojure 丰富的标准库,到了 ClojureScript 却发现基础的漂亮打印缺失了。特别是在使用 Reagent、Rum 或 Om 这类框架开发时,应用程序往往维护着一个庞大的状态 Atom,开发者急需对整个应用状态进行漂亮打印以便排查,而无需为了看个数据“把自己的头发点着”。最终,社区成员 Jonathan Boston 和 Shaun Lebron 挺身而出,提交了一个约 3000 行的巨大补丁,终于将 `pprint` 完整移植到了 ClojureScript。 与此同时,ClojureScript 另一个被搁置长达四年的领域是单元测试。在 Clojure 1.0 之前,Rich Hickey 就为函数引入了测试元数据(test metadata),将测试视为语言的一等公民;但在 ClojureScript 中,官方测试库长期处于空白状态。虽然 Chas Emerick(O'Reilly《Clojure Programming》一书的合著者)曾编写过优秀的第三方测试工具,但对终端用户而言,不得不为了基础测试引入第三方依赖是极不合理的。最终 David Nolen 亲自编写并补齐了内置测试功能。这是官方核心命名空间拼图的最后一块,自此之后,除了多线程相关特性外,开发者可以合理预期 ClojureScript 具备 Clojure 的几乎所有核心功能。 - `pprint` 涉及把 2009 年带有 Common Lisp 历史痕迹、采用 `defstruct` 的 3000 行旧代码重构成适合 ClojureScript 的现代实现。 - 整个基础核心库与测试体系补齐经历了四年,“如果你是在 2016 年才接触 ClojureScript,你真的很幸运,你避开了许多动荡。” --- ### [31:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=1905s) 拓展至移动端:Mike Fikes、Amble 与 iOS 上的即时交互编程 在发布之初,Rich Hickey 就宣称 ClojureScript 关乎“触达能力”(reach),有望用于解决 iOS 与 Android 等移动平台的开发问题;然而整整四年过去,几乎没有人真正拿它在移动端做成实质性的产品。推动这一局面转变的关键人物是 Mike Fikes。他不仅成功使用 ClojureScript 将应用发布到了苹果 App Store,还为 iOS 端 ClojureScript 的开发体验打造了大量基础设施(相关成果随后也被一定程度复用到了 Android 上)。 为了实现顺畅的移动端开发,Mike Fikes 构建了名为 Amble 的工具。为了支持 Amble 的 REPL 服务器,ClojureScript 团队专门重构了底层的 REPL 机制,使其更容易定制。Amble 展现了一种优雅的移动开发范式:当你在桌面终端启动 REPL 时,运行在 iOS 上的应用会通过 Bonjour(ZeroConf / mDNS)在 Wi-Fi 局域网内自动广播并发现设备;桌面端显示可连接的设备编号,开发者键入数字即可建立连接。该架构通过套接字直接连入移动端的 JavaScriptCore,并在桌面端编译源文件,利用 WebDAV 将编译产物同步到 iOS 设备上。除了最开始需要借助 Xcode 完成启动打包外,后续的日常开发完全脱离了 Xcode,让 Clojure 标志性的实时热重载(live coding)首次无缝运行在真实的 iOS 环境中,配合 React Native 的巨大潜力,兑现了五年前关于触达移动生态的承诺。 ```mermaid flowchart LR accTitle: Amble iOS REPL 架构图 accDescr: 展示桌面端与 iOS 设备之间通过 Bonjour 发现、Socket 交互以及 WebDAV 文件同步的通信机制。 subgraph Desktop["桌面开发环境"] D_REPL["Amble 自定义 REPL"] Compiler["ClojureScript 编译器"] end subgraph Network["局域网通信"] MDNS["Bonjour / mDNS (广播发现)"] Sock["Socket 连接"] WD["WebDAV 文件同步"] end subgraph Mobile["iOS 设备端"] JSC["JavaScriptCore 运行时"] App["宿主应用"] end App -->|自动广播| MDNS MDNS -->|发现设备| D_REPL D_REPL <-->|交互求值| Sock Sock <-->|执行代码| JSC Compiler -->|同步编译产物| WD WD -->|加载代码| App ``` --- ### [34:21](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2061s) 自举与读入器条件表达式:摆脱 JVM 的 Self-Hosted ClojureScript 在最初的四年里,ClojureScript 甚至没有正式的语义化版本号,仅依靠 Git 的提交修订号作为版本标示(正式版本引入前最后一个版本号高达 3225 左右)。转变成正式版本号的转折点,是 Clojure 核心团队在 1.7 版本中正式发布了“读入器条件表达式”(reader conditionals)。此前 Clojure(`.clj`)和 ClojureScript(`.cljs`)虽然本质是同一种语言,但缺乏官方的代码共享机制,只能依赖各种并不完美的黑客工具;而 `.cljc` 文件的引入彻底打破了壁垒。 读入器条件表达式发布后,David Nolen 立即升级了 ClojureScript 中的依赖版本,决定直接让编译器编译自身:“读入器条件表达式一合并,我干的第一件事就是:把所有编译器和分析器文件转换成 cljc,然后让编译器在自己身上跑起来,看看到底哪里会坏掉。”在整整一个月的时间里,他一步步排查重构分析器和编译器,直至两者都能成功自我编译。 自举成功的关键在于宏的处理。在宏文件(如 `cljs.core` 相关的宏定义)中,宏代码本身开始引用标准库和分析器,呈现出一种元循环(metacircular)的自引用形态。与其他 Lisp 实现中宏时间与运行时间交织不同,ClojureScript 严格区分宏阶段(编译期)与运行时阶段: > “因为宏完全属于编译期事物,ClojureScript 的自举反而变得非常直截了当。我所要做的就是编译分析器和编译器,然后把这两个生成的 JavaScript 文件直接追加到标准库后面,任务就完成了。” 摆脱对 JVM 的依赖后,自举的 ClojureScript 衍生出了众多激动人心的成果: - **Klipse**:可以直接在网页端内嵌交互式的 Clojure 代码运行环境与演示 demo。 - **Plank**:基于 JavaScriptCore 的原生轻量 REPL 命令行工具,可在 macOS、Linux 和 Windows 上直接运行。 - **Replete**:运行在 iOS 手机上的全功能独立 ClojureScript REPL。结合社区开发的 Parinfer 算法(通过代码缩进自动推断括号位置),开发者在没有特殊全键盘的地铁上通勤时,也能舒适地在手机上编写 Clojure 代码。 ### [38:30](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2310s) 庞大的社区贡献与 React 带来的“寒武纪大爆发” David Nolen 强调,尽管无法在幻灯片上展示每个人的照片或逐一致谢,但 ClojureScript 能有今天的成就,离不开整个社区的共同建设。截至当时,项目已有约 141 位代码贡献者。从提交补丁、提 issue,到在 IRC 频道提问“这到底该怎么运作”,每一个看似微小的贡献都至关重要。David Nolen 由衷地表示:“ClojureScript 如今能有这么好,全凭每一个参与其中的人。”(“ClojureScript is as good as it is today because everybody that's worked on it.”) 谈及周边生态的发展,David Nolen 指出 React 的出现带来了根本性的转折。在 React 面世前,人们对 ClojureScript 的质疑往往是:拥有优雅的不可变数据结构又如何?最终还不是得去操作糟糕的 DOM 树?而 React 的到来直接推开了新世界的大门,引发了生态圈的“寒武纪大爆发”。围绕 React 迅速涌现出大批集成库,让 ClojureScript 在探索最优秀的 UI 构建范式上走在了行业最前沿。David Nolen 甚至提到,他在参加 React 官方大会时,看到主流前端社区还在为 Flux 这类方案兴奋不已,而他当时的感受是“啊,那可太糟糕了”(“Flux and you're like, ah, that's horrible”),因为 ClojureScript 社区早就找到了更好的路标,甚至让主流技术圈反过来追赶 ClojureScript 的前沿思想。 除了 UI 范式,周边工具生态也涌现了许多惊喜,例如 Darwin 开发的 Chrome 扩展 `cljs-devtools`。即便有 Source Map,在浏览器里直接打日志输出 Vector 时,看到的依旧是一堆难以辨认的底层 JavaScript 对象;而该工具利用 Chrome 的自定义对象打印机制(Custom Object Formatting),让开发者无论在单步调试还是在控制台交互时,都能直观看到格式规整的 ClojureScript 原生数据结构。 ```mermaid flowchart TD accTitle: React 与 ClojureScript 结合引发的演进 accDescr: 展示了从不可变数据结构面对原生 DOM 的困境,到 React 出现后促成生态爆发并反哺核心的演进链路。 subgraph Problem["痛点时期"] A["不可变数据结构"] -.->|"直接操作繁琐"| B["脆弱的 DOM 树"] end subgraph Explosion["React 带来的爆发"] C["React 虚拟 DOM 机制"] --> D["与不可变数据完美契合"] D --> E["生态迎来‘寒武纪大爆发’<br/>(如各类 UI 库)"] end subgraph Leading["走在主流前端前沿"] E --> F["更先进的 UI 架构思想<br/>(远超早期的 Flux 等方案)"] end Problem --> Explosion ``` - 社区贡献者达到 141 位,所有提问、提交 issue 和打 patch 的开发者共同塑造了 ClojureScript。 - React 的出现弥补了不可变数据结构与浏览器原生 DOM 之间的脱节。 - 开发者 Darwin 编写的 `cljs-devtools` 解决了浏览器控制台打印 ClojureScript 复杂对象难以阅读的难题。 --- ### [40:45](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2445s) 竞争性项目:从 Shadow-build 汲取的养分 在开源世界中,David Nolen 最欣赏的特质之一就是独立、具有竞争性的项目。ClojureScript 的演进绝不仅仅是核心团队关起门来自己构思功能,许多极其优秀的想法反而来自于核心之外。Thomas Heller 打造的编译构建工具 shadow-build(后发展为 shadow-cljs)就是一个典型代表。 Thomas Heller 在社区讨论中非常活跃,并提交了许多有价值的补丁,但他同时按照自己对 ClojureScript 编译器的理解独立开发了 shadow-build。在整整一年半的时间里,shadow-build 的许多特性都远远领先于官方核心编译器。例如利用 Google Closure Compiler 的 Modules 实现代码分割(Code Splitting),shadow-build 几个月前就已落地;又如自动推断符号究竟是宏变量(Macro Var)还是运行时变量(Runtime Var),免除开发者手动编写 `:refer-macros` 的繁琐,这一特性早在官方合并前就已在 shadow-build 中成熟运作。这种“百花齐放、各行其道”的探索,为核心项目提供了最宝贵的灵感池。 - 官方核心并非创新的唯一源头,社区独立构建工具往往能验证更前卫的想法。 - shadow-build 率先实现了基于 Google Closure Modules 的代码分割(Code Splitting)。 - shadow-build 提前探索了宏的自动推断,终结了手动 `:refer-macros` 的体验断层。 --- ### [41:46](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2506s) 未来五年的“正确随机漫步”与短期核心优先级 关于“未来五年”,David Nolen 坦言演讲标题略带调侃,因为 ClojureScript 的研发本质上是一个“朝着正确方向的随机漫步”(“It's sort of a random walk in the right direction”)。功能推进往往由大家在特定时期的真实需求所驱动。不过,核心路线图依然有一批清晰的近期工作重点。 开发优先级的第一位永远是“与 Clojure 保持一致”(Clojure Parity)。在 ClojureScript 中最让开发者痛苦的莫过于“为什么在 Clojure 里能这么写,到了 ClojureScript 就不灵了”。因此,当时首要任务是跟进 Clojure 1.9 引入的重大特性 `spec`。当时 ClojureScript 已追平至 Alpha 11 版本,但随着上游持续更新,后续支持也会不断跟进。David Nolen 认为 spec 的潜力不可估量,整个社区在未来两到五年内都将不断发掘并理解 spec 所能带来的惊人价值。 与此同时,深度整合 Google Closure Compiler 依然是一项硬骨头工程。Google 内部频繁升级自身工具链,而且他们“只关心别人有没有改动弄坏 Google 内部系统,从不在乎上游变动会不会把世界其他地方搞崩溃”。由于 ClojureScript 是除 Google 自身外极少数深度重度依赖 Closure Library 的生态,团队必须花费精力持续紧跟 Google Closure Compiler 的演进步伐。 - 研发模式并非僵化的自顶向下规划,而是社区需求驱动的“正确随机漫步”。 - 始终以“与 Clojure 语义一致”作为第一优先级,消除两端差异。 - 全力跟进推进中的 Clojure spec,并预计该特性将在未来数年深刻改变生态。 - 持续对抗 Google Closure Compiler 频繁变动带来的上游破坏,保证构建管道稳定。 --- ### [43:26](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2606s) 编译器性能提升、平台支持与测试建设 David Nolen 指出,在过去五年中,团队实际上从未真正集中精力优化过编译器的串行执行性能。此前他实现的唯一重大性能改进是“并行构建”(Parallel Build)——利用多核 CPU 分摊不同文件的编译工作,这对于生产环境构建(Production Build)提升显著。然而,并行编译对单线程串行处理速度没有任何帮助,至今没有人坐下来专注于剖析并优化编译器本身的代码路径。David Nolen 认为串行编译存在巨大的优化空间:“我怀疑这里至少有 2 倍的性能提升空间。”(“I suspect there's at least a 2X perf gain right here.”)如果单核编译耗时能从 30 秒压缩到 15 秒,再叠加上多核并行构建压缩到 7 秒,这对日常开发体验将是飞跃性的改进。 除了性能,他还列举了多项亟需社区协助的工程基建方向: 1. **Windows 平台适配**:虽然使用 Windows 的 ClojureScript 开发者比例较低,但偶尔会出现 Windows 专有的环境 Bug。David Nolen 当场承诺,只要有 Windows 用户提交针对性补丁,他几乎会第一时间立刻审查合并,确保跨平台体验不留死角。 2. **测试用例扩充**:随着编译器复杂度日益增加,现有的测试覆盖仍显不足。不仅每个编译配置选项都需要单元测试,运行时逻辑更亟待引入基于 spec 的“生成式测试”(Generative Testing)。 3. **运行时性能基准套件**:建立起长期性能度量机制,用来持续监控生成出的 JavaScript 代码在各阶段的执行效率变化。 - 计划挖掘编译器本身的串行优化潜力,预期可达成 2 倍以上的提速空间。 - 承诺对 Windows 修复补丁提供最高优先级的即时合并。 - 呼吁社区参与编写编译器配置测试用例,并运用生成式测试覆盖运行时核心。 --- ### [45:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2710s) 前瞻规划:编译期类型校验、公共 API 与打破 Externs 噩梦 在展望更前沿的改进时,David Nolen 强调了 spec 在编译优化方面的巨大前景。虽然在编译器内部做复杂的全套递归类型推断可能不现实,但完全可以利用基础的 spec 信息做编译期校验:例如检测参数是否可为 `nil`、是否为数值(Number)、映射(Map)或向量(Vector)。更进一步,ClojureScript 可以把这些基础类型断言转译为类型提示,直接喂给底层的 Google Closure Compiler 进行静态类型检查,确保开发者不会带着“传入了 nil 却没有做判空处理”的代码上线。 对于工具生态开发者,编译器暴露公共 API(Public APIs)是另一关键基石。现场绝大多数开发者都是 Figwheel 的忠实用户,而 Figwheel 之所以能够做到比肩甚至媲美 Elm 级别的精准错误行号定位与精美提示,正是因为 ClojureScript 编译器内部暴露出了足够多且合理的公共钩子函数。未来的架构设计必须持续保持并深化对工具链生态的支持。 最后,David Nolen 触及了整个 ClojureScript 长期以来“附带复杂性(Incidental Complexity)的最大来源”——Externs(外部声明文件)。当开发者引入 React、Highcharts 或 npm 上随便找来的第三方 UI 组件时,开发模式下一切顺利,可一旦执行面向生产的 Advanced 编译优化,整个界面就会立刻崩溃。这背后的根源是 Google Closure Compiler 会激进地重命名所有属性名称,必须通过 Externs 显式告诉编译器“千万不要重命名这个外部方法名或属性”。这一直是 ClojureScript 最令新手头疼、挫败感最强的体验门槛。David Nolen 透露,他已经着手构建相关原型,决心亲自攻关这个痛点,从根本上解决 Externs 带来的困扰。 - 构想将简单的 spec 声明转化为 Google Closure Compiler 识别的类型注解,在编译期拦截空指针等基本类型错误。 - 编译器将开放更多公共 API,以支撑类似 Figwheel 这样的前端工具实现极致的错误报告与重载体验。 - 外部依赖与属性重命名称为生态最大的附带复杂性来源,消除手动编写 Externs 的痛点被列为个人原型研发的核心攻坚方向。 ### [47:17](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2837s) 消除 Externs 文件与社区贡献方式 在与第三方 JavaScript 库集成的过程中,编写 Externs 声明文件一直是一件极易出错的事情。David Nolen 坦言,即便是他自己也经常掉进这个坑里:信心满满地执行了 `:advanced` 优化构建准备上线生产,结果程序直接崩溃,原因仅仅是漏掉了一个 Extern。这种偶发复杂性(incidental complexity)让人头疼,但 David 认为这是一个完全可解的问题,团队很有希望在未来彻底攻克它。消灭编写 Externs 的需求将是打通整个 JavaScript 生态系统的最后一块绊脚石,也是近期路线图上的重点。 ```mermaid flowchart LR accTitle: JS 生态集成的演进目标 accDescr: 展示从手动维护 Externs 到实现全自动集成并接入 JS 生态的演变过程。 subgraph Current ["当前困境"] A["引入外部 JS 库"] --> B["手动编写 Externs"] B --> C{"Advanced 编译"} C -->|"遗漏声明"| D["生产环境报错崩溃"] end subgraph Future ["近期路线图目标"] E["自动化模块解析"] --> F["消除手动 Externs"] F --> G["无缝融入完整 JS 生态"] end ``` 然而,要推进这些宏大构想,必须有更多人加入进来。很多人误以为给 ClojureScript 贡献代码门槛极高,但事实并非如此。David 呼吁大家尽早签署贡献者协议(Contributor Agreement),即使你觉得自己永远不会给 Clojure 或 ClojureScript 提代码,也应该先签了备用。他分享道,团队有时会遇到极其荒谬的基础漏洞——比如某个特定边界条件下,持久化 Map 存到 9 个条目就会报错——这种在长达五年时间里无人发现的 Bug,其实任何懂 Clojure 的人看一眼函数就能修复。 想要深度参与的人可以加入 ClojureScript 开发专属的 IRC 或 Slack 频道(`#cljs-dev`),哪怕只是潜水围观也能学到很多东西。在挑选任务时,David 建议初学者寻找“低垂的果实”(low-hanging fruit): - 不要一开始就挑战那些极为复杂的硬骨头任务。 - 去 JIRA 上浏览已有的补丁(patch),直接拉下来测试,并在工单下留言确认“我测试过了,运行正常”。 - 如果发现了微小的 Bug,随手提交一个微小补丁即可,开源社区从不嫌弃问题或补丁太小。 > “We would like to remove the need to ever write extern files like that would be a gigantic step forward for integrating with again the wider JavaScript ecosystem.” —— David Nolen --- ### [49:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2953s) 非代码维度的贡献与推广力量 除了提交代码,非代码形式的贡献对生态的发展同样至关重要。David 看着台下感慨道,能来到现场非常令人兴奋,这个会议有大约 300 人参加,规模甚至超过了他去过的很多主流 JavaScript 会议。回顾过去,他在 2008 年时曾尝试全身心投入 Common Lisp,但当时困难重重,幸好后来出现了 Clojure。在早期,Lisp 语法给外界的印象往往是过于奇特和边缘化,而如今在 Hacker News、Reddit 以及各种技术博客上,看到 Clojure 代码片段已经屡见不鲜,大家早已习以为常。 David 极力倡导大家记录并分享自己的实践经验,无论你是在玩 React Native、Reagent 还是 Rum,撰写博客帮助新手跨越门槛,是影响力最大的贡献方式之一。此外,在本地用户组(User Group)或技术大会上发表演讲也非常重要。随着社区里讲解 Clojure/ClojureScript 的演讲者越来越多,核心团队成员就不必到处疲于奔命。他坚信,只停留在抽象层面大谈编程语言的炫酷特性,是无法打动一线开发者的;真正能说服程序员的,永远是用它构建出让人眼前一亮的实际作品。 每当 David 启动 ClojureScript 时,即便自己已为其贡献了无数代码,依然觉得它像是一种“外星科技”,令人惊叹。如今从底层编译器到上层的 `cljsbuild`、Boot 以及 Figwheel,核心团队与社区开发者使用的都是同一套工具链,整个生态正是由大家共同推进的。 > “You can talk about fancy language features all day, but really developers are convinced when you show them something cool.” —— David Nolen --- ### [51:50](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3110s) 问答环节:编译器反向移植与持久化数据结构重写 在问答环节中,一位现场观众提出了一个深度的技术问题:既然 ClojureScript 已经成功使用 Clojure 本身重写了原先用 Java 实现的部分核心逻辑,那么核心团队是否有考虑过将 ClojureScript 生成 JavaScript 的思路或架构反向移植(backport)回 Clojure 主干,从而用纯 Clojure 代替目前用 Java 编写的持久化数据结构,亦或是将 Protocol 机制更深地植入核心层? David 回应称,目前核心团队内部还没有就这个具体方向展开过讨论。当前 Clojure 开发的核心重心全放在了 `clojure.spec` 上,因此很难预测他们何时才会重新审视 Clojure 编译器的底层实现。但 David 坚信在未来的某个时间节点,团队一定会回过头重新审视这一切。 - ClojureScript 编译器的最初版本正是由 Rich Hickey 亲自操刀编写的,那代表了他心中“用 Clojure 实现 Clojure 编译器”的最初蓝图。 - 尽管目前无法确定未来是否会直接复制代码片段,但 ClojureScript 这五年积累的架构经验,必然会反哺并深刻影响未来可能出现的下一代 Clojure 编译器实现。 > “Rich wrote the first version of the ClojureScript compiler so that was his idea of what a Clojure in Clojure would look like, so I'm convinced that whenever they go back to do it again it's going to be heavily informed by how we did it in ClojureScript.” —— David Nolen --- ### [53:40](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3220s) 问答环节:Mori 的起源、基准测试与 React 的推动 随后有参会者询问 Mori 库在整个 ClojureScript 发展历史中的位置。David 详细回顾了这段渊源:当 ClojureScript 的持久化数据结构成熟后,他发现这些结构在 V8 引擎与 Node.js 上的运行速度快得不可思议。于是他创建了 Mori,将 ClojureScript 的持久化数据结构单独编译提取出来,封装成一个符合 JavaScript 开发者习惯的纯 JS 依赖包,供前端或 Node.js 环境使用。 当时 David 发布了详尽的基准测试报告,数据表现极为震撼:在 V8 环境下构建一个包含 100 万个元素的可变 JavaScript 数组(mutable array),其速度竟然还不如构建一个 ClojureScript 的暂态向量(Transient Vector)。然而,光有顶尖的性能指标并没有引起波澜。Mori 在 2012 年发布后,整个 JavaScript 社区在长达两年的时间里对其反应冷淡,直到 2014 年 React 诞生并引发广泛关注。 David 借着 React 的东风深入讲解不可变数据与 UI 渲染的天然契合,这不仅让 JavaScript 社区终于重视起 Mori,更直接启发并影响了 Facebook 团队着手开发 Immutable.js。这个历程再次印证了他的核心观点:程序员很少仅仅因为基准测试数字漂亮就更换技术方案,技术往往需要像 React 这样的“神奇仙女尘”(magic fairy dust)作为催化剂,才能真正引爆认知。 > “It's really hard to convince programmers to make decisions based only on benchmarks and technical stuff; there has to be I think some other thing going on and React happened to be the magic fairy dust that made people interested in it.” —— David Nolen --- ### [55:47](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3347s) 问答环节:JavaScript 模块化支持现状与代码消除愿景 最后一位提问者关注了 Maria Geller 在 Google Summer of Code (GSoC) 中负责的 JavaScript 模块(Module)支持项目的进展。David 介绍道,Maria 目前主要负责维护极为流行的构建工具 `cljsbuild` 以及 Mori 库,精力相对分散。虽然她在 GSoC 期间所实现的 AMD 和 CommonJS 模块集成功能目前依然运转良好,并且已有开发者在项目中成功引入,但整体状态尚未达到 David 的理想标准。 当前面临的两个主要挑战与未来目标如下: 1. **上游 API 破坏**:Google Closure Compiler 在版本更新中破坏了原先使用的接口,导致未来升级 Google Closure 时必须修补相关代码。 2. **终极优化目标(DCE)**:David 认为模块支持是否真正成熟的检验标准,是能否将类似 React 这样庞大的第三方库完整纳入构建,并实现按需剔除。 3. **改造外部代码**:开发者应该能够精准声明只加载某个模块(例如 `react.Component`),而打包工具则能通过高级死码消除(Dead Code Elimination)技术,将剩余未引用的所有 React 冗余代码彻底剥离。这种让外部 JavaScript 库遵循 ClojureScript 优化规则的能力,才是解决第三方庞大依赖包体积问题的根本出路。 > “What you should be able to do if the module stuff works correctly is that you should be able to include all of React in your build... and we should be able to dead code eliminate all of React that you don't use, that's the actual target.” —— David Nolen ### [57:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3454s) 摆脱微模块与第三方 JavaScript 库的死代码消除 David Nolen 探讨了 ClojureScript 依赖 Google Closure Compiler 所带来的核心优势——死代码消除(Dead Code Elimination)。在常规的 JavaScript 生态中,开发者往往受限于一种近视的世界观,为了减小包体积而不得不拆分出无数的微型模块(micro modules)。然而在 ClojureScript 的世界里,开发者完全不需要操心这些琐碎的拆分细节,因为即便引入了一个庞大的库却只调用了其中一个函数,Google Closure 也会精准地剔除所有未使用的代码,最终产物中就只包含那一个函数。 ```mermaid flowchart TD accTitle: 代码体积优化流程 accDescr: 展示常规 JS 依赖微模块拆分对比 ClojureScript 与 Google Closure 进行高级优化的流程 subgraph NPM["常规 JavaScript 困境"] N1["微模块拆分 (Micro Modules)"] --> N2["手动控制依赖包大小"] end subgraph CLJS["ClojureScript 愿景"] C1["引入完整第三方库"] --> C2["Google Closure Compiler"] C2 -->|"死代码消除"| C3["仅保留实际调用的函数"] end ``` 这种优化的终极愿景是延伸到外部生态。David Nolen 表示,即便面对团队无法掌控其开发流程的第三方 JavaScript 库,他也希望 ClojureScript 能对它们应用相同的优化技术。 - “we don't have this this myopic view of the world where you have Micro modules we don't care because Google closure eliminates all the stuff you don't use and I would like to be able to know that um even third-party JavaScript libraries that we cannot control the development of we are able to apply this same optimization techniques too” —— David Nolen --- ### [58:10](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3490s) WebAssembly 对 ClojureScript 的意义与 GC 挑战 现场观众提问 WebAssembly(Wasm)对 ClojureScript 而言是否算是一个好消息。David Nolen 肯定地回应称这绝对不是坏消息。在短期和局部场景中,如果开发者需要进行高性能的数值计算,可以立刻编写一个针对 WebAssembly 的领域特定语言(DSL),从而为游戏等场景生成极致优化的底层函数,这没有任何弊端。 然而,若要探讨将 WebAssembly 作为 ClojureScript 的直接编译目标,情况就会变得复杂得多。Clojure 和 ClojureScript 的底层设计高度依赖高性能的垃圾回收机制(GC)。当时的 WebAssembly 缺乏内置的 GC 集成支持,如果直接将 ClojureScript 编译为 Wasm,开发者就必须自行实现一套垃圾回收器,而这在性能上无疑是一场噩梦。尽管如此,负责制定标准的 WebAssembly 委员会已经意识到了这个局限性。David Nolen 指出,或许在 6 年、10 年甚至更短的时间内,一旦 GC 规范落地且 Wasm 成为更具吸引力的编译目标,ClojureScript 毫无疑问会跟进并支持它。 - “closure script like closure assumes the presence of a high performance GC um and there's no GC integration story for web assembly you you would have to write you know your own GC and that sounds like a performance nightmare” —— David Nolen - WebAssembly 能够有效弥合浏览器环境与预期高性能计算之间的差距。 - 只要未来技术条件成熟并且方向正确,ClojureScript 团队绝不会排斥将其作为编译目标。 --- ### [59:34](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3574s) 模块处理与 Externs 推断的双轨演进 观众针对第三方库的处理机制提问:Maria Geller 关于模块消耗的工作与演讲尾声提到的 Externs 推断(Externs Inference)究竟是同一回事、相互关联,还是风马牛不相及?David Nolen 澄清二者是互为补充的双轨机制,共同致力于改善 ClojureScript 与更广泛 JavaScript 生态的互操作体验。 ```mermaid flowchart LR accTitle: JS 库接入的双重路径 accDescr: 展示规范 ES6 模块直接编译与非标库配合 Externs 推断接入的两条处理路径 subgraph Direct["理想路径: 直接导入"] A["标准 ES6 模块"] --> B["Google Closure 编译"] B --> C["无需手写 Externs 并自动优化"] end subgraph Fallback["保底路径: 构建隔离"] D["非标准 / 无法解析的库"] --> E["排除在高级编译之外"] E --> F["Externs 类型推断"] F --> G["避免手动编写 Externs 文件"] end ``` David Nolen 解释说,如果一个第三方库采用规范的 ES6 模块编写,Google Closure 能够完全理解并处理它,那么直接将其送入高级编译流水线即可,此时根本不需要任何 Externs 文件。但在现实中,很多第三方库并不规范,在高级编译下可能会直接报错中断。针对这种无法被编译器直接吞下的库,开发者的策略是将其排除在高级编译之外、仅作为普通依赖打包到构建中;而此时,Externs 推断技术就会发挥作用,自动识别对该库属性的调用,从而免除开发者手工编写冗长 Externs 文件的痛苦。这两种方案从不同角度出击,共同降低了接入 npm 生态的摩擦力。 - “if you could actually consume them them truly consume them and pass them to Google closure you wouldn't need externs for them anyway” —— David Nolen - “all of these things are designed to make integration with the wider ecosystem better um but they're sort of attacking it from two different ways” —— David Nolen 随着解答完毕,David Nolen 感谢了全场听众的耐心倾听,在热烈的音乐与掌声中结束了本次演讲。 ## Notable quotes > [49:13](https://www.youtube.com/watch?v=mty0RwkPmE8&t=2953s) You can talk about fancy language features all day, but really developers are convinced when you show them something cool. — David Nolen > [53:40](https://www.youtube.com/watch?v=mty0RwkPmE8&t=3220s) It's really hard to convince programmers to make decisions based only on benchmarks and technical stuff; there has to be I think some other thing going on and React happened to be the magic fairy dust that made people interested in it. — David Nolen ## Mentioned David Nolen, Cognitect, Clojure, ClojureScript, Datomic, Alex Miller, Jeremy Ashkenas, The New York Times, CoffeeScript, Google Web Toolkit (GWT), Chris Houser, Florian Loitsch, scheme2js, Dart, Relevance, Rich Hickey, Google Closure Compiler, Google Closure Library, ClojureScript One, Leiningen, Evan Mezeske, lein-cljsbuild, Maria Geller, Lars Bak, V8, László Török, Michał Marczyk, Facebook, Immutable.js, Chris Granger, Light Table, Node-WebKit, Nicola Mometto, Breader, tools.reader, Sean Grove, Google Summer of Code (GSoC), Jonathan Boston, Shaun Lebron, Chas Emerick, Mike Fikes, Amble, Bonjour, JavaScriptCore, WebDAV, React Native, Klipse, Plank, Replete, Parinfer, React, Darwin, cljs-devtools, Thomas Heller, shadow-build, shadow-cljs, Figwheel, Mori, WebAssembly ## Video description With five years behind us, the history of ClojureScript is already becoming murky. This talk attempts to document the many interesting landmarks along the way before we forget them. By pausing to reflect on how much ground we have collectively covered, we also hope to form a clearer picture of the next five years ahead of us. Spoiler alert: the best is yet to come! [Source](https://www.youtube.com/watch?v=mty0RwkPmE8)

Source quotes

[49:13] David Nolen: You can talk about fancy language features all day, but really developers are convinced when you show them something cool. [53:40] David Nolen: It's really hard to convince programmers to make decisions based only on benchmarks and technical stuff; there has to be I think some other thing going on and React happened to be the magic fairy dust that made people interested in it.

Source quotes

[49:13] David Nolen: You can talk about fancy language features all day, but really developers are convinced when you show them something cool. [45:10] David Nolen: Probably the largest source of incidental complexity in ClojureScript—ClojureScript is awesome, but there's things that are not awesome—is externs. [14:31] David Nolen: The cool thing about using persistent data structures to drive ClojureScript perf was that this is something that everybody's going to depend on. If we make this fast, then we know that we're actually delivering on performance.

Original transcript

[0:02] all [0:03] right I think I'm gonna get started so [0:06] hello um this has a been a really [0:09] awesome conference very exciting um very [0:11] thankful that I was invited to speak [0:12] here my first time in Finland uh so far [0:15] having a pretty good time so last Talk [0:17] of the day I'm not going to be it's not [0:20] going to be a very technical talk I [0:22] actually thought it would be interesting [0:24] to um talk a little bit about the [0:26] history of closure script um so that's [0:29] what we're going to focus on on a bit uh [0:31] because I think it's been long enough [0:32] that I think uh like raise your hand if [0:36] You' been using closure script for 5 [0:37] years raise your hand okay exactly four [0:43] years okay three [0:46] years uh two [0:49] years and then one year so yeah so [0:53] probably the last two right it's um a [0:56] lot of people um just aren't going to be [0:59] familiar with the early history uh and [1:01] it's a long unwinding Road and I think [1:02] there's some fun highlights and it'll [1:04] give you some perspective on how closure [1:06] script development uh works all right so [1:09] just a little quickly about me I'm David [1:10] Nolan I'm a software engineer at [1:12] cognitech uh cognitech is a software [1:15] consultancy uh we Steward closure uh and [1:18] closure script I'm the lead developer of [1:19] closure script and we also have a [1:21] product called datomic uh which is [1:23] really cool you check it [1:24] out um so uh a couple weeks ago closure [1:29] script finally got a website uh again [1:31] I'm not sure well go [1:35] ahead um huge shout out to Alex Miller [1:39] uh for pushing this through um we [1:41] basically repur repurposed the closure. [1:44] org website uh the infrastructure for [1:46] that took the design and then we made a [1:48] bunch of changes on the content uh to be [1:50] more relevant to closure script uh so [1:52] for those of youve been using closure [1:53] script for a while you know that closure [1:54] script is really pretty cool Tech uh [1:57] it's pretty reliable Tech uh but for [1:59] outside people who are coming to the [2:01] first time it's nice to finally have a [2:03] public face it really makes it feel like [2:05] uh closure script has uh grown up uh so [2:10] um but again it's it's it's been a long [2:12] extremely long process to get to where [2:14] we are today and I want to um talk about [2:18] it um I mean when I use closure script I [2:22] I use closure script at work uh you know [2:24] today it's like um it's like we've come [2:27] so very very very very far uh for me I [2:31] when I use closure script even though [2:33] that I work even though I work on the [2:34] compiler every time I have fig wheel or [2:36] I'm building my project it's like this [2:37] is like magic this is amazing uh so even [2:40] though I've been heavily involved in [2:42] this development it still feels like uh [2:44] We've climbed an incredible mountain and [2:47] so I want to point out some sort of [2:49] interesting way points along the way [2:51] again um specifically things that people [2:53] may not know about so what were the [2:56] first five years like so five years ago [2:58] um I was not doing enclosure I was at [3:00] the New York Times in The Newsroom [3:02] working on a team called interactive [3:04] news building news applications and uh [3:07] our stack was uh Ruby on Rails and I was [3:10] doing JavaScript and uh jQuery uh and [3:12] and this was fine at the time it was [3:16] 201 um I was actually on the same team [3:19] as Jeremy ashkinos and Jeremy sort of [3:21] became famous because he developed some [3:23] in called coffee script uh so even [3:25] though you had things like GWT Google's [3:28] GW GWT which took Java and compiled it [3:31] to JavaScript um compiling to JavaScript [3:34] really wasn't that popular of a thing [3:37] among JavaScript developers and Jeremy [3:39] sort of cycript sort of made that oh [3:42] maybe compiling the JavaScript is not [3:44] such a a wacky idea and in fact we ended [3:47] up using cycript a little bit here and [3:49] there at the Times um and and people [3:51] thought it was cool and so it was there [3:53] was a it was the beginning of a [3:54] transition I think in the sort of uh [3:57] frontend mainstream world that maybe [3:58] compiling to Java script isn't totally [4:01] uh a crazy thing to do um so I was also [4:05] like ah copy script's cool U maybe [4:07] there's you know I'm a list person I'm [4:09] not I really wasn't much of a a ruby [4:11] person I mean I was happy to use it to [4:12] build the apps that we were building but [4:14] I was a list person so I started being [4:15] like well maybe there's a cool lisp that [4:17] compiles um uh to JavaScript at the time [4:20] closure for me was a hobby language um [4:23] and there was kind of an experimental [4:25] thing called closure script back in the [4:27] day by this person Chris Hower who's [4:29] great uh but it wasn't really um ready [4:32] for prime time and I came across this [4:34] thing called scheme tojs which was a [4:36] almost fully compliant version of scheme [4:39] r5rs um by somebody whose name is [4:42] Florian Lo and actually he ended up [4:44] going to Google to work on Dart um but [4:48] specifically the dart 2js compiler since [4:51] he had had a lot of experience uh [4:52] figuring that problem out for scheme [4:54] tojs but the problem with scheme tojs it [4:56] was really cool is that but didn't have [4:58] macros and so you know I I I had totally [5:01] you know been sold on closure and common [5:04] lisp and you know proper scheme and I [5:05] was like ah I'm not going to use this [5:06] doesn't have macros um and so I so I was [5:10] a bit dejected so I was going to stick [5:11] with Co coffee script uh but it turned [5:13] out I researched this I think in June or [5:16] May of 2011 and um two months later uh [5:20] relevant said we're going to make a [5:22] really big announcement at closure NYC [5:24] which is I'm based in New York it's a [5:26] local um User Group there uh this was [5:30] probably one of the most well attended [5:32] uh closure uh meetups and the big [5:34] announcement of course was closure [5:36] script this was July [5:39] 2011 um and Richi gave a great [5:41] presentation in many in many ways [5:44] everything he talked about five years [5:45] ago uh remains true today I think the [5:48] big idea behind closure script is reach [5:50] so even though um I think uh people have [5:54] uh through closure either maybe you're [5:55] already on the jvm you're like great I [5:57] can do I can use a more interesting [5:58] language and still Target the jvm or [6:00] you're getting introduced to the jvm [6:01] you're like oh the jvm is pretty cool [6:03] technology if you have a better [6:04] programming language um but the the [6:07] problem is with the jvm of course is [6:09] that there are a lot of places where the [6:11] jvm is not an option um you know we this [6:14] was people aware of this even back then [6:15] right I you know apple has a very [6:17] specific way they want people to develop [6:19] for iOS you probably were never going to [6:21] be able to get the jvm on iOS um if [6:24] you're targeting clients uh it often [6:26] means you're building web applications [6:27] and you know people aren't building [6:29] taets uh for um in the browser anymore [6:32] so JavaScript more or less um was the [6:35] way to get to places um the jvm couldn't [6:37] go and that's one of the big Ideas the [6:40] other big idea and I'm going to [6:41] emphasize this quite a bit today is uh [6:43] when Rich uh talked about closure script [6:46] he talked about as the first pass at [6:48] this sort of idea of closure and closure [6:51] uh so closure script was going to be [6:53] written entirely in closure so if people [6:55] don't know closure's implementation is [6:57] almost entirely in Java the compiler and [6:59] the data structures so closure script [7:01] was the first time um a dialect of [7:04] closure was going to be written in [7:05] closure itself and the other cool thing [7:07] was is that at the bottom of the [7:09] language protocols would be a [7:11] fundamental thing and so uh I've been [7:13] doing closure as a hobby and then now as [7:16] for work of course since about 2008 and [7:19] I remember it was the uh like January [7:22] 2011 richii popped onto the IRC Channel [7:25] and said what if there was a version of [7:27] closure with protocols at the bottom and [7:29] then he like left and then you know six [7:31] months later you you figure out what he [7:33] was talking [7:34] about okay so uh closure script existed [7:37] for two or three months before I [7:38] actually was involved this is my very [7:41] first commit um to closure script right [7:43] here uh eight lines of code if you [7:45] discount the extra line of whites space [7:48] um and this is uh def Macro for rifi uh [7:52] I had started playing around with [7:54] closure script you could you could [7:55] download the repo repo and there were [7:56] some scripts to run it and I was running [7:58] the reple I was like really [8:00] and boom there was an error because RI [8:02] wasn't implemented yet I was like oh and [8:04] I popped on to um the mailing list I [8:07] said why isn't there rifi and they're [8:09] like well just hasn't been done yet um [8:11] and I said okay I'll I'll submit a patch [8:13] for RI and I was okay this is going to [8:14] take weeks you know the the closure [8:17] script compile is going to be so [8:18] complicated there's no way I can you [8:19] know it's going to take a lot of time [8:21] and then I I read the macro file and I [8:23] looked around I was like oh wow this is [8:25] just closure it's it's actually pretty [8:27] straightforward and simple and I saw [8:29] that I could Implement rifi in about [8:31] eight lines of code and this was really [8:33] awesome Rich hicky and Chris Hower both [8:35] like wow that's so cool only eight lines [8:37] of code to get rifi and this was my this [8:39] got me commit rights to closure script [8:41] and from that point forward you know I [8:43] was one of the committers and I would [8:45] sort of um sort of deal with jira and [8:47] make sure that patches were flowing [8:49] through consistently because for the [8:51] first two years again uh closure script [8:53] was only going to succeed if people [8:55] believed it was going to succeed um [8:57] there was just a ton of work to do what [8:59] they shipped um that first thing that [9:02] they shipped was you know had a lot of [9:04] Promise um but didn't have that much [9:06] capability uh it was going to be a long [9:09] road um but it was still actually pretty [9:12] useful out the door um but one one huge [9:15] problem was that closure script in [9:17] typical uh I think Rich hickey and [9:20] fashion it didn't really follow what the [9:22] mainstream was doing it it definitely [9:24] had very sound technical decisions but [9:27] maybe at the expense of being something [9:29] was that was familiar to the average [9:31] developer that was doing frontend work [9:33] frontend in 2011 was all jQuery and then [9:36] richii is like we're going to do this [9:37] thing we're going to use this thing [9:38] you've never used called Google closure [9:40] compiler and this Library you've never [9:42] heard of called Google closure Library [9:44] um so I think that's a it was a lot of [9:45] unfamiliarity for people that would want [9:48] to use closure script so relevance put [9:50] together this awesome thing called [9:51] closure script one um and it was it was [9:55] not a tool it was just a template [9:56] project it was a template project [9:58] showing you that you could build a [10:00] reasonable application and to to [10:02] basically demonstrate that all the [10:04] functionality that people wanted from [10:06] jQuery or whatever it was already there [10:09] uh in Google closure Library Google [10:11] closure library to this day is heavily [10:14] developed by Google closure right that [10:16] is the thing that Google's actually [10:17] using to build all their JavaScript [10:19] applications closure library and the [10:21] closure compiler um so just an [10:24] incredible amount of functionality there [10:26] and I think this sort of opened up the [10:28] eyes uh of of some people oh maybe the [10:30] closure Library thing wasn't such a bad [10:34] idea um but but even at that point uh [10:37] you had this problem in that closure [10:38] script one was kind of a template and it [10:40] was still very awkward to get anything [10:43] done uh by 2011 lingan had taken the [10:46] closure World by storm I mean it's [10:48] basically if it wasn't a lingan plugin [10:50] chances are nobody was in a use your [10:52] thing um and this was something I was [10:54] just missing there was no easy way to [10:56] integrate um the closure script compiler [10:58] into your prod projects right you had to [11:01] clone the repo and then you had to like [11:02] run all these custom scripts it's very [11:05] tedious and not that fun and so Evan [11:07] mazeski huge shout out he's no longer [11:09] that active in the closure script [11:11] Community but the fact that he worked on [11:13] this and made it um basically trivial [11:16] for people to build a ring application [11:18] and then include cljs build as a plugin [11:22] um uh it really lowered the barrier and [11:25] at this point you started you finally [11:26] this is like eight months in two or nine [11:28] months in you finally saw closure [11:30] programmers being like okay I'm going to [11:32] give uh closure script a chance and this [11:35] was you know we're slowly building [11:37] momentum so eight nine months in right [11:40] the first eight nine months sounds like [11:42] a cool idea but nothing much is [11:43] happening when CJs build appears um it [11:46] starts becoming more active uh it's [11:48] actually now maintained by um [11:51] um Maria G and we'll talk about more [11:54] about her later um oh so that's another [11:58] thing so I don't I'm not sure how many [11:59] people know that uh closure script did [12:02] not ship with persistent data structures [12:04] uh the first year almost the first year [12:07] uh closure script only had copy on right [12:10] it was these very naive uh slow full [12:13] copy on right data structures they had [12:14] the same uh interface as what you're [12:17] used to in in closure but they were not [12:20] persistent data structures in fact a lot [12:22] of people were skeptical right U because [12:24] in 2011 um the sort of JavaScript [12:28] performance Revolution was beginning uh [12:30] it hadn't really um come to its full [12:33] fruition uh but the group leading the [12:36] pack here was Google so Google uh hired [12:39] a SWAT team of basically you know the [12:41] world's compiler experts led by Lars [12:43] Bach large Bach worked on Hotspot right [12:46] the the jvm and he also worked on self [12:49] so somebody who had been working on [12:50] optimizing compilers for more than a [12:53] decade or two decades already so they [12:55] had him working on JavaScript and the [12:58] strides that they were able to make [12:59] incredible right um and then suddenly we [13:02] were like well what happens if we take [13:04] the Java code for the like persistent [13:07] Vector the mo you know a really [13:08] relatively simple persistent data [13:10] structure about 400 lines of java um we [13:13] were like what happens if we just trip [13:15] porting this handwriting this to [13:17] JavaScript and running it a VA what is [13:19] what are performance numbers going to be [13:21] uh so a gentleman named Lao Toro or too [13:25] um he did this and when we looked at the [13:27] numbers we were like this is in the ball [13:29] Park like not even an order of magnitude [13:31] difference from the jvm this is under an [13:33] order of magn within an order of [13:34] magnitude of jvm performance I think [13:36] only like 4X slower and this is 2011 [13:39] that like that's not even true today [13:41] today I think we're only like 1.5 times [13:43] slower than the jvm for prisent Vector [13:45] perve but this was our this was good [13:47] enough to be exciting uh clearly was [13:49] going to be a huge win over copy on [13:51] right um so we did this and then once we [13:55] once we showed that it was good in [13:56] JavaScript uh uh llo did a version of [14:00] 200 lines of of uh enclosure script of [14:03] the a port of the JavaScript code so we [14:05] just Faithfully ported the Java to [14:07] JavaScript and then ported that uh to [14:10] closure script and this was sort of the [14:12] beginning um of this sort of persistent [14:14] data structure Revolution within closure [14:16] script because again these were done in [14:19] Java they weren't done in closure right [14:21] so this is uh the first time we were [14:23] really going to do persistent data [14:25] structures um all of them in a dialect [14:28] of Clos itself uh and the neat thing [14:31] about doing this was that you know when [14:33] you're doing performance work you often [14:35] you know people when you look at [14:36] benchmarks it's always just a bunch of [14:38] right it's just like what [14:39] you're benchmarking something it doesn't [14:41] matter um and the cool thing about using [14:44] persistent data structures to drive [14:45] closure script perf was that this is [14:47] something that everybody's going to [14:49] depend on if we make this fast then we [14:52] know that we're actually delivering on [14:53] performance so when llo did this version [14:57] what I did was okay why is it that this [15:00] version which looks like a faithful Port [15:02] of the JavaScript is um three times [15:05] slower than the JavaScript so it was the [15:07] process of implementing the persistent [15:09] data structures uh that I was able to [15:11] see what was wrong with closure script [15:13] code gen right so why are there function [15:16] overhead calls oh we're we're not [15:18] inlining all of our arithmetic [15:19] operations and so on and so forth um and [15:21] I think when what I was done we again he [15:24] did not change his code after I was done [15:26] optimizing the compiler I think we were [15:28] only uh at that time like 20 or 30% [15:31] slower than they had JavaScript which is [15:33] great and of course those were just [15:35] weird artifacts of the way that JS [15:36] engines work I think now I it's you know [15:39] it's like maybe it's 10% slower than [15:41] writing this in JavaScript at which [15:42] point who [15:44] cares um and then this kicked kicked off [15:47] there was so much excitement and in [15:48] internally I'm not saying that the [15:49] outside world was excited about this but [15:51] internal to the closure Community once [15:53] we showed that persistent data [15:55] structures were viable on V8 and without [15:57] a doubt everybody else was in up like [16:00] JavaScript core and spider monkey would [16:02] be competing against V8 so there was no [16:04] doubt that um what we showed was [16:06] possible on V8 it was just a matter of [16:08] time so we might as well do the other [16:09] precis data structures uh mik [16:12] March a fine polish Poland he's polish [16:16] uh closure programmer and mathematician [16:18] he decided to take every single [16:20] persistent data structure and do all the [16:21] ports um and it was great so every time [16:24] he would Implement one we would [16:25] Benchmark against um the jvm as a [16:27] baseline we find out out what was wrong [16:29] with the code gen um and then I I think [16:32] a year it was like a year and a couple [16:34] months we had all the persistent data [16:36] structure ported and people ran their [16:38] closure script applications they were [16:39] like it's now 10 times faster 20 times [16:41] faster 30 times faster um so that was [16:44] just a huge win um which is cool so the [16:48] persistent data structure stuff now it's [16:50] it's now because um fa Facebook has [16:52] something called immutablejs and a lot [16:54] of people are talking about immutability [16:56] now mainstream programmers aren't [16:57] scratching their heads when you say [16:59] persistent data structures but back in [17:01] 2011 even though internally in the [17:03] closure script Community like yeah this [17:05] is so awesome nobody in the mainstream [17:07] cares because they don't know what [17:08] you're talking about like they're like [17:10] okay that sounds cool it's computer [17:12] sciency that's neat but like what are [17:14] you doing with this thing this is this [17:17] list what are you actually making show [17:18] me something uh because most developers [17:21] that are serious they just want to know [17:24] how does this help me solve problems and [17:26] show me an example of how you solved a [17:29] problem that I can understand a more [17:30] typical problem um and show me how your [17:34] process or methodology or programming [17:35] language is better than what I'm [17:37] currently doing and we didn't have any [17:39] good examples of this because again it [17:41] was very much internal to the closure [17:42] community and again we only had [17:44] convinced a small population within [17:46] closure to give a closure script A Try [17:49] So a big sort of change here um was the [17:52] arrival of light table because many [17:54] programmers were excited about light [17:55] table light table was uh basically [17:57] supposed to come out the door with [17:58] support for closure closure script [18:00] Python and I believe Ruby at some point [18:03] uh but but it was extremely exciting to [18:06] the pro the programming community at [18:08] large and um very cool stuff lots of [18:11] innovative ideas about how to make the [18:13] development process uh sort of more uh [18:16] interesting more interactive um and uh a [18:19] lot of these ideas just got copied like [18:21] I mean a lot of the ideas that appeared [18:22] first on light T just got copied over to [18:24] you know Swift playgrounds and uh xcode [18:28] and and uh intellig so the impact that [18:31] light table had was huge and Chris [18:33] Granger had written the entire thing in [18:36] closure script the whole thing was [18:37] written in closure script when it when [18:38] they open sourced it it was 11 to 12,000 [18:41] lines of closure script um that [18:43] integrated with node webkit and you know [18:45] people were like whoa closure script you [18:47] can do that with closure script you can [18:48] build a very serious application a very [18:52] impressive application with closure [18:54] script and I think this was the [18:55] beginning of a sort of change both [18:57] internal to the closure SC Community but [18:59] also external to the closure script [19:01] Community okay um here's an example of [19:03] what you can do uh that's quite [19:05] impressive and quite cool so huge shout [19:07] out to Chris stranger to getting people [19:09] to to sort of take closure script more [19:11] seriously it was definitely a big step [19:13] forward there okay so that at that point [19:17] you saw you saw after light table you [19:19] definitely saw more people picking up [19:20] closure script which is cool but I want [19:22] to talk a little bit now switch gears [19:24] just a tiny bit to talk about the uh the [19:27] closure enclosure idea aide right so [19:29] closure script um was almost from the [19:32] beginning the bootstrap was always there [19:34] as a possibility uh but there were [19:37] definitely some obstacles uh and this [19:39] one is interesting because this was both [19:40] relevant for bootstrap but also relevant [19:42] for debugging because as we entered the [19:44] two-year Mark um one huge problem would [19:47] be that so somebody would uh closure [19:49] program would try closure script they [19:51] used CJs build they've seen light table [19:53] that's awesome they want to start [19:54] building something and then they get a [19:57] an error and then um the code that [20:00] they're looking at it's like this crazy [20:01] JavaScript right because we weren't like [20:04] coffee script we had no intention of [20:06] ever producing anything readable right I [20:08] I specifically said earlier the only [20:10] thing we cared about is how fast is it [20:12] going to be you know like that's all we [20:14] cared about was performance we didn't [20:15] care about is this something for humans [20:17] to look at um and so there was a huge [20:20] problem here in order to make the code [20:22] debuggable uh we we need really needed [20:24] Source mapping and for two years uh [20:26] closure script did not have source [20:28] mapping um I mean part of that was [20:30] stalled by there wasn't great support in [20:32] browsers yet but once there was support [20:34] in browsers we just hadn't done the work [20:36] um part of the problem though was that [20:39] we actually reused the standard closure [20:42] reader that's written in Java right so [20:45] so closure script really piggybacked on [20:47] a lot of the functional was already [20:49] inclosure the closure reader now the [20:51] problem with the closure reader the [20:52] reader which actually reads text and [20:55] converts it into data structures which [20:56] represents your program before the the [20:58] compiler sees it that thing is what [21:01] annotates every symbol and every s [21:03] expression with file line and column [21:06] except the closure reader did not record [21:08] the column right so this was a huge [21:10] problem to get accurate um results from [21:14] the source mapping support that was [21:15] present in in web browser so this was [21:17] just we were blocked uh because we were [21:19] piggybacking on uh closure to do this [21:23] but closure was missing the [21:24] functionality that we needed um then a [21:26] very nice gentleman uh Nicolo MTO [21:29] and you're going to see this like like [21:30] people I think often misconstrue that I [21:33] mean I definitely do a lot of work on [21:34] closure script but so much of of each [21:37] significant advancement came from [21:38] somebody in the community and not [21:40] necessarily myself Nicolo MTO worked on [21:43] uh had this project called Blind and it [21:45] was a faithful implementation of the [21:47] reader and uh It Was Written in closure [21:50] so it wasn't written in Java so so [21:52] there's two benefits here one is that [21:54] okay it's possible if now now that it's [21:56] in closure porting it to closure script [21:58] is going to be trivial so that's one one [22:00] benefit the other benefit was that [22:02] because we weren't tied to closures [22:04] development timeline right so the core [22:07] team has a lot of things they have to [22:08] think about a lot of things they have to [22:09] consider and adding column information [22:12] is not necessarily the most high [22:13] priority thing right but tools reader [22:16] being a standalone separate open source [22:18] effort Nicola please add column [22:20] information I need it uh it's much [22:23] easier to get for that to happen he was [22:25] the only committer and um I convinced [22:27] him to make a contri project tools. [22:29] reader um and we swapped it we just [22:31] swapped it out because it was again a [22:33] faithful implementation of the reader [22:36] and then I spent uh two weeks on Source [22:40] mapping uh and a lot of work and this [22:43] isn't like remember this is 2012 so it's [22:45] nights and weekends for me I'm working [22:47] at the New York Times this is this is [22:48] not my job to fix debugging for closure [22:52] script this is just uh a fun open source [22:54] thing for me um so after two weeks [22:57] implementing Source map is really a pain [22:59] in the butt uh because when you get it [23:01] wrong it's it's one of these cases like [23:03] it's this really crazy um midi inspired [23:07] uh 64 uh B 64 encoding thing where you [23:11] have these these bits let them compress [23:13] and like anyways it's horrible so [23:15] debugging it's really ter a terrible [23:17] experience and I got burned out even [23:18] after two weeks of like doing this and [23:19] the week like ah nobody's helping me I'm [23:22] just like the only person that cares [23:23] about this working and no there nobody's [23:25] helping me and so I I set it aside for [23:27] like two months even though made like a [23:29] lot of progress and once again uh it's [23:32] Theo it's the awesome closure script [23:34] community that stepped forward uh and [23:36] made it and made it really happen so [23:37] Sean Grove jumped on IRC and was like I [23:40] see that you basically did all the [23:42] foundational work for Source mapping [23:44] what is it going to take to finish it [23:45] because he was uh building a a product [23:48] in closure script and he was losing his [23:50] mind at looking at the generated [23:52] JavaScript um and so he uh collaborated [23:56] with me he finished it and it basic [23:58] basically took it 98% of the way there [24:00] and then I just had to wrap up the last [24:01] 2% and then right at two years basically [24:04] or two years in a month uh closure [24:06] script had Source maps and that was [24:08] another huge change right suddenly a lot [24:12] more closure closure programmers were [24:14] like okay that's really great I can now [24:16] get um sensible step you know you can [24:19] set break points you can step debug uh [24:22] and that's just a huge usability uh uh [24:26] win uh so today like and and and [24:29] actually uh in Chrome you know you're [24:31] going to get syntax highlighted closure [24:33] code and you can set break points and [24:34] it's amazing it's like your browser is a [24:36] list machine this is uh still to this [24:38] day I I never ceases to amaze me I've [24:40] got all my closure script here in the [24:41] source in the browser uh and it's [24:44] awesome and it and it works reasonably [24:45] well it could definitely work better but [24:47] it works reasonably well um okay so that [24:52] was uh Source mapping uh another project [24:54] so this one is you know some of the [24:56] things that we do in closure script are [24:57] let's fix the problem the immediate [24:59] problem so some of those things are like [25:01] Source mapping some of those things are [25:03] like persistent data structure some of [25:05] the things we work on um are well if [25:09] this is going to be a problem in the [25:10] future or it may be something we want to [25:12] have flexibility on in the future so JS [25:15] modules was something that I predicted [25:16] would eventually be become important and [25:18] actually may it's still a bit ahead of [25:21] us it's not quite important yet but it [25:23] will probably eventually be critical [25:25] that we have a good answer uh and this [25:27] is because um uh compiling es6 is [25:30] becoming more and more of a thing uh [25:32] people are shipping their code as es6 um [25:35] uh that's that's one that's one one [25:37] problem the other is that then you have [25:39] really interesting libraries that are [25:40] written in the AMD format or a really [25:43] interesting Library written in commonjs [25:44] or a really interesting Library written [25:46] in node.js which is a really jacked up [25:48] version of commonjs so you have all [25:50] these competing module formats but the [25:52] but the libraries there are are useful [25:54] you want to be able to use something for [25:56] npm or you want to use an ES Library uh [25:59] what are you going to do how do you [26:01] integrate that stuff into into your your [26:03] closure project so um I decided this was [26:07] probably something we should invest some [26:09] time in and uh we were involved in [26:11] Google summer of code so I said this [26:13] sounds like a good project for Google [26:14] summer of [26:15] code and um uh there were a bunch of [26:18] other ideas for a closure script for [26:20] this this was not this past summer [26:21] because we didn't get in this past [26:22] summer but the summer before well there [26:24] were a lot of interesting projects but [26:26] really this was the only one that was [26:27] going to have a considerable amount of [26:29] impact an impact you know we're talking [26:31] about years into the future uh and I got [26:35] really lucky Maria Geller said I'm [26:37] interested in solving that problem uh [26:39] and this was really awesome and so she [26:40] was a somebody who had I thought she [26:43] signed up for this and I think she'd [26:44] been doing closure for like three months [26:47] and she signed up for this um summer of [26:49] code project uh and so by the end of the [26:52] summer she ended up being an expert in [26:54] the closure script compiler somebody who [26:55] had just learned closure ended up being [26:57] a closure script compiler compiler [26:58] expert and I think she may be the only [27:01] one that has contributed to closure [27:03] script that actually got Patches into [27:05] the Google closure compiler uh and [27:07] successfully because it's actually [27:09] Google a lot of people don't know this [27:10] but like if you submit something to [27:12] Google closure and it breaks anything [27:15] within Google internally they have they [27:17] have a whole system for automatically [27:18] backing out your changes that's how [27:20] important Google closure compiler is uh [27:22] to Google internally so she got her [27:24] patches in so that we could um have [27:26] better module integration um but it's [27:29] also another point about contributing to [27:30] closure script here's somebody who who [27:33] wasn't that familiar with closure and [27:34] people may you may you may think the [27:36] closure script pilot has got to be so [27:37] complicated and so sophisticated it's [27:40] really not it's it's if you're writing [27:41] closure or closure script programs it's [27:44] the same stuff you know we we have multi [27:46] methods and and we have maps and we have [27:49] vectors it's all the same stuff it's [27:50] really not any more complicated than [27:52] what you're doing um I highly recommend [27:54] watching Maria's talk last year at the [27:57] con where she talks you know she walks [27:59] through the whole compilation flow she [28:01] does a she do a incredible job making it [28:04] seem approachable um highly [28:06] recommended okay so those are those are [28:09] some of the better stories uh about [28:11] closure script development but not [28:13] everything in not everything is awesome [28:14] this is one of my favorite quotes about [28:15] richii uh you know open source is is a [28:19] funny thing you know basically what [28:20] happens with open source is you work on [28:22] stuff when you want to work on it [28:24] because nobody's paying you to do it [28:25] right um and sometimes that means things [28:28] things get left undone for a very very [28:31] long time so um uh PR print pretty [28:35] printing which many tools use enclosure [28:37] if you're enclosure you're probably [28:39] using it all the time uh maybe [28:40] indirectly um this had remained unported [28:44] for four years and every time and the [28:46] reason reason I couldn't bring myself to [28:48] do it is because if You' ever looked at [28:50] preprint pprint is written in 2009 era [28:56] closure code it uses death struct which [28:58] hopefully some of you have never heard [29:00] of um and and print is a port in 2009 [29:05] style closure of a com of common lisp [29:07] code right the the common Lis pretty [29:09] printer and so it's just like every time [29:11] and it was 3,000 lines of closure every [29:14] time I would look at it I would close my [29:15] tab right I was like cannot bring myself [29:17] to do this and um uh so so it languished [29:21] and it was huge problem because really [29:23] uh to not have it was really a huge [29:26] bummer for people who are coming closure [29:28] there's all this stuff in the standard [29:29] library and closure and when you use [29:31] closure script oh it's great it's great [29:33] it's great what why isn't this thing [29:35] there and it's really um a bad [29:37] experience um so it didn't get done and [29:40] it's unfortunate but once again the [29:42] community stepped forward and they made [29:43] it happen and it was Jonathan Boston and [29:46] Shan LeBron um they there was was I [29:48] think the single biggest uh PR or or [29:51] patch it was like a 3,000 line patch one [29:54] huge patch uh which implemented preprint [29:57] uh and this was really big because again [29:58] if you're doing development and you're [30:00] like you're doing reagent or you're [30:02] doing rum you're doing M and you're like [30:04] got this huge State atam you're just [30:05] like please I just want to prettyprint [30:07] the state of my application you can [30:08] finally do this uh and not set your hair [30:10] hair on fire so again another huge [30:13] contribution from the community uh that [30:15] makes closure script better um I had to [30:18] I there this this is the one case like [30:20] so another case where something didn't [30:21] get done for four years was testing [30:24] which is really unfortunate because I [30:26] think closure was one of these amazing [30:27] languages like closure had a testing [30:29] story like before 1.0 uh richii had [30:32] added um uh support for test metadata on [30:37] functions and that was like super cool I [30:38] like wow testing is like a first class [30:41] thing in a programming language um but [30:43] that did not happen for a closure script [30:45] and uh finally I I ended up doing this [30:47] so there had been a thirdparty thing by [30:49] Chaz Chaz Emer who some of you may know [30:52] he he wrote The Great O'Reilly closure [30:54] programing book he' done something but [30:55] you know again um in the end [30:58] uh your end user wants to know that the [31:02] difference between closure and closure [31:03] script is the same why do I have to [31:04] include a third party dependency to do [31:07] basic testing why isn't the basic [31:09] functionality of the programming [31:10] language there um so anyway some random [31:13] person on the internet you know [31:14] contributed this thing um and and that [31:17] really closed that really this that was [31:19] sort of the last puzzle piece of the [31:21] standard core name spaces once that was [31:23] done um uh a person could sit down and [31:25] reasonably expect all the functionality [31:27] that's en closure that's not around [31:29] multi-threading uh to be present in [31:31] closure script so that took four years [31:33] sometimes things take a really really [31:35] really long time if you're coming to [31:37] closure script right now in like in 2016 [31:40] you're really lucky you missed you [31:41] missed some a lot of [31:43] turbulence um okay and then and then the [31:45] other thing is like five years in um uh [31:48] we're finally now that these sort of [31:50] bigger problems have settled down we're [31:52] finally being able to focus on some of [31:54] the this earlier promise so rich was [31:56] like closure scripts about reach this is [31:58] finally there's going to be a way to [31:59] deal with like IOS and Android but four [32:02] years go by and actually nobody's really [32:04] said they've successfully done anything [32:06] um and a huge person that's done a lot [32:09] here especially in open source and [32:10] making sure that uh closure script as a [32:13] project is compatible um with these [32:15] great mobile platforms is Mike Fikes so [32:18] Mike Fikes you may know him because he [32:19] has a s called plank which is really [32:21] cool but it was Mike Fikes he actually [32:23] shipped an application on the App Store [32:25] with closure script and he built a lot [32:27] of infrastructure around making um the [32:30] closure script development experience on [32:31] iOS uh great and a lot of that's been [32:33] repurposed um to some degree uh for [32:36] Android but he built this really amazing [32:38] thing called amble which I if you [32:40] haven't seen this I highly recommend it [32:42] um and I think it would be a great model [32:44] uh for mobile development but basically [32:45] it's a thing it's a reppel a custom [32:47] reppel U so the other great thing about [32:49] am is that because we wanted to do am [32:52] his reppel server it required us to [32:55] refactor the way that reel worked so [32:57] that it was easier to make custom reppel [32:59] and so he built a reppel that actually [33:02] finds your iOS device so you make an app [33:04] you're building an an IOS app it it [33:07] broadcasts over the Wi-Fi network via [33:09] bonjour zeroc conf multicast DNS so it [33:12] finds it so you're in a reppel on your [33:14] desktop and it says you want to connect [33:15] to this device you you press in the [33:17] number of the reppel you want to connect [33:18] to boom you're you're logged in and what [33:21] we have a connection to JavaScript core [33:24] uh via a socket and then what we do is [33:27] you're just comp filing your files on [33:29] your on your desktop and we're [33:31] synchronizing all those files onto the [33:33] iOS device uh via uh webdav that's [33:36] pretty slick and so he again he built a [33:38] lot of cool apps and and basically um [33:41] you can basically build uh iOS apps um [33:44] untethered from xcode right you can [33:46] actually don't need xcode at all you [33:47] just need xcode to bootstrap but after [33:49] that uh you're just programming directly [33:51] against iOS live coding so the thing [33:53] that we really love about closure which [33:55] is live coding live programming uh this [33:57] is completely possible on iOS now which [33:59] is really cool so this is again probably [34:03] more future looking as we heard about [34:04] react native react native it's obviously [34:07] a Hu there's a huge potential there uh [34:09] and we're making finally making good on [34:11] it um so some work to do definitely some [34:13] hurdles but wow okay it's happening this [34:16] thing that rich was talking about five [34:18] years ago the reach okay so last thing [34:21] I'm going to talk about is [34:25] bootstrap so this was last year um so uh [34:29] if you only been doing closure for [34:31] closure script for one year you missed [34:33] the four years where we didn't even have [34:35] like real version numbers it was just [34:37] the the git revision number so you know [34:39] I think the last the last version before [34:41] we had real version numbers was like [34:44] 3,225 um and the reason we switched to [34:46] real version numbers was last year um [34:49] rich and at all the core team finally [34:52] decided to deliver on reader [34:54] conditionals so closure script and [34:56] closure even though they were [34:58] effectively the same language there was [35:00] no really there was no real official way [35:02] to share code between both languages you [35:05] had cl. clj files for closure. cljs [35:08] files for closure script there were a [35:10] bunch of hacky tools which were which [35:12] worked okay uh to allow you to share [35:15] code but um they all suffered because [35:18] they weren't official Solutions and so [35:21] uh 1.7 closure 1.7 released reader [35:23] conditionals allowing you to write write [35:25] cljc files common file is shared by both [35:29] programming languages and of course what [35:31] do I do as soon as they land reader [35:33] conditionals I I I I bump the version [35:36] the dependency version in closure script [35:37] I'm like we can we can just we can just [35:40] we can just compile the compiler now [35:42] right that was literally the first thing [35:44] I did was okay I'm going to convert all [35:46] the compiler and the analy analyzer [35:48] files to cljc and I'm going to run the [35:51] compiler on itself what doesn't work and [35:54] so for a month it was just me slowly [35:57] working through through the analyzer [35:58] slowly working to the compiler until the [36:01] point that both of those uh files could [36:04] successfully be compiled um that was a [36:06] lot of fun uh because at the other end [36:08] of that we were going to have something [36:09] really cool which was a version of [36:11] closure script that could run without [36:12] the jvm it could be completely [36:14] self-hosted which is you know cool for [36:17] it's like a very lispy thing to do um so [36:20] uh at the moment this was like the final [36:22] moment before I was done um this file [36:25] this is the macros file uh so there's a [36:28] file called cj. core which is just clj [36:31] it's just all the macros uh um that we [36:35] use and and again these are the compile [36:36] time macros right uh so so the the it's [36:41] right here that it gets really funny [36:43] this is tying the knot and getting a [36:45] little bit metac circular right this [36:47] this macro file is requiring the [36:49] standard library and the analyzer right [36:52] so this is sort of tying the knot we [36:54] we're sort of requiring oursel again um [36:58] and you know people complain a little [37:00] bit but I think people are finally used [37:01] to it about the fact that macros are [37:03] sort of a compile time thing but it's [37:06] actually specifically because it's a [37:08] compile time thing that bootstrapping [37:10] closure script was so straightforward [37:13] right all I had to do was compile the [37:15] analyz and the compiler and then all I [37:17] have to do is take those two generated [37:19] JavaScript files and append them to the [37:21] standard library and we're done we don't [37:23] have this crazy talking to the compiler [37:25] and talking to the runtime at the same [37:27] same time because um there are two [37:29] distinct phases in closure script [37:31] there's macro time and there's runtime [37:33] and they'll never meet but that means [37:35] bootstrapping closure script was uh a [37:37] very very very straightforward Affair [37:39] and we've already seen uh the benefits [37:41] of that today with Clips there's people [37:42] make awesome demos all the time you've [37:44] got plank which is a really great reppel [37:46] that runs on Linux Windows OS 10 you've [37:49] got um uh what's it what's it replete [37:52] for iOS which is a full-blown uh closure [37:55] script reppel on your is phone so if [37:56] you're on the Metro you can you can hack [37:59] closure while you're while you're uh [38:01] while you're waiting to get to work and [38:03] it and it's particularly neat because it [38:04] actually uses a par infer which is also [38:07] a really amazing Innovation from the [38:09] closure Community which infers the [38:11] location of your parentheses based on [38:13] indentation so you don't need a crazy [38:14] keyboard it's [38:16] amazing um so that that that that gives [38:19] a sense of what's happened you know so [38:21] hope I'm sure that many of you weren't [38:23] aware of all the various things that [38:25] happen so this gives a sense of how much [38:27] work is involved how many people are [38:29] involved um of course there are many [38:30] more people uh I can't I can't I can't [38:32] show everybody's photo or or or think [38:34] everybody's names but there's been no [38:36] contribution that's too small so there's [38:38] now I think 141 contributors literally [38:41] every single person that's ever opened [38:42] the issue that ever jumped on IRC and [38:44] asked a question that said is this how [38:46] it's supposed to work um that ever filed [38:48] um a ticket or a patch uh it's everybody [38:51] that's made um this project great we it [38:54] closure script is as good as it is today [38:56] because everybody that's worked on it uh [38:59] other cool things that happened I mean I [39:00] haven't again I'm focusing mostly on [39:02] closure script itself because um we [39:05] could spend you know weeks talking about [39:07] all the other cool things but I'll [39:09] summarize um of course things really [39:11] changed with um with the appearance of [39:13] react because suddenly closure script [39:15] was okay that's doesn't that's weird [39:18] okay you have immutable immutable data [39:20] structures but you have to talk to this [39:21] horrible thing called the Dom so it [39:22] doesn't really matter right and was [39:24] really react I was like you know the [39:26] floodgates were open you know Cambrian [39:28] explosion right suddenly there were all [39:30] these libraries that integrate with [39:32] react and now like closure script is [39:34] like ahead of the pack like way ahead of [39:36] the pack in like what's the best way to [39:38] do UI uh we're definitely at the [39:40] Forefront and in many ways uh the react [39:43] Community is still catching up like I [39:44] went to the react conference and and [39:46] like you go up there and they're like [39:47] flux and you're like Ah that's horrible [39:50] you know so I I think we're way ahead in [39:52] terms of of what react is good for and [39:55] and how we should go about uh doing UI [39:58] work and so it's super inspiring to me [40:00] and exciting to see uh the closure [40:02] script Community um really really go way [40:04] further than a lot of other uh sort of [40:07] stuff happening in the mainstream um [40:09] lots of other cool things happen like [40:11] cjf Dev tools if you haven't seen this [40:13] so This solves the problem I don't know [40:14] his real name I just know his online [40:16] handle Darwin or something but he wrote [40:18] a Chrome extension which uses Chrome's [40:21] custom object printing so even though [40:23] Source mapping is great you know when [40:25] you when you log a vector it's like this [40:28] horrible JavaScript object you don't [40:30] want to look at that and so he actually [40:31] has custom printing of of closure script [40:34] data structures inside the web browser [40:37] whether you're step debugging or whether [40:39] you're interact with the console it's [40:40] awesome it's really really cool if you [40:42] haven't checked it out you most [40:43] definitely should um and then and then [40:45] there's another thing about open source [40:47] which I really love which is that [40:48] sometimes people do competing projects [40:50] so closure script is not just the story [40:51] of like what were all the things we did [40:53] in core what were the what were the [40:55] better ideas that people had that [40:56] weren't in core uh so Shadow build was a [40:59] sort of a competing build tool um by [41:01] Thomas heler and Thomas hel was very [41:03] active in in discussions you know he [41:04] submit some Pates was great but you know [41:06] Shadow build was his idea of how the [41:09] closure script compiler should work as a [41:11] build tool and it took I think we had a [41:13] year and a half there were many things [41:15] that shadow Bill did that we did not do [41:17] for example Google closure modules which [41:19] allow you to do code splitting so he had [41:21] that in for like months before we had it [41:24] um the new feature where we can infer [41:26] whether something is a macro macro VAR [41:28] or runtime VAR so you don't have to do [41:29] refer macros this existed in Shadow [41:32] build long before it existed um in [41:35] closure script itself so a lot of times [41:37] uh the the best source of ideas are are [41:39] just people doing their own thing uh and [41:41] that's also really really great okay [41:46] so closure script is an iter iterative [41:49] process it's sort of a random walk in [41:51] the right direction right so you can [41:53] expect the next five years it's probably [41:55] going to be a random walk in the right [41:57] direction things will happen when people [41:59] want them to happen um so my my talk my [42:02] my title is a bit misleading but I [42:03] wanted to sort of show how how have you [42:05] been doing it and then now you have a [42:07] good expectation of of how it's going to [42:09] happen um but there are some things that [42:11] we want to do next and I'm going to [42:13] enumerate some of them there are many [42:14] more but some highlights at least so [42:16] things that are always high priorities [42:18] like people you're probably wondering [42:19] how does closure script development work [42:21] uh so the highest priority is always [42:22] closure parity right so this was as I [42:25] pointed out the biggest pain point in [42:26] closure is almost always it doesn't work [42:28] the same as enclosure why it doesn't [42:30] make any sense so this is always a high [42:32] priority so you can expect for the next [42:34] you know at least until closure One n [42:36] the main thing we're working on is is [42:38] spec so we have um up to Alpha 11 parody [42:42] and of course they've already rolled out [42:44] new stuff and that stuff will be coming [42:46] uh but I definitely think spec is huge I [42:49] think uh I supect we'll be still be [42:52] learning about what benefits spec has [42:54] long into the future this is definitely [42:56] at least for the next two years we're [42:58] going to begin to understand what's [43:00] possible with something like spec um [43:02] another big one is closure compile [43:06] integration we want the module stuff to [43:08] be better again Google's constantly [43:10] updating stuff they don't really care [43:12] with break they they care when if we do [43:14] something to break them but they don't [43:15] really care if they break the rest of [43:16] the world because they're the only ones [43:19] you really seriously using a closure or [43:21] closure Library um so we are interested [43:23] in staying a breast of their changes and [43:24] their enhancements another thing [43:26] actually in five years we've never [43:28] worked on compiler performance um it's [43:31] okay it's okay uh the only thing I did [43:33] uh was I did parallel build so if you [43:36] have end cores we try to compile um you [43:39] know each different files on different [43:40] cores as much as we can so that's for [43:43] production builds that's great um but it [43:45] doesn't help with serial performance and [43:47] nobody's actually ever sat down and said [43:49] okay let's just focus on the serial [43:50] performance to the compiler I suspect [43:52] there's at least a 2X perf gain right [43:55] here so to me like if you're compile [43:57] times can go down from 30 seconds to 15 [43:59] seconds and then you add parallel build [44:01] you get down to seven that's a huge win [44:03] and I would like to see uh eventually I [44:05] might get to this but if somebody else [44:06] is interested in it I would love to see [44:08] that happen Windows uh this is probably [44:10] less of a problem but I I mention it [44:12] anyways because we don't have that many [44:13] windows users and people often like [44:15] closure script's so awesome but it's [44:16] broken on windows so if you're a Windows [44:19] user and you have a patch there's a [44:21] there's a chance I will apply it [44:22] immediately the moment I get a Windows [44:24] patch it'll probably get applied because [44:26] we care we want our stuff to work great [44:28] everywhere um more tests you know so [44:31] maybe some of you are like well I don't [44:33] don't the compil to still too scary I [44:35] mean something that's missing in closure [44:37] script still is we don't have enough [44:39] tests there's there's really never [44:40] there's no such thing as too many tests [44:42] um especially with a tool that's now as [44:44] sort of sophisticated as the closure [44:46] script compiler we have many options uh [44:48] we would like to have test for each [44:49] options uh for the runtime stuff we [44:51] would like to have generative tests we [44:52] would like to actually do generative [44:54] testing of things so maybe you're like [44:56] oh I've got some time I actually I want [44:57] to contribute some tests that would be [44:59] awesome um runtime performance harness [45:01] would be great um this is probably lower [45:03] priority but it would be nice to able to [45:05] track performance the performance of the [45:07] generated code over time um [45:10] forward-looking so closure spec is huge [45:13] again I I could say this a million times [45:15] I think it's really really really big um [45:17] but there's an obvious thing here that [45:19] um you know we can't do all the fancy [45:20] recursive stuff but we could trivially [45:23] emit uh very basic valid like compile [45:27] time validation right so is this [45:29] parameter nillable is this parameter a [45:31] map or a number or a vector they're very [45:34] basic type checks um that we could [45:36] actually convert into static type checks [45:39] to uh closure compiler we could pass [45:41] them onto closure compiler and at least [45:43] you know oh we're not going to [45:44] production with something where we [45:46] passed nil and we didn't check for that [45:48] and that would be huge so this is [45:49] definitely something I would like to do [45:51] with closure spec to convert those [45:52] things into um type information with a [45:55] closure compiler public apis this is [45:58] definitely more for tooling people but [45:59] raise your hand if you use fig [46:01] wheel right so there a lot of people so [46:05] this this may not immediately affect you [46:06] but it it does affect you because the [46:08] reason fig wheel is able to do all this [46:10] awesome stuff like now it has almost [46:12] almost Elm quality uh errors about [46:15] location of your errors and where things [46:16] went wrong it's beautiful and that's [46:18] only because we expose the right hooks [46:20] ride the right public hooks inside the [46:22] closure script compiler so if you want [46:24] your tools to be better that's another [46:26] thing or if you're interested in tools [46:27] becoming better um uh thinking about the [46:29] Clos script public apis is something [46:31] that's extremely important moving [46:32] forward and this is probably the last [46:35] the last thing before I I switch gears [46:37] again um so this is one I'm probably [46:39] going to work on myself and I have some [46:41] prototypes so if you've been doing [46:42] closure script for a while probably the [46:45] largest source of insul denal complexity [46:47] in closure script closure script is [46:48] awesome but there's things that are not [46:49] awesome is externs right so you want to [46:52] use react or you want to use high charts [46:54] or you want to use just use some random [46:56] react component that somebody wrote and [46:58] the problem is you can do this but when [47:01] you do your production build it's going [47:02] to break because you don't have externs [47:05] right you don't have the the the the [47:07] definitions that the compiler the [47:09] closure compiler the Google closure [47:11] compiler needs to know you cannot change [47:14] this name you cannot change this name um [47:17] and so it's extremely error prone even I [47:19] run to this I do an advanced build oh my [47:21] God I'm ready to go to production and it [47:23] doesn't work because I missed an next [47:25] turn right it's a huge source of inst on [47:27] complexity um so this I think is [47:29] actually a solvable problem and actually [47:32] probably there's a good chance we can [47:33] really do a good job here um but this [47:35] would be huge uh it would be probably [47:37] the last problem that we really have [47:40] when we want to integrate with third [47:41] party libraries we would like to remove [47:44] the need to ever write extern files like [47:46] that would be a gigantic step forward [47:49] for integrating with Again The Wider [47:51] JavaScript ecosystem so that's most [47:53] definitely on the very near future Road [47:56] mapap um but in order for any of this [47:58] stuff to happen it requires more people [47:59] or people that are interested in helping [48:00] out so you know people I think uh think [48:03] that the contribution process is [48:04] complicated it's not how do how to [48:06] contribute um submit your contributor [48:08] agreement even if you think you're like [48:10] I'll never contribute to closure or [48:11] closure script just do it because [48:13] chances are I mean i' there bugs that [48:16] I've seen I'm like how is it that we [48:18] that the people using closure script for [48:20] five years and we never found that bug [48:22] like persistent Maps break after nine [48:24] entries on this weird case how did we [48:26] never see that um and then somebody [48:29] submits a patch because they look at the [48:30] function and it's a simple bug right [48:32] it's a simple thing you can fix it you [48:33] know closure um so submit your [48:35] contributor agreement you never know [48:36] when it might be useful um if you're [48:39] interested in getting more involved uh [48:40] people know I'm very active on IRC and [48:43] slack cljs Dev is where we talk about [48:45] Dev stuff uh again everybody is welcome [48:49] even even you might learn something just [48:51] by lurking there so uh uh come join the [48:54] fun um and if you are getting involved [48:56] then look for low hanging fruit don't [48:58] pick some crazy task find something in [49:00] jira and like be like oh that's a patch [49:02] and that's I need that just test it and [49:05] leave a comment I tested it it works um [49:07] and if you have a trivial patch just [49:08] submit it um there's no again there's no [49:11] issue that's uh too small okay and then [49:13] of course there are other forms of [49:14] contribution it's ALS it's extremely [49:16] exciting to be here because this this is [49:18] Hu this is a big conference it's like [49:19] 300 people like I I go to JavaScript [49:21] conferences that aren't this big so it's [49:23] it's definitely super exciting to me but [49:25] there are other ways to contribute that [49:26] aren't so code Centric um uh for me it's [49:29] been awesome because I I like in 2008 I [49:31] was like I'm going to do common list and [49:33] then that didn't really work out and [49:35] fortunately there was closure but really [49:37] it felt like to me as much as I loved [49:38] list list seemed like too weird and and [49:42] and you know you look at Hacker News or [49:43] you look at Reddit and like you look at [49:45] coding blogs and it's like it's so [49:47] normal to see a Blog with like closure [49:50] code like nobody thinks this is weird [49:52] and this is the best possible thing [49:54] there's nothing weird about using a list [49:56] for writing lists so writing about your [49:58] experiences whether you're doing react [50:00] native you're doing raan or Rum or [50:01] whatever just writing about your [50:03] experiences and helping people adopt the [50:06] technology that's one of the most [50:08] impactful things you could possibly do [50:11] um of course presentations give [50:12] presentations to your local user groups [50:14] give presentations at conferences um [50:17] it's been great I I have to give less [50:19] talks the more the more you give talks [50:21] on closure closure script somewhere the [50:23] less that we have to run around because [50:25] I mean in order for closure closure and [50:27] closure script to succeed it really is [50:29] again it's a community effort it can't [50:31] just be core team people uh giving talks [50:33] and cool presentations uh and build cool [50:36] stuff and talk about it this is the only [50:37] thing that again I believe it's the only [50:39] thing that convinces developers you can [50:41] talk about fancy language features all [50:44] day um but really developers are [50:46] convinced when you show them something [50:48] cool um so again thank you very much um [50:52] uh again I hopefully I give some sense [50:54] about how much effort's gone into it and [50:56] again the reason I love closure script [50:58] is that every time I fire it up it's [50:59] really feels even though I've been [51:01] contribued so much to it it feels like [51:03] alien talk technology it feels like I [51:05] can't believe you can do this stuff it's [51:07] so cool um I use all the same tools that [51:10] you all use I use cgis build there are [51:12] people like cognitech using boot we're [51:13] using fig wheel I mean all this stuff [51:15] that's getting developed is the same [51:17] stuff um and it's great to see that [51:19] everybody's uh pushing it Forward uh so [51:21] thank you and um probably went over um [51:23] maybe I can take some questions [51:26] [Applause] [51:50] um given that you've been able to [51:52] rewrite closure code in closure from [51:56] with when it before was written in Java [51:58] have you been able to backport or I'm [52:00] thinking about backporting some of the [52:02] JavaScript generating code into actual [52:05] closure so you could rewrite closure in [52:08] closure instead of having the persistent [52:10] data structures that are written in Java [52:12] currently or like bring protocols to the [52:15] core has the um the kind of the other [52:18] guys or the persons working on the core [52:19] team been thinking about this of reusing [52:22] what the closure script people have [52:24] written to rewrite parts of closure in [52:27] closure um I mean there's been no [52:30] discussion about that um but I I suspect [52:33] that um if you know I mean the thing is [52:36] you have to prioritize and so uh I don't [52:39] know when with closure spec being like [52:41] the main focus the dev Focus right now I [52:42] don't know when they're ever going to [52:44] relook reconsider the way that the [52:46] closure compiler has been done I do not [52:49] doubt that some point in the future they [52:50] will they will revisit it and remember [52:53] Rich wrote the first version of the [52:54] closure script compiler so that was his [52:56] idea of what a closure enclosure would [52:59] look like so I'm convinced that whenever [53:01] they go back to do it again it's going [53:03] to be heavily informed by uh how we did [53:06] it in closure script so there's there's [53:08] definitely going to be some sort of [53:09] feedback loop as to whether um we'll [53:12] copy and paste stuff that's you know [53:14] that remains to be seen um but yes I I'm [53:17] sure that the experience of closure [53:19] scrip is going to inform if there is a [53:21] next version of closure it will inform [53:23] it [53:40] David can you just touch on Mori in the [53:42] history you gave of closure closure [53:44] script um where did Mory fit into that [53:48] so Mory so Mory was so that's so okay [53:51] Mor is um uh what I did was once once we [53:55] had all the persistent data structure I [53:57] was like whoa this is so cool persistent [53:58] data structur in JavaScript and they're [54:00] fast uh on V8 and node uh so what I did [54:03] was I made a library called Mory in [54:05] which I compiled closure script just the [54:08] persistent data structures into a sort [54:11] of idiomatic JavaScript dependency for [54:14] node.js or even frontend um and the and [54:18] and uh and I published the benchmarks I [54:21] compared it to jbm presentation I was [54:23] like these are really great numbers you [54:25] should check this out uh in fact I had [54:27] numbers where um it's faster to build um [54:31] a transient Vector than is to build um a [54:33] mutable array like if you want to build [54:36] a mutable JavaScript array with 1 [54:38] million elements it's faster to build a [54:40] transient Vector um but uh it was it was [54:43] really hard to convince JavaScript [54:45] people to use it I mean a few people [54:47] were interested in it but it was basic [54:48] it came out Mori came out in 2012 and I [54:51] gave I talked about it a little bit at [54:53] JavaScript conferences but it remained [54:56] un JavaScript developers are [54:57] uninterested in it until react until [55:00] 2014 so it took two years before anybody [55:04] in the JavaScript Community cared about [55:06] myy but uh with Mory because Mory um I [55:10] talked about my and I talked about um [55:12] react um I think a lot of that [55:14] influenced Facebook to do immutablejs so [55:17] there there definitely was a very strong [55:19] connection but again I think this goes [55:21] to my point like it's really hard to [55:24] convince programmers to make decisions [55:26] based only on benchmarks and technical [55:28] stuff there has to be I think some other [55:30] thing going on and react happened to be [55:32] the the magic ber dust that made people [55:35] interested in it does it hopefully this [55:37] answer gives you some history and [55:47] context hi uh you mentioned Maria Geller [55:50] uh working on the JS module support [55:53] what's the what's the status of that and [55:54] is is there still any momentum there is [55:56] that being carried forward uh so it uh [55:59] she I she so she's the maintain sej [56:01] build so my and and also my library M so [56:04] I think she's probably a bit busy cljs [56:07] build is still I think one of the most [56:08] popular build tools um so I don't think [56:10] she has time to do the module stuff the [56:12] module stuff that she has works as well [56:14] as it did in G gsoc in Google summer of [56:17] code so everything that she she showed [56:20] that works right now um and in fact um [56:23] there's already been stories of people [56:25] that have integrated MD modules or [56:26] commonjs modules uh and even with the [56:29] limitations it is useful however uh it's [56:31] not quite where I would like it to be um [56:35] first of all Google closure actually [56:37] broke the interface that we were using [56:39] so when we bump Google closure we're [56:41] going to have to fix her work uh but [56:43] more importantly um uh we still haven't [56:46] done like what I would call like the [56:49] real test and to me uh what should what [56:51] you should be able to do if the module [56:53] stuff works correctly is that you should [56:55] be able to include all of react in your [56:57] build like you should be able to say I [56:59] want to load react component at the [57:02] module react component and you should [57:03] only get get that and we should be able [57:05] to dead code eliminate all of react that [57:07] you don't use that's the actual Target [57:10] um that that we basically make the rest [57:13] of the JavaScript World conform to us [57:15] which is that their code becomes [57:17] optimizable that that that's the real [57:19] goal here right is that you can take [57:21] some random JavaScript library and you [57:24] can now um apply all the benefits that [57:27] we have with closure script code right [57:28] this is this to me is the problem with [57:30] third party stuff is that when you when [57:32] I when I use some gigantic closure [57:34] script library and I only use one [57:35] function I know I'm only going to get [57:37] one function this is awesome we don't [57:39] have this this myopic view of the world [57:41] where you have Micro modules we don't [57:43] care because Google closure eliminates [57:45] all the stuff you don't use and I would [57:47] like to be able to know that um even [57:51] third-party JavaScript libraries that we [57:53] cannot control the development of we are [57:55] able to apply this same optimization [57:57] techniques too um so yes this is still [58:00] where we want to [58:10] be what about web web assembly is that [58:13] good news for closure script uh it's [58:16] it's not bad news that's that's that's [58:18] for sure I mean there's um I mean I [58:20] think web assembly immediately um if [58:22] you're doing high performance numeric [58:24] stuff I mean you could immediately be [58:25] like oh I could write a a cool DSL for [58:27] web assembly so I can get super [58:29] optimized closure script functions for [58:30] my game or something there's obviously [58:33] no downsides um there um the bigger [58:36] question is to whether it's the right [58:38] solution um for uh as a compilation [58:42] Target for a closure script I mean [58:44] that's a bigger question there are lots [58:45] of things that need to happen with web [58:47] assembly before we can go there uh [58:49] closure script like closure assumes the [58:51] presence of a high performance GC um and [58:53] there's no GC integration story for web [58:55] assembly you you would have to write you [58:58] know your own GC and that sounds like a [59:00] performance nightmare um but but the [59:03] final word hasn't been said right I know [59:05] that the web ASM committee they're aware [59:08] of that limitation uh so it may be that [59:12] 10 years or maybe six years or maybe [59:14] maybe sooner I I have no idea maybe [59:16] sooner if it becomes a desirable Target [59:18] there's no question we will Target it if [59:20] it if it's the right thing but it's cool [59:23] it's is absolutely cool it definitely [59:26] closes the Gap in the types of [59:27] performance you would get expect to get [59:29] out of a browser [59:34] environment hi so um Maria's work and [59:38] the extern stuff you mentioned at the [59:40] end is that related is it the same or is [59:43] it complete am I like Off the Mark so [59:46] they're they're um they're somewhat [59:49] complimentary right so if you could [59:51] consume third party libraries then you [59:53] wouldn't have to write externs like if [59:54] you could actually consume them them [59:56] truly consume them and pass them to [59:58] Google closure you wouldn't need externs [59:59] for them anyway um but uh the fact of [60:03] the matter is um maybe maybe you use [60:06] random random Library one and it's es6 [60:08] and you're like boom it just works it [60:10] just works but then you use some other [60:12] thing you're like it doesn't work why [60:14] not okay I'm just going to include it as [60:17] a part of my build and keep it out of [60:19] the advanced compilation but with the [60:21] externs inference you wouldn't have to [60:23] write an externs file for that so yes [60:25] all of these things are designed to make [60:27] integration with the wider ecosystem [60:29] better um but they're sort of attacking [60:32] it from two different [60:44] ways cool thank you thanks for your [60:46] patience and uh yeah [60:48] [Music] [60:50] [Applause] [60:52] [Music]