oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
73.01k stars 2.66k forks source link

React 19 SSR Fails In Production Mode, But Works In Development #11025

Open pauldvu opened 3 months ago

pauldvu commented 3 months ago

What version of Bun is running?

1.1.8

What platform is your computer?

Darwin 23.4.0 arm64 arm

What steps can reproduce the bug?

  1. Build a react 19 application and statically server the files
  2. Set node env to development mode
  3. Use render to renderToReadableStream to server the application
    
    import { renderToReadableStream } from "react-dom/server";

await renderToReadableStream(element, { signal: request.signal, bootstrapScriptContent: [_INIT_PATH=${JSON.stringify(pathname)}, _ROUTES=${JSON.stringify(routes)}, _PROPS=${JSON.stringify(props)}].filter(Boolean).join(";"), bootstrapModules: [${routes["/hydrate"]}], identifierPrefix: "app", });


4. set up the entry point to the application for the client
```tsx
const root = hydrateRoot(document, <App />);
  1. start the application and visit the page
  2. At this point in development mode everything works as normal

How to recreate the error

  1. Set NODE_ENV to production and follow steps 1-6 and you'll receive
{"name":"Error","message":"Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner}). If you meant to render a collection of children, use an array instead."}

What is the expected behavior?

The expected behavior is that in production mode , the react 19 application would successfully render with bun renderToReadableStream

What do you see instead?

Instead in production the hydration will fail

image

Additional information

One way to get the code working is to moneky patch the following code out

react-dom-server.bun.production.js


    throw Error(
                "Objects are not valid as a React child (found: " +
                    ("[object Object]" === childIndex ? "object with keys {" + Object.keys(node$jscomp$0).join(", ") + "}" : childIndex) +
                    "). If you meant to render a collection of children, use an array instead.",
            );
        }

however by doing so styles will not load correctly when passing a style from the server

export const app = new Elysia({ prefix: "" })
    .get("/home", async (ctx) => {
        const Module = await import("../app/home");
        const css = await generate(ctx.path, config.app.dir);
        const props = {
            meta: {
                title: "",
                description: "",
            },
            style: css,
        };

        const stream = await renderToStream(
            <Shell {...props}>
                <script src="/loader.js" type="module" />
                <Module.default {...props} />
                {/* <style precedence="high">{css}</style>  */}
            </Shell>,
            props,
            ctx.request,
        );
        return new Response(stream, {
            headers: { "Content-Type": "text/html; charset=utf-8" },
        });
    })

I got around this by passing the styles as a prop and using the

tag in the component itself. Typically ``` {/* */} ``` would work in development mode
paperdave commented 3 months ago

react renamed their symbol for elements, https://github.com/facebook/react/pull/28813

bun's own transform for JSX does inlining in production:

image

it seems for react 19 we will need to update or disable this

pauldvu commented 3 months ago

Ah that makes more sense , so this change was causing Bun not to tag element's correctly?

Thanks paperdave!

paulzakin commented 1 month ago

Hello, is there any update on this? I can replicate it on v1.1.21. Thanks!

Jarred-Sumner commented 1 month ago

I thought we had disabled the inlining but I guess we didn’t

paulzakin commented 1 month ago

I do not think so, but I could be wrong!

paulzakin commented 1 month ago

Is there anything I can do to help this along - digging into Bun internals might be a bit tricky for me but I'm willing to give it a shot!

Arctomachine commented 1 month ago

I encounter following error in nextjs. Same conditions, works in dev and fails in prod. Is it relevant here? Component with strange name is actually called ClientsFilter error: Could not find the module "...\src\app\(main)\base\\u0421lientsFilter.tsx#default" in the React Client Manifest. This is probably a bug in the React Server Components bundler.

paulzakin commented 2 weeks ago

Hello! Not sure if you have time to take a look at this @paperdave?