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

TypeError: Cannot assign to read only property 'atob' of object '[object global]' #5591

Closed
1 task done
jonschlinkert opened this issue Feb 27, 2023 · 4 comments
Closed
1 task done

Comments

@jonschlinkert
Copy link

jonschlinkert commented Feb 27, 2023

What version of Remix are you using?

v1.11.1

Are all your remix dependencies & dev-dependencies using the same version?

  • Yes

Steps to Reproduce

I'm running v1.11.1, but also confirmed that the bug exists in the latest version, v1.13.0, as well.

Honestly I'm not sure how to reproduce. I tried for a bit with the help of @doowb, but we can't narrow down why it's happening on my box and not his. We both have the same setup as far as we know, and we even the same hardware down to the model number, but he doesn't get the error. I also tried using different Node versions from 18-latest, and it happens on all versions I tested.

The bug is definition happening due to remix attempting to assign atob to globals. However, the error is happens when trying to run jest, so perhaps jest is assigning atob as a read-only global? FWIW, it's pretty easy to fix so probably not worth the headache of figuring out which library is causing this, or if it's Node.js internals (but since Node introduced atob in v16, and I'm just now getting this error, it's a bit of a head scratcher).

Here is the error message in case it helps:

image

Expected Behavior

Existing globals should not be overwritten.

Actual Behavior

The bug is caused by the following code in remix, which attempts to overwrite an read-only value on global:

export function installGlobals() {
global.atob = atob;
global.btoa = btoa;
global.Blob = NodeBlob;
global.File = NodeFile;
global.Headers = NodeHeaders as typeof Headers;
global.Request = NodeRequest as typeof Request;
global.Response = NodeResponse as unknown as typeof Response;
global.fetch = nodeFetch as typeof fetch;
global.FormData = NodeFormData;
global.ReadableStream = NodeReadableStream;
global.WritableStream = NodeWritableStream;
global.AbortController = global.AbortController || NodeAbortController;
}

My suggested solution is to use a logical OR assignment (||=) for all of the globals in installGlobals:

My suggested solution of using assignment doesn't work, since it preserves whatever version of atob is presently on global, which is problematic, since remix relies on headers.raw (and the version on globals doesn't have the raw property, which causes the following error: TypeError: nodeResponse.headers.raw is not a function. See #4354 for more details).

Instead of simple assignment, since remix already patches globals with an atob polyfill that works, I suggest using Reflect.defineProperty to enable the read-only properties to be overwritten.

I only updated the properties that I confirmed were causing conflicts, but it wouldn't hurt to update all of them using this signature.

function installGlobals() {
  Reflect.defineProperty(global, 'atob', { value: base64.atob });
  Reflect.defineProperty(global, 'btoa', { value: base64.btoa });
  Reflect.defineProperty(global, 'Blob', { value: webFile.Blob });

  global.File = webFile.File;
  global.Headers = webFetch.Headers;
  global.Request = fetch.Request;
  global.Response = fetch.Response;
  global.fetch = fetch.fetch;
  global.FormData = webFetch.FormData;
  global.ReadableStream = webStream.ReadableStream;
  global.WritableStream = webStream.WritableStream;

  if (!('AbortController' in global)) {
    Reflect.defineProperty(global, 'Blob', { value: abortController.AbortController });
  }
}

I'd be happy to do a PR if you want. Remix is amazing, btw. Thank you!

@jonschlinkert jonschlinkert changed the title TypeError: TypeError: Cannot assign to read only property 'atob' of object '[object global]' Feb 27, 2023
@jonschlinkert
Copy link
Author

jonschlinkert commented Feb 27, 2023

wow, sorry about sending lots of incremental edits there. every time I hit enter it was saving. I'm having keyboard issues and I think one of my keys is locked down. lol it just did it again, and yes, it's the command key.

@github-actions
Copy link
Contributor

This issue has been automatically marked stale because we haven't received a response from the original author in a while 🙈. This automation helps keep the issue tracker clean from issues that are not actionable. Please reach out if you have more information for us or you think this issue shouldn't be closed! 🙂 If you don't do so within 7 days, this issue will be automatically closed.

@github-actions github-actions bot added the needs-response We need a response from the original author about this issue/PR label Apr 28, 2023
@machour machour removed the needs-response We need a response from the original author about this issue/PR label Apr 29, 2023
@brophdawg11 brophdawg11 added this to v2 Aug 3, 2023
@brophdawg11 brophdawg11 self-assigned this Aug 3, 2023
@brophdawg11 brophdawg11 moved this to Backlog in v2 Aug 3, 2023
@brophdawg11
Copy link
Contributor

I think this should be resolved in v2 since Remix will no longer automatically call installGlobals for you (#7009), so you would be free to install only the polyfills needed for your setup.

@brophdawg11 brophdawg11 closed this as not planned Won't fix, can't repro, duplicate, stale Aug 7, 2023
@brophdawg11 brophdawg11 moved this from Backlog to Closed in v2 Aug 7, 2023
@DGuentherTV
Copy link

maybe this will help someone:

for me, this error was only happening in Node 18.19 and 20. Version 18.18 and below are fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Closed
Development

No branches or pull requests

4 participants