As of version 0.70.0, Meta’s Hermes became the default JavaScript engine for React Native. While JSC is still supported, the React ecosystem moves fast, and what is the default now can quickly become the only supported option.
The Problem
ClojureScript depends on Google Closure as both a standard library and a compiler. Hermes does not yet support ES6 classes, which are used in several places in the Closure library. The Closure compiler does support transpiling to ES5, but without advanced optimizations, there is a small bug.
When Closure converts an ES6 class to a simple var, it uses the
file location to build a JS name (e.g. my$directory$src$index
). For files
in JARs (which is how ClojureScript bundles up google-closure-library
, for
example), that filename will have a !
in it (e.g. bundle.jar!src/index.js
).
Since Closure does not specifically replace the !
, it results in a var name
that illegally contains the !
character, and therefore unparseable JS.
The Immediate Solution
The easiest thing to do is to just find/replace these illegal var names before
they make it into a JS interpreter. When you start up a ClojureScript REPL with
Krell, it will build all of the
Closure JS into target/
first, so I have script that scours that directory for
broken JS and fixes it:
#!/bin/sh
find ./target/goog -type f -name "*.js" -exec sed -i '' 's/\!\$/_$/g' {} +
Then I just run that script when I yarn start
to start the Metro server
that provides JS in the dev environment:
{
"start": "sh ./scripts/fixClosure.sh && react-native start",
}
The Permanent Solution
Not generating illegal JS from Closure in the first place would of course be preferable. I submitted a small PR to the Closure project that fixes the behavior. That fix was accepted, so on the next release of Closure and then the next release of ClojureScript, ES5 output should work without hacks.