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

Possible race condition leading to "TypeError: Cannot read property 'context' of undefined" #3220

Closed
PaulBlanche opened this issue Jul 7, 2021 · 6 comments
Labels

Comments

@PaulBlanche
Copy link

Describe the bug
There seems to be a race condition related to useContext with Suspense and preact-ssr-prepass. In my application i use usePromise (from react-promise-suspense) to await on certain computation server-side.

Sometimes (but not systematically) the ssr prepass fails with this error :

error TypeError: Cannot read property 'context' of undefined
    at Object.exports.useContext (.../frugal/node_modules/preact/hooks/src/index.js:239:36)
    at Object.useAssertCreator (.../frugal/packages/preact-render/src/asset.ts:8:32)
    at Object.useImage (.../frugal/packages/preact-render/src/useImage.ts:8:26)
    at d.call (.../frugal/packages/ulule/src/pages/project/descriptor.tsx:50:20)
    at t (.../frugal/node_modules/preact-ssr-prepass/src/index.js:82:22)

If i remove the longest computations (the ones that would need to be awaited on the most during the ssr prepass), the error disappears. If i replace the computation with a simple timeout, the error still happens. That's why i suspect a race condition. I don't know if this is an issue with preact or preact-ssr-prepass.

To Reproduce
I could not reproduce this issue with a simplified setup on CodeSandbox. I could share my codebase if needed but there is a lot of moving parts.

Expected behavior
When a value is passed to a context.Provider, a useContext should return this value even in the context of an ssr prepass.

@PaulBlanche
Copy link
Author

I managed to reproduce the bug here : https://github.com/PaulBlanche/preact-bug-reproduction
Strangely, the same code in codesandbox runs without errors.

@PaulBlanche
Copy link
Author

Does anybody have some pointer for where i should look to try and understand the problem ?

@dancras
Copy link

dancras commented Feb 11, 2022

I think I've just encountered this same error in a different context. I've managed to narrow it down to a very simple failing example: https://github.com/dancras/preact-bug

  • Error only occurs with useContext. Using Context.Consumer works as expected
  • Error occurs in vitest but not jest so likely some race condition as mentioned above
TypeError [Error]: Cannot read properties of null (reading 'context')
    at Proxy.exports.useContext (/app/node_modules/preact/hooks/dist/hooks.js:1:2437)
    at d.ExampleConsumer [as constructor] (/app/app/src/preact-bug.test.jsx:38:41)
    at d.M [as render] (/app/node_modules/preact/dist/preact.js:1:7837)
    at j (file:///app/node_modules/preact/dist/preact.mjs:1:5752)
    at file:///app/node_modules/preact/dist/preact.mjs:1:1494
    at Array.some (<anonymous>)
    at g (file:///app/node_modules/preact/dist/preact.mjs:1:1392)

@marvinhagemeister
Copy link
Member

@dancras Looking at that output it seems like vitest is including two different versions of Preact. Hooks require by design a singleton and multiple Preact versions don't know about each other. That's why the context value is missing and the error only pops up with hooks. Here in particular it includes preact.mjs (ESM Module) and preact.js (CommonJS Module).

Reported it upstream at vitest-dev/vitest#747

@JoviDeCroock
Copy link
Member

Closing as this should be fixed upstream by preact-testing-library adding the ESM build

@rhengles
Copy link

rhengles commented Mar 8, 2023

It sounds like my React-router problem might be related to this!

preactjs/preset-vite#73

Link to CodeSandbox

For me the error always happens.

As I commented on the issue above, when I use react-router 5.x the app works, including with SSR. But it fails the moment I try to get a hook from the router, be it useLocation() or useHistory().

I verified and, in fact, the error is happening on the CJS hooks file. Now I have to search how to solve this issue...

Edit: I think I found the problem, here is the solution - remix-run/react-router#10175

rhengles added a commit to arijs/react-router that referenced this issue Mar 8, 2023
This fixes an issue with Preact + Vite + SSR. Without the export maps, Vite SSR and Node.js
gets confused and loads both the ESM and CJS versions of Preact. This breaks the hooks system
of Preact as discussed here[1] and here[2].

During SSR, Vite starts as ESM and loads my modules (and Preact). But when I load React-Router,
as it does not have the exports map, Node loads the CJS version, which loads the CJS version of
Preact. Then Preact breaks because it can't find the hooks registered in the ESM code.

Also, in the version of Node that I tested, v16.14.0, Node printed the warning below, so I also
changed the extension of the ES module for node from ".js" to ".mjs".

(node:5753) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

[1] preactjs/preact#3220 (comment)
[2] vitest-dev/vitest#747 (comment)
rhengles added a commit to arijs/react-router that referenced this issue Mar 9, 2023
This fixes an issue with Preact + Vite + SSR. Without the export maps, Vite SSR and Node.js
gets confused and loads both the ESM and CJS versions of Preact. This breaks the hooks system
of Preact as discussed here[1] and here[2].

During SSR, Vite starts as ESM and loads my modules (and Preact). But when I load React-Router,
as it does not have the exports map, Node loads the CJS version, which loads the CJS version of
Preact. Then Preact breaks because it can't find the hooks registered in the ESM code.

Also, in the version of Node that I tested, v16.14.0, Node printed the warning below, so I also
changed the extension of the ES module for node from ".js" to ".mjs".

(node:5753) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

[1] preactjs/preact#3220 (comment)
[2] vitest-dev/vitest#747 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants