some ssr changes

This commit is contained in:
Alistair Smith
2025-09-08 14:40:46 -07:00
parent cc3e4d8319
commit 6eee2eeaf6
4 changed files with 28 additions and 16 deletions

View File

@@ -35,7 +35,7 @@ interface Config {
* Removed using --drop=ASSERT in releases.
*/
declare namespace DEBUG {
declare function ASSERT(condition: any, message?: string): asserts condition;
function ASSERT(condition: unknown, message?: string): asserts condition;
}
/** All modules for the initial bundle. */
@@ -45,13 +45,13 @@ declare type UnloadedESM = [
deps: EncodedDependencyArray,
exportKeys: string[],
starImports: Id[],
load: (mod: import("./hmr-module").HMRModule) => Promise<void>,
load: (mod: import("../../src/bake/hmr-module.ts").HMRModule) => Promise<void>,
isAsync: boolean,
];
declare type EncodedDependencyArray = (string | number)[];
declare type UnloadedCommonJS = (
hmr: import("./hmr-module").HMRModule,
module: import("./hmr-module").HMRModule["cjs"],
hmr: import("../../src/bake/hmr-module.ts").HMRModule,
module: import("../../src/bake/hmr-module.ts").HMRModule["cjs"],
exports: unknown,
) => unknown;
declare type CommonJSModule = {
@@ -88,10 +88,10 @@ declare module "react-server-dom-bun/client.browser" {
}
declare module "react-server-dom-bun/client.node.unbundled.js" {
import type { ReactClientManifest } from "bun:app/server";
import type { ServerManifest } from "bun:app/server";
import type { Readable } from "node:stream";
export interface Manifest {
moduleMap: ReactClientManifest;
moduleMap: ServerManifest;
moduleLoading?: ModuleLoading;
}
export interface ModuleLoading {
@@ -107,7 +107,7 @@ declare module "react-server-dom-bun/client.node.unbundled.js" {
}
declare module "react-server-dom-bun/server.node.unbundled.js" {
import type { ReactServerManifest } from "bun:app/server";
import type { ServerManifest } from "bun:app/server";
import type { ReactElement } from "react";
export interface PipeableStream<T> {
@@ -118,7 +118,7 @@ declare module "react-server-dom-bun/server.node.unbundled.js" {
export function renderToPipeableStream<T = any>(
model: ReactElement,
webpackMap: ReactServerManifest,
webpackMap: ServerManifest,
options?: RenderToPipeableStreamOptions,
): PipeableStream<T>;

View File

@@ -5,6 +5,7 @@ import { ssrManifest } from "bun:app/server";
import { EventEmitter } from "node:events";
import type { Readable } from "node:stream";
import * as React from "react";
import type { RenderToPipeableStreamOptions } from "react-dom/server";
import { renderToPipeableStream } from "react-dom/server.node";
import { createFromNodeStream, type Manifest } from "react-server-dom-bun/client.node.unbundled.js";
import type { MiniAbortSignal } from "./server.tsx";
@@ -46,7 +47,7 @@ export function renderToHtml(
type: "direct",
pull(controller) {
// `createFromNodeStream` turns the RSC payload into a React component.
const promise = createFromNodeStream(rscPayload, {
const promise: Promise<React.ReactNode> = createFromNodeStream(rscPayload, {
// React takes in a manifest mapping client-side assets
// to the imports needed for server-side rendering.
moduleMap: ssrManifest,
@@ -65,7 +66,7 @@ export function renderToHtml(
// `renderToPipeableStream` is what actually generates HTML.
// Here is where React is told what script tags to inject.
let pipe: (stream: any) => void;
let pipe: (stream: NodeJS.WritableStream) => void;
({ pipe, abort } = renderToPipeableStream(<Root />, {
bootstrapModules,
onError(error) {
@@ -106,16 +107,21 @@ export function renderToHtml(
// Static builds can not stream suspense boundaries as they finish, but instead
// produce a single HTML blob. The approach is otherwise similar to `renderToHtml`.
export function renderToStaticHtml(rscPayload: Readable, bootstrapModules: readonly string[]): Promise<Blob> {
export function renderToStaticHtml(
rscPayload: Readable,
bootstrapModules: NonNullable<RenderToPipeableStreamOptions["bootstrapModules"]>,
): Promise<Blob> {
const stream = new StaticRscInjectionStream(rscPayload);
const promise = createFromNodeStream(rscPayload, createFromNodeStreamOptions);
const Root = () => React.use(promise);
const promise: Promise<React.ReactNode> = createFromNodeStream(rscPayload, createFromNodeStreamOptions);
const Root: React.JSXElementConstructor<{}> = () => React.use(promise);
const { pipe } = renderToPipeableStream(<Root />, {
bootstrapModules,
// Only begin flowing HTML once all of it is ready. This tells React
// to not emit the flight chunks, just the entire HTML.
onAllReady: () => pipe(stream),
});
return stream.result;
}
@@ -139,7 +145,7 @@ const enum RscState {
Done,
}
class RscInjectionStream extends EventEmitter {
class RscInjectionStream extends EventEmitter implements NodeJS.WritableStream {
controller: ReadableStreamDirectController;
html: HtmlState = HtmlState.Flowing;

View File

@@ -9,6 +9,12 @@
"jsx": "react-jsx",
"types": ["react/experimental"]
},
"include": ["**/*.ts", "**/*.tsx", "../runtime.js", "../runtime.bun.js"],
"include": [
"**/*.ts",
"**/*.tsx",
"../runtime.js",
"../runtime.bun.js",
"../../packages/bun-framework-react/bake.private.d.ts"
],
"references": [{ "path": "../../packages/bun-types" }]
}

View File

@@ -7,7 +7,7 @@
"bindgen": ["./codegen/bindgen-lib.ts"]
}
},
"include": ["**/*.ts", "**/*.tsx"],
"include": ["**/*.ts", "**/*.tsx", "../packages/bun-framework-react/bake.private.d.ts"],
// separate projects have extra settings that only apply in those scopes
"exclude": ["js", "bake"]
}