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

fix(cloudflare): use React edge renderer for compatibility with React 19 #436

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

mlafeldt
Copy link

@mlafeldt mlafeldt commented Nov 6, 2024

React 19 requires MessageChannel from node:worker_threads, which isn't available in Cloudflare's workerd runtime. Switch to React's edge-optimized server renderer to avoid the MessageChannel dependency.

More background

Trying to use useActionState from React 19 as described here currently results in Uncaught ReferenceError: MessageChannel is not defined when workerd is involved.

❯ rg  --no-ignore 'new MessageChannel' node_modules/react-dom/
node_modules/react-dom/cjs/react-dom-server.browser.development.js
7095:      channel = new MessageChannel(),

node_modules/react-dom/cjs/react-dom-server.browser.production.js
126:var channel = new MessageChannel(),

Rather than polyfilling MessageChannel and its dependencies, e.g. via unenv, I found that switching the renderer is much easier.

The edge renderer probably makes more sense at the edge anyway (😄), though I don't know if the browser variant was initially chosen for a specific reason.

React 19 requires MessageChannel from node:worker_threads, which isn't
available in Cloudflare's workerd runtime. Switch to React's
edge-optimized server renderer to avoid MessageChannel dependency.
Copy link

changeset-bot bot commented Nov 6, 2024

🦋 Changeset detected

Latest commit: 86d1ac5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@astrojs/cloudflare Minor
@test/astro-cloudflare-astro-dev-platform Patch
@test/astro-cloudflare-astro-env Patch
@test/astro-cloudflare-compile-image-service Patch
@test/astro-cloudflare-external-image-service Patch
@test/astro-cloudflare-wasm Patch
@test/astro-cloudflare-no-output Patch
@test/astro-cloudflare-routes-json Patch
@test/astro-cloudflare-with-solid-js Patch
@test/astro-cloudflare-wrangler-preview-platform Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mlafeldt mlafeldt changed the title fix(cloudflare): use React 19's edge renderer for workers compatibility fix(cloudflare): use React edge renderer for compatibility with React 19 Nov 6, 2024
@mlafeldt
Copy link
Author

Can I interest @alexanderniebuhr or @bholmesdev in a review?

@bluwy
Copy link
Member

bluwy commented Nov 13, 2024

This breaks for React 18?

I think we could probably simply remove the alias altogether, it has this exports:

  "./server": {
      "deno": "./server.browser.js",
      "worker": "./server.browser.js",
      "browser": "./server.browser.js",
      "default": "./server.node.js"
   },

And the cloudflare vite config will respect worker or browser conditions already. So it should load the right entrypoint.

@mlafeldt
Copy link
Author

Removing the alias doesn't work, unfortunately. Here's what will happen.

React 18:

✘ [ERROR] TypeError: Cannot read properties of null (reading 'useState')

      at react_production_min.useState
  (file:///Users/mathias/devel/myproject/.wrangler/tmp/pages-PNPhoG/chunks/_@astro-renderers_BO7YS_f8.mjs:258:20)
      at null.<anonymous>
  (file:///Users/mathias/devel/myproject/.wrangler/tmp/pages-PNPhoG/chunks/App_4EsssyrD.mjs:6931:394)
      at renderWithHooks
  (file:///Users/mathias/devel/myproject/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5658:16)
      at renderForwardRef
  (file:///Users/mathias/devel/myproject/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5853:18)
      at renderElement

React 19:

✘ [ERROR] TypeError: Cannot read properties of null (reading 'useState')

      at react_production.useState
  (file:///Users/mathias/devel/myproject/.wrangler/tmp/pages-NLf5Nx/chunks/_@astro-renderers_sWJxeN6r.mjs:423:33)
      at Component
  (file:///Users/mathias/devel/myproject/.wrangler/tmp/pages-NLf5Nx/chunks/App_Cvyax1x8.mjs:430:386)
      at renderWithHooks
  (file:///Users/mathias/devel/myproject/node_modules/react-dom/cjs/react-dom-server.edge.development.js:4545:19)
      at renderElement
...

The correct files are loaded even without the alias (as you suggested), but something else breaks. I guess that's why the alias was added in the first place.

Also, you're right that my change actually breaks React 18. 😕

12:23:34 [ERROR] [vite] x Build failed in 48ms
[commonjs--resolver] Missing "./server.edge" specifier in "react-dom" package
  Location:
    /Users/mathias/devel/myproject/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:46041:25
  Stack trace:
...

We need a better fix.

Copy link
Member

@alexanderniebuhr alexanderniebuhr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking, since this doesn't work for all versions, to avoid accidental merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants