Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

atob and btoa should not be marked as legacy #57145

Closed
chee opened this issue Feb 20, 2025 · 13 comments
Closed

atob and btoa should not be marked as legacy #57145

chee opened this issue Feb 20, 2025 · 13 comments
Labels
doc Issues and PRs related to the documentations. web-standards Issues and PRs related to Web APIs

Comments

@chee
Copy link

chee commented Feb 20, 2025

Affected URL(s)

https://nodejs.org/docs/latest/api/globals.html#atobdata https://nodejs.org/docs/latest/api/buffer.html#bufferatobdata

Description of the problem

hey!

i notice that atob and btoa are marked as Legacy, which states "no longer actively maintained, and other alternatives are available".

some notes on that:

  1. they do seem to still be maintained:
  2. the alternative listed is not an equivalent. atob and btoa are optimized at the C++ level, and do not create an in-memory Buffer in javascript context that then has to be garbage collected (needless, for instance, when ⁠ JSON.parse(atob(b64)))

having these marked as legacy also seems to go against the very good direction node has taken recently of compatibility with web apis like the webstreams api

i think it would be great if these were marked Stability 2! what do you think?

@chee chee added the doc Issues and PRs related to the documentations. label Feb 20, 2025
@panva
Copy link
Member

panva commented Feb 20, 2025

Even if their legacy status has been somewhat weakened by the fact that they were optimized it stands to say that they were not optimized as much as other methods and their proper replacement being https://github.com/tc39/proposal-arraybuffer-base64 is going to be generally available soon(ish)12.

I don't think we need to be doing any changes here. If anything I'd say we update the new recommendation to be the new Uint8Array methods as soon as they become available in V83 (and soon thereafter in node).

Footnotes

  1. https://caniuse.com/mdn-javascript_builtins_uint8array_frombase64

  2. https://caniuse.com/mdn-javascript_builtins_uint8array_tobase64

  3. https://issues.chromium.org/issues/42204568

@panva panva added the web-standards Issues and PRs related to Web APIs label Feb 20, 2025
@chee
Copy link
Author

chee commented Feb 20, 2025

I love the new Uint8Array methods! i've been using them in Firefox, and they're great. Though I still don't think they're a great replacement for every usecase:

this is making a lot more Stuff:

JSON.parse(new TextDecoder().decode(Uint8Array.fromBase64("eyJoZWxsbyI6IndvcmxkIn0=")))

than this:

JSON.parse(atob("eyJoZWxsbyI6IndvcmxkIn0="))

and that can really matter in memory-sensitive applications!

atob and btoa are stable and fantastic at their job. they're also stable in the web platform and deno. i don't know if that matters so much, but i think many of us really appreciate the cross-runtime compatibility.

@targos
Copy link
Member

targos commented Feb 20, 2025

But that's not the same! atob and btoa don't work with UTF-8 encoding. This kind of confusion is one of the main reasons that we discourage their use.

@targos
Copy link
Member

targos commented Feb 20, 2025

Example to illustrate:

> Buffer.from(JSON.stringify({check: ''})).toString('base64')
'eyJjaGVjayI6IuKckyJ9'

> btoa(JSON.stringify({check: ''}))
Uncaught:
DOMException [InvalidCharacterError]: Invalid character
    at btoa (node:buffer:1288:11)

@JakeChampion
Copy link

But that's not the same! atob and btoa don't work with UTF-8 encoding. This kind of confusion is one of the main reasons that we discourage their use.

Correct, and this fact, that they are not the same was mentioned in the original comment:

  1. the alternative listed is not an equivalent.

Because they are not the same, we can't suggest that someone use the suggested alternative for all use-cases, since those differences might be important for them.

It seems like what we likely want to do here is not mark this as legacy, and also direct to newer APIs for specific scenarios, which is what MDN has chosen to do. This would also align with Deno and with Bun, both of whom do not mark atob btoa as legacy.

Image

@panva
Copy link
Member

panva commented Feb 20, 2025

A method marked as legacy has no functional or future deprecation related consequences tho. And it is exactly that, legacy. It's part of the HTML standard, not ECMAScript. It doesn't work with utf-8 inputs and it has considerable drawbacks when you actually want to use it with large inputs and eventually move those in/out of Uint8Array.

Because they are not the same, we can't suggest that someone use the suggested alternative for all use-cases, since those differences might be important for them.

They are the same in that they're compatible in terms of what they accept, and they actually accept more, which is not to the user's detriment.

@jasnell
Copy link
Member

jasnell commented Feb 20, 2025

These were marked as Legacy for the simple reason that we want to subtly discourage users from reaching for them while we have better options readily available. When they were proposed to be added there was some disagreement about whether they should be and adding them with the legacy flag was the compromise that was reached. Being marked as legacy means it won't be deprecated or removed but that it's not the thing we recommend that you use. In every other way they are perfectly fine to make use of.

@joyeecheung
Copy link
Member

joyeecheung commented Feb 20, 2025

having these marked as legacy also seems to go against the very good direction node has taken recently of compatibility with web apis like the webstreams api

The status of being legacy doesn't really have much to do with compatibility - the fact that they were implemented as legacy features from the beginning is already a choice made with consideration of compatibility. If we are indeed going against this trend then this API would be added in the first place. As @jasnell mentioned the legacy status in the docs is just a way of discouraging usage when there are better alternatives (in this case, the typed array methods or TextDecoder etc. that are capable of handling non-ASCII characters properly).

It seems like a better way forward is to document why it's considered legacy and what's the better alternative instead. We can add a "good first issue" label to see if someone is interested in sending a documentation PR if there's agreed.

@joyeecheung
Copy link
Member

joyeecheung commented Feb 20, 2025

Also, I think the fact that the OP states needless, for instance, when ⁠ JSON.parse(atob(b64)) is somewhat concerning already, because it seems to already been giving people an idea that you don't need to worry about what happens when e.g. b64 = Buffer.from('{"a": "测试"}').toString('base64')

@JakeChampion
Copy link

I'm just not sure why these needed to be marked 'legacy' within NodeJS when it seems that no other runtime has marked them as legacy, including sites such as MDN. The messaging to the end-user is mixed. I understand wanting to encourage other alternative APIs, can that be achieved whilst also not tagging these functions as 'legacy'?

Also, I think the fact that the OP states needless, for instance, when ⁠ JSON.parse(atob(b64)) is somewhat concerning already, because it seems to already been giving people an idea that you don't need to worry about what happens when e.g. b64 = Buffer.from('{"a": "测试"}').toString('base64')

I would assume the OP shortened the example and was likely using input which is always latin-1 such as HTTP Field Values:

var h = new Headers
h.set('hello', 'world')
h.set('a', 'à') 

JSON.parse(
  atob(
    btoa(
      JSON.stringify(
        Object.fromEntries(
          h.entries()
        )
      )
    )
  )
) // { a: "à", hello: "world" }

@chee
Copy link
Author

chee commented Feb 20, 2025

A method marked as legacy has no functional or future deprecation related consequences tho

Being marked as legacy means it won't be deprecated or removed

This is great news! the documentation for "Stability 3" is slightly less firm on that point, stating "unlikely to be removed" and "unmaintained". If it were to say "will continue to be maintained, will not be deprecated or removed, but is discouraged" in the docs I probably wouldn't have come here.

I'll see if I can get manager sign-off on the use of legacy atob to decode serialized latin-1 base 64 strings off the back of the commitments in this thread.

@chee chee closed this as completed Feb 20, 2025
@jasnell
Copy link
Member

jasnell commented Feb 21, 2025

The documentation was written to give us long term wiggle room Just In Case but I cannot foresee any circumstance where Node.js would remove atob/btoa or not fix any bugs that may be found, so I'd say you're safe.

@chee
Copy link
Author

chee commented Feb 21, 2025

@jasnell thank you <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. web-standards Issues and PRs related to Web APIs
Projects
None yet
Development

No branches or pull requests

6 participants