Skip to content

test(rsc): migrate Vite fixtures to @hiogawa/vite-rsc #13819

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

Merged
merged 6 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions integration/helpers/rsc-vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
node_modules
1 change: 0 additions & 1 deletion integration/helpers/rsc-vite/.wrangler/deploy/config.json

This file was deleted.

16 changes: 0 additions & 16 deletions integration/helpers/rsc-vite/framework/references.browser.ts

This file was deleted.

5 changes: 0 additions & 5 deletions integration/helpers/rsc-vite/framework/references.rsc.ts

This file was deleted.

4 changes: 0 additions & 4 deletions integration/helpers/rsc-vite/framework/references.ssr.ts

This file was deleted.

19 changes: 0 additions & 19 deletions integration/helpers/rsc-vite/framework/server.ts

This file was deleted.

21 changes: 8 additions & 13 deletions integration/helpers/rsc-vite/package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
{
"name": "@playground/rsc-vite",
"name": "integration-rsc-vite",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "node server.js",
"build": "vite build --app",
"start": "cross-env NODE_ENV=production node server.js",
"typecheck": "tsc"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@cloudflare/vite-plugin": "0.1.7",
"@cloudflare/workers-types": "^4.20250224.0",
"@jacob-ebey/vite-react-server-dom": "0.0.12",
"@hiogawa/vite-rsc": "0.4.1",
"@types/express": "^5.0.0",
"@types/node": "^22.13.1",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.5.2",
"typescript": "^5.1.6",
"vite": "^6.2.0",
"vite-tsconfig-paths": "^5.1.4",
"wrangler": "^3.111.0"
"vite": "^6.2.0"
},
"dependencies": {
"@jacob-ebey/react-server-dom-vite": "19.0.0-experimental.14",
"@mjackson/node-fetch-server": "0.6.1",
"compression": "^1.8.0",
"express": "^4.21.2",
Expand Down
15 changes: 2 additions & 13 deletions integration/helpers/rsc-vite/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { createRequestListener } from "@mjackson/node-fetch-server";
import compression from "compression";
import express from "express";

import ssr from "./dist/ssr/entry.ssr.js";
import server from "./dist/server/entry.rsc.js";
import rscRequestHandler from "./dist/rsc/index.js";

const app = express();

Expand All @@ -16,17 +15,7 @@ app.get("/.well-known/appspecific/com.chrome.devtools.json", (req, res) => {
res.end();
});

app.use(
createRequestListener((request) => {
return ssr.fetch(request, {
SERVER: {
fetch(request) {
return server.fetch(request);
},
},
});
})
);
app.use(createRequestListener(rscRequestHandler));

const { values } = parseArgs({
options: { p: { type: "string", default: "3000" } },
Expand Down
49 changes: 23 additions & 26 deletions integration/helpers/rsc-vite/src/entry.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,34 @@ import { hydrateRoot } from "react-dom/client";
import {
createFromReadableStream,
encodeReply,
// @ts-expect-error - no types
} from "@jacob-ebey/react-server-dom-vite/client";
// @ts-expect-error - no types yet
import { manifest } from "virtual:react-manifest";

setServerCallback,
} from "@hiogawa/vite-rsc/browser";
import type { unstable_DecodeServerResponseFunction as DecodeServerResponseFunction } from "react-router";
import {
type unstable_DecodeServerResponseFunction as DecodeServerResponseFunction,
type unstable_EncodeActionFunction as EncodeActionFunction,
unstable_createCallServer as createCallServer,
unstable_getServerStream as getServerStream,
unstable_RSCHydratedRouter as RSCHydratedRouter,
} from "react-router";
import { type unstable_ServerPayload as ServerPayload } from "react-router/rsc";

const encodeAction: EncodeActionFunction = (args: unknown[]) =>
encodeReply(args);
import type { unstable_ServerPayload as ServerPayload } from "react-router/rsc";

const decode: DecodeServerResponseFunction = (body) =>
createFromReadableStream(body, manifest, { callServer });
const decode: DecodeServerResponseFunction = (
body: ReadableStream<Uint8Array>
) => createFromReadableStream(body);

const callServer = createCallServer({ decode, encodeAction });

createFromReadableStream(getServerStream(), manifest, { callServer }).then(
(payload: ServerPayload) => {
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RSCHydratedRouter decode={decode} payload={payload} />
</StrictMode>
);
});
}
setServerCallback(
createCallServer({
decode,
encodeAction: (args) => encodeReply(args),
})
);

createFromReadableStream<ServerPayload>(getServerStream()).then((payload) => {
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RSCHydratedRouter decode={decode} payload={payload as any} />
</StrictMode>
);
});
});
58 changes: 33 additions & 25 deletions integration/helpers/rsc-vite/src/entry.rsc.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
/// <reference types="@cloudflare/workers-types" />
import {
decodeAction,
decodeReply,
loadServerAction,
renderToReadableStream,
} from "@hiogawa/vite-rsc/rsc";
import {
type unstable_DecodeCallServerFunction as DecodeCallServerFunction,
type unstable_DecodeFormActionFunction as DecodeFormActionFunction,
unstable_matchRSCServerRequest as matchRSCServerRequest,
} from "react-router/rsc";
// @ts-expect-error - no types yet
import { manifest } from "virtual:react-manifest";

import { decodeReply, renderToReadableStream } from "../framework/server";
import { routes } from "./routes";

const decodeCallServer: DecodeCallServerFunction = async (actionId, reply) => {
const args = await decodeReply(reply);
const reference = manifest.resolveServerReference(actionId);
await reference.preload();
const action = reference.get() as (...args: unknown[]) => Promise<unknown>;
const action = await loadServerAction(actionId);
return action.bind(null, ...args);
};

export default {
fetch(request, env) {
return matchRSCServerRequest({
decodeCallServer,
request,
routes,
generateResponse(match) {
if (match instanceof Response) {
return match;
}
const decodeFormAction: DecodeFormActionFunction = async (formData) => {
return await decodeAction(formData);
};

export async function callServer(request: Request) {
return await matchRSCServerRequest({
decodeCallServer,
decodeFormAction,
request,
routes,
generateResponse(match) {
return new Response(renderToReadableStream(match.payload), {
status: match.statusCode,
headers: match.headers,
});
},
});
}

return new Response(renderToReadableStream(match.payload), {
status: match.statusCode,
headers: match.headers,
});
},
});
},
} satisfies ExportedHandler;
export default async function handler(request: Request) {
const ssr = await import.meta.viteRsc.loadSsrModule<
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
typeof import("./entry.ssr")
>("index");
return ssr.default(request, callServer);
}
61 changes: 23 additions & 38 deletions integration/helpers/rsc-vite/src/entry.ssr.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,28 @@
/// <reference types="@cloudflare/workers-types" />

// @ts-expect-error
import RSD from "@jacob-ebey/react-server-dom-vite/client";
import bootstrapScriptContent from "virtual:vite-rsc/bootstrap-script-content";
import { createFromReadableStream } from "@hiogawa/vite-rsc/ssr";
// @ts-expect-error
import RDS from "react-dom/server.edge";
// @ts-expect-error
import { bootstrapModules, manifest } from "virtual:react-manifest";

import * as ReactDomServer from "react-dom/server.edge";
import {
unstable_routeRSCServerRequest as routeRSCServerRequest,
unstable_RSCStaticRouter as RSCStaticRouter,
unstable_routeRSCServerRequest as routeRSCServerRequest,
} from "react-router";

type CloudflareEnv = {
ASSETS: Fetcher;
SERVER: Fetcher;
};

export default {
async fetch(request, { SERVER }) {
const callServer = async (request: Request) => await SERVER.fetch(request);
try {
return await routeRSCServerRequest({
request,
callServer,
decode: (body) => RSD.createFromReadableStream(body, manifest),
async renderHTML(getPayload) {
return await RDS.renderToReadableStream(
<RSCStaticRouter getPayload={getPayload} />,
{
bootstrapModules,
signal: request.signal,
}
);
},
});
} catch (reason) {
console.error(reason);
return new Response("Internal Server Error", { status: 500 });
}
},
} satisfies ExportedHandler<CloudflareEnv>;
export default async function handler(
request: Request,
callServer: (request: Request) => Promise<Response>
) {
return routeRSCServerRequest({
request,
callServer,
decode: (body) => createFromReadableStream(body),
renderHTML(getPayload) {
return ReactDomServer.renderToReadableStream(
<RSCStaticRouter getPayload={getPayload} />,
{
bootstrapScriptContent,
signal: request.signal,
}
);
},
});
}
2 changes: 1 addition & 1 deletion integration/helpers/rsc-vite/src/routes/home.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function ServerComponent() {
export default function HomeRoute() {
return <h2>Home</h2>;
}
2 changes: 1 addition & 1 deletion integration/helpers/rsc-vite/src/routes/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
);
}

export default function ServerComponent() {
export default function RootRoute() {
return <Outlet />;
}
4 changes: 0 additions & 4 deletions integration/helpers/rsc-vite/src/wrangler.rsc.toml

This file was deleted.

6 changes: 0 additions & 6 deletions integration/helpers/rsc-vite/src/wrangler.ssr.toml

This file was deleted.

25 changes: 0 additions & 25 deletions integration/helpers/rsc-vite/tsconfig.client.json

This file was deleted.

20 changes: 15 additions & 5 deletions integration/helpers/rsc-vite/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.client.json" }
]
"compilerOptions": {
"allowImportingTsExtensions": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client", "@hiogawa/vite-rsc/types"],
"jsx": "react-jsx"
}
}
Loading