rwsdk
Version:
Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime
50 lines (49 loc) • 2.16 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { use } from "react";
import { renderToReadableStream } from "react-dom/server.edge";
export const renderRscThenableToHtmlStream = async ({ thenable, Document, requestInfo, shouldSSR, onError, }) => {
const Component = () => {
const node = use(thenable).node;
// todo(justinvdm, 18 Jun 2025): We can build on this later to allow users
// surface context. e.g:
// * we assign `user: requestInfo.clientCtx` here
// * user populates requestInfo.clientCtx on worker side
// * user can import a read only `import { clientCtx } from "rwsdk/client"`
// on client side
const clientContext = {
rw: {
ssr: shouldSSR,
},
};
return (_jsxs(Document, { ...requestInfo, children: [_jsx("script", { nonce: requestInfo.rw.nonce, dangerouslySetInnerHTML: {
__html: `globalThis.__RWSDK_CONTEXT = ${JSON.stringify(clientContext)}`,
} }), _jsx("div", { id: "hydrate-root", children: node })] }));
};
return await renderToReadableStream(_jsx(Component, {}), {
nonce: requestInfo.rw.nonce,
onError(error, { componentStack }) {
try {
if (!error) {
error = new Error(`A falsy value was thrown during rendering: ${String(error)}.`);
}
const message = error
? (error.stack ?? error.message ?? error)
: error;
const wrappedMessage = `${message}\n\nComponent stack:${componentStack}`;
if (error instanceof Error) {
const wrappedError = new Error(wrappedMessage);
wrappedError.stack = error.stack;
error = wrappedError;
}
else {
error = new Error(wrappedMessage);
error.stack = componentStack;
}
onError(error);
}
catch {
onError(error);
}
},
});
};