<commit_before># ESM Braindump

The idea of writing an alternate CLJS compiler that emits "modern" ESM JavaScript code instead of ClojureJS has been circling in my head for years now. Still not sure this would be worth doing but I need to get this out of my head so I can stop thinking about it.

I assume that the reader is familiar with ESM and how JavaScript works otherwise this won't be very easy to follow.

## Motivation

ClosureJS **the module format** is dead. **Not the Compiler or Library**. Can't find the reference but the Google Closure devs said they are moving the Closure Library over to more modern formats (possibly even Typescript). This process started years ago by moving parts from `goog.provide/require` to `goog.modules`. Over time mode actual ESM code should make it in. The Closure Compiler nowadays supports ESM code just fine so there really is no reason for ClosureJS to exist anymore (more on that later). Heck even today the `goog.module` code requires transpilation and isn't directly loadable as their `goog.provide/require` counterparts were.

ClosureJS is also the biggest blocker for smoother interop with the broader JS ecosystem. The JS world never adopted it and getting the code to work with other JS requires all sort of ugly hacks (eg. glue code using globals).

When <NAME> first announced ClojureScript the choice of using ClosureJS was the correct one. Nowadays not so much, there is an actual standard now. Note that I'm **ONLY** referring to the ClosureJS "module" format used by the Closure Library and Closure Compiler. The Closure Compiler is just as relevant as ever and still the best option, it just also supports ESM just fine today. Obviously it didn't back then, but it does now. It is an actual standard that is not going anywhere.

## The "Problem" to Fix

The ClosureJS output mode using a ad-hoc namespacing system setup by `goog.provide`. `goog.provide("cljs.core");` will create a nested `var cljs = { core: {} };` object in the **global scope** and any additional "var" will just be added to that object. (eg. `cljs.core.assoc = function() ...`). For the Compiler `goog.require` statements are added to wire up dependencies required to be loaded before the actual file. At runtime these don't have any effect besides "guarding" against trying to load files in the wrong order. The "Debug Loader" actually ensures that files are loaded in the correct order. The Debug Loader is only used in unoptimized builds as the Closure Compiler remove/rewrite this ad-hoc namespacing system completely when optimizing.

The Debug Loader however makes integrating with other systems hard. The Closure Library has one Debug Loader implementation (which regular CLJS still uses) but `shadow-cljs` has had its own loading mechanism for years now. This fixes some issues with loading but overall the main issue persists. For each target platform this loader needs to use whatever loading mechanism the platform provides to emulate its own loading. For the browser this was traditionally done by emitting `<script>` tags in the correct order or loading the files via XHR. This is actually pretty terrible performance-wise for bigger project which is why I added [:loader-mode :eval](https://clojureverse.org/t/improving-initial-load-time-for-browser-builds-during-development/2518) to `shadow-cljs`. Initially for `:browser` builds only but nowadays `:react-native` uses the same strategy.<commit_msg>Fix little typo (#844)<commit_after># ESM Braindump

The idea of writing an alternate CLJS compiler that emits "modern" ESM JavaScript code instead of ClosureJS has been circling in my head for years now. Still not sure this would be worth doing but I need to get this out of my head so I can stop thinking about it.

I assume that the reader is familiar with ESM and how JavaScript works otherwise this won't be very easy to follow.

## Motivation

ClosureJS **the module format** is dead. **Not the Compiler or Library**. Can't find the reference but the Google Closure devs said they are moving the Closure Library over to more modern formats (possibly even Typescript). This process started years ago by moving parts from `goog.provide/require` to `goog.modules`. Over time mode actual ESM code should make it in. The Closure Compiler nowadays supports ESM code just fine so there really is no reason for ClosureJS to exist anymore (more on that later). Heck even today the `goog.module` code requires transpilation and isn't directly loadable as their `goog.provide/require` counterparts were.

ClosureJS is also the biggest blocker for smoother interop with the broader JS ecosystem. The JS world never adopted it and getting the code to work with other JS requires all sort of ugly hacks (eg. glue code using globals).

When <NAME> first announced ClojureScript the choice of using ClosureJS was the correct one. Nowadays not so much, there is an actual standard now. Note that I'm **ONLY** referring to the ClosureJS "module" format used by the Closure Library and Closure Compiler. The Closure Compiler is just as relevant as ever and still the best option, it just also supports ESM just fine today. Obviously it didn't back then, but it does now. It is an actual standard that is not going anywhere.

## The "Problem" to Fix

The ClosureJS output mode using a ad-hoc namespacing system setup by `goog.provide`. `goog.provide("cljs.core");` will create a nested `var cljs = { core: {} };` object in the **global scope** and any additional "var" will just be added to that object. (eg. `cljs.core.assoc = function() ...`). For the Compiler `goog.require` statements are added to wire up dependencies required to be loaded before the actual file. At runtime these don't have any effect besides "guarding" against trying to load files in the wrong order. The "Debug Loader" actually ensures that files are loaded in the correct order. The Debug Loader is only used in unoptimized builds as the Closure Compiler remove/rewrite this ad-hoc namespacing system completely when optimizing.

The Debug Loader however makes integrating with other systems hard. The Closure Library has one Debug Loader implementation (which regular CLJS still uses) but `shadow-cljs` has had its own loading mechanism for years now. This fixes some issues with loading but overall the main issue persists. For each target platform this loader needs to use whatever loading mechanism the platform provides to emulate its own loading. For the browser this was traditionally done by emitting `<script>` tags in the correct order or loading the files via XHR. This is actually pretty terrible performance-wise for bigger project which is why I added [:loader-mode :eval](https://clojureverse.org/t/improving-initial-load-time-for-browser-builds-during-development/2518) to `shadow-cljs`. Initially for `:browser` builds only but nowadays `:react-native` uses the same strategy.
{'fraction_non_alphanumeric': 0.053165290453426044, 'fraction_numerical': 0.0015935100680863393, 'mean_word_length': 4.594813614262561, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4383235', 'n_tokens_mistral': 1764, 'n_tokens_neox': 1640, 'n_words': 1058}