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

Framework v1.13 building a broken version of React 19 #1866

Closed
sbarre opened this issue Dec 5, 2024 · 8 comments · Fixed by #1872
Closed

Framework v1.13 building a broken version of React 19 #1866

sbarre opened this issue Dec 5, 2024 · 8 comments · Fixed by #1872
Labels
bug Something isn’t working

Comments

@sbarre
Copy link

sbarre commented Dec 5, 2024

I'm opening an issue because I think I've found a bug while debugging an issue with my own work on the discussion forum.

Here are my steps to reproduce:

I installed a fresh version of Framework 1.13 using npx @observablehq/framework@latest create.

I created a super simple JSX component in components/Button.jsx:

import * as React from "npm:react";

export default function Button() {
  return (
    <button>Test</button>
  )
}

I import and add this button to the existing index.md file:

import Button from './components/Button.js';

display(<Button />)

The above display() call is in a fenced jsx block, sorry I don't know how to display that properly in here.

Anyways, then I run npm run dev and load the homepage, and the button does not appear.

I see this error in the browser console:

Uncaught (in promise) TypeError: createRoot is not a function at client.js:211:19

And sure enough in the client.js bundle it's importing the _npm/react-dom@19.0.0 library but that file does not export a method called createRoot..

Now, if I look in the .observablehq/cache/_npm folder I see that the react-dom@19.0.0 folder contains one file: _esm.js and that file is only 4,492 bytes.

The same file in a previous Framework v11.1 project, for react-dom@18.3.1 is around 192k ... Plus there are other files in that folder including a package.json etc.. Those other files are not present here in v1.13

Similarly the _esm.js file in the cache/_npm/react@19.0.0 folder seems suspiciously small as well (11k)..

This is all from a fresh vanilla install with no other changes except creating a basic JSX component to test.

I'm on a Mac (Sequoia 15.1.1) and I'm running Node 20.11.1

@sbarre sbarre added the bug Something isn’t working label Dec 5, 2024
@sbarre
Copy link
Author

sbarre commented Dec 5, 2024

To rule out machine-specific issues, I also performed the same steps above in Ubuntu on a different computer and got the same results.

@mbostock
Copy link
Member

mbostock commented Dec 5, 2024

React has had a broken (incompatible with ES modules) distribution for quite some time facebook/react#11503, so we had to do a clunky workaround to get esbuild to convert it into a functional ES module:

framework/src/node.ts

Lines 75 to 87 in 8efdcf4

/**
* React (and its dependencies) are distributed as CommonJS modules, and worse,
* they’re incompatible with cjs-module-lexer; so when we try to import them as
* ES modules we only see a default export. We fix this by creating a shim
* module that exports everything that is visible to require. I hope the React
* team distributes ES modules soon…
*
* https://github.com/facebook/react/issues/11503
*/
function isBadCommonJs(specifier: string): boolean {
const {name} = parseNpmSpecifier(specifier);
return name === "react" || name === "react-dom" || name === "react-is" || name === "scheduler";
}

It’s possible that they’ve changed something that will require us to do another workaround to get React 19 to work. It’s not a bug in Framework per se, but we’re willing to make changes to get React working again.

@sbarre
Copy link
Author

sbarre commented Dec 5, 2024

For what it's worth I tried pinning @18 in my test and I see the same issue, so it might be all builds?

Anything I can do to debug this further?

@mbostock
Copy link
Member

mbostock commented Dec 5, 2024

I don’t think pinning React using import * as React from "npm:react@18" will work because there’s an implicit unpinned import that is generated when you use JSX. You might be able to get it to work by clearing your npm cache and then creating the appropriate folders, something like:

rm -rvf src/.observablehq/cache/_npm
mkdir -p src/.observablehq/cache/_npm/react-dom@18.3.1
mkdir -p src/.observablehq/cache/_npm/react@18.3.1

That seems to workaround the problem in my testing. I’ll try to debug what’s broken in React 19 when I have time.

@sbarre
Copy link
Author

sbarre commented Dec 6, 2024

Thanks for that workaround! I can confirm that it works for me as well.

I inserted some extra commands in my Dockerfile to create those paths after git checkout and npm install and before npm run build.

@caseyg
Copy link

caseyg commented Dec 6, 2024

Also experiencing this issue, and the workaround worked for me as well. Thank you!

@ifree
Copy link

ifree commented Dec 7, 2024

Unfortunately I'm unable to get it working with the workaround above, and the document page of React support is broken as well, is there a way to blacklist React 19 or pin to the previous version?

Fil added a commit that referenced this issue Dec 7, 2024
@Fil Fil mentioned this issue Dec 7, 2024
@caseyg
Copy link

caseyg commented Dec 10, 2024

Thank you for the quick fix! Is it possible to push a patched minor version to NPM so that CI builds which pull in the @observable/framework package can use this? Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn’t working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants