Skip to content

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

Closed
@pauldvu

Description

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",
		});
  1. set up the entry point to the application for the client
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

<style></style> tag in the component itself.

Typically

{/* <style precedence="high">{css}</style>  */}

would work in development mode

Metadata

Assignees

Labels

bugSomething isn't workingtranspilerparser || printer

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions