facebook/hermes

Add support for `atob()` and `btoa()` functions

jonkoops opened this issue ยท 20 comments

Problem

Much of the existing code in the JavaScript ecosystem, such as packages on NPM contain code that uses the atob() and btoa() global functions. And although not strictly part of the ECMAScript specification, it might be worthwhile to support these for the sake of compatibility with the rest of the ecosystem. Other runtimes that are also not strictly web-based such as Node.js, Bun and Deno all support these functions as well.

Solution

Add support for the atob() and btoa() global functions to Hermes.

Additional Context

I contribute to jwt-decode, a popular library (~5.7 million downloads per week) to decode JSON Web Tokens. One of the users logged an issue specifically referencing this issue in React Native, and by extension Hermes (see auth0/jwt-decode#241).

tmikov commented

It seems that JSC supports these, which is a pretty strong argument in favor of adding them.

@tmikov My understanding is that these were added to JSC relatively recently, and only to the CLI tool. (in WebKit/WebKit@70ccbd9). So RN users on JSC would likely still need an atob polyfill.

There seem to be three options:

  1. Continue using the polyfill, which may be slow if the inputs are large.
  2. Adding Base64 encoding and decoding to Hermes natively.
  3. Add an implementation over JSI to RN. But this will be clumsy to write because JSI forces strings to be converted to UTF-8, which means we will force some unnecessary conversions for the binary string. If we do this, we should consider adding functions to convert to/from std::u16string.
tmikov commented

Issues like this will keep popping up. I think we need to figure out a general way to address them without the overhead of JSI. An optional "library" .so perhaps.

I've been using the JSI based https://github.com/craftzdog/react-native-quick-base64

Issues like this will keep popping up. I think we need to figure out a general way to address them without the overhead of JSI. An optional "library" .so perhaps.

The pure JS polyfills everyone recommends in these threads are even worse than JSI!

Issues like this will keep popping up. I think we need to figure out a general way to address them without the overhead of JSI. An optional "library" .so perhaps.

It's perplexing to me how long the RN runtime has existed without these critical Web APIs. I think it would be uncontroversial to say that the platform is critically incomplete without them. I know it doesn't belong in Hermes and you get these requests here. But why are the runtime team disregarding the lack of these APIs that exist in every web runtime and native platform?

@tmikov Why can't the atob/btoa, crypto, web streams, etc. C++ libraries from Chromium just be inserted into the React Native core and exposed through JSI?

tmikov commented

Good news, folks! We have decided to add these to Hermes. We should have them soon. We are also working on a way to handle this in general in Static Hermes, by automatically pulling such functions in only when they are needed.

Of course, we realize that after we commit these new functions, it then takes a significant time for them to actually be usable, because the next RN release needs to happen, and then users need to upgrade to it...
We plan to also address this problem very soon by introducing a stable Hermes ABI, which will allow Hermes to be upgraded freely independently of RN.

That is great news, thanks so much for considering this and the quick and efficient handling of this issue!

tmikov commented

Implemented in 13fafde and d2177c3.

Cool, I want to use it. How can I understand in which version it will land and which version used in a react-native project?

tmikov commented

@Bardiamist React Native automatically uses the latest Hermes version when they cut a release, so it will be in the next RN release, I guess 0.74.

Is it possible to see versions? 0.12.0 is the latest version of Hermes? It's strage because of more than year ago.
And how to see Hermes used version in react native?

tmikov commented

@Bardiamist for now Hermes is distributed as part of RN and has no independent distribution or version. You can see versions as branches in the Hermes repo:
Screenshot 2024-01-17 at 7 55 56โ€ฏAM

@tmikov just to verify, as I am having some trouble reading the changelog for React Native, has this been released in version 0.73?

@jonkoops No, this commint not in https://github.com/facebook/hermes/tree/rn/0.73-stable

Also I checked that atob doesn't exist in react-native@0.73.4 just now

Thanks for checking that @Bardiamist. I'll assume this will be landing in version 0.74 then.

How do you check if atob is included ?

0.74 has released by now, would be nice to see if this is settled.
Thanks

One simple way to see whether it is available using the CLI:

echo "print(typeof atob)" | hermes

Now atob has issue reactwg/react-native-releases#287
But should be fix will be cherry picked soon

@TwistedMinda I am using react-native 0.74.1 atob and btoa are now working for me.

Hi there.
I wonder if it's possible to change the implementations of atob() and btoa() to some faster libraries, like simdutf. This is used in Node.js and should be faster than the implementation in 13fafde and d2177c3

@wh201906 do you have a specific case where the performance of atob()/btoa() is unsatisfactory? On what platform?

The Hermes team doesn't have bandwidth to experiment with faster implementations of these. But if there is a PR that measurably improves performance on all supported platforms without dramatically increasing the binary size (which is very important for a mobile platform), we will consider it.