@hiogawa/vite-rsc v0.3.4
@hiogawa/vite-rsc
Features
- Framework-less: Implements RSC conventions and provides direct
react-server-domruntime API without framework-specific abstractions. - CSS support: CSS is automatically code-split at client boundaries and injected upon rendering. For server components, CSS assets can be manually rendered via
import.meta.viteRscCssAPI based on own routing conventions. - HMR support: Enables editing both client and server components without full page reloads.
- Runtime agnostic: Built on Vite environment API and works with other runtimes (e.g.,
@cloudflare/vite-plugin).
Examples
Basic Concepts
This example can be found in ./examples/basic-doc.
import rsc from "@hiogawa/vite-rsc/plugin";
export default defineConfig() {
plugins: [
rsc({
entries: {
// server entry with react-server condition, which should manage:
// - RSC serialization
// - server functions handling
rsc: "./src/entry.rsc.tsx",
// server entry without react-server condition, which should manage:
// - RSC deserialization for SSR
ssr: "./src/entry.ssr.tsx",
// main script entry executed on browser, which should manage:
// - RSC deserialization for hydration
// - refetch and re-render RSC
// - calling server functions
browser: "./src/entry.browser.tsx",
},
})
]
}import * as ReactServer from "@hiogawa/vite-rsc/rsc"; // React core API
import { importSsr } from "@hiogawa/vite-rsc/rsc"; // Vite specifc helper
// the plugin assumes `rsc` entry having default export of request handler
export default async function handler(request: Request): Promise<Response> {
// serialize RSC
const root = <html><body><h1>Test</h1></body></html>;
const rscStream = ReactServer.renderToReadableStream(root);
// respond direct RSC stream request based on framework's convention
if (request.url.endsWith(".rsc")) {
return new Response(rscStream, {
headers: {
'Content-type': 'text/html'
}
})
}
// delegate to SSR environment for html rendering
const { handleSsr } = await importSsr<typeof import("./entry.ssr.tsx")>();
const htmlStream = await handleSsr(rscStream);
// respond html
return new Response(htmlStream, {
headers: {
'Content-type': 'text/html'
}
})
}import * as ReactClient from "@hiogawa/vite-rsc/ssr";
import * as ReactDOMServer from "react-dom/server.edge";
import { getAssetsManifest } from "@hiogawa/vite-rsc/ssr";
export async function handleSsr(rscStream: ReadableStream) {
// deserialize RSC
// (NOTE: ssr deserization should be done inside a wrapper component, but it's simplified for doc.)
const root = await ReactClient.createFromReadableStream(rscStream);
// render html (traditional SSR)
const htmlStream = ReactDOMServer.renderToReadableStream(root, {
bootstrapScriptContent: getAssetsManifest().bootstrapScriptContent,
})
return htmlStream;
}import * as ReactClient from "@hiogawa/vite-rsc/browser";
import * as ReactDOMClient from "react-dom/client";
async function main() {
// fetch and deserialize RSC
// (NOTE: extra fetch for hydration can be avoided but it's simplified for doc.)
const rscResponse = await fetch(window.location.href + ".rsc");
const root = await ReactClient.createFromReadableStream(rscResponse.body);
// hydration (traditional CSR)
ReactDOMClient.hydrateRoot(document, root);
}
main();Handling server function
TODO
For now, read ./src/extra/{rsc,browser} or ./examples/react-router for the idea.
RSC API
These are mostly re-exports of react-server-dom-xxx/server and react-server-dom-xxx/client, aka React flight API.
@hiogawa/vite-rsc/rsc
renderToReadableStream: RSC serializationcreateFromReadableStream: RSC deserialization (This is also available on rsc environment itself. For example, it allows saving serailized RSC and deserializing it for later use.)decodeAction/decodeReply/loadServerAction: server function related
@hiogawa/vite-rsc/ssr
createFromReadableStream: RSC deserialization on server for SSR
@hiogawa/vite-rsc/browser
createFromReadableStream: RSC deserialization on browser for hydrationcreateFromFetch: a robust way ofcreateFromReadableStream((await fetch("...")).body)encodeReply/setServerCallback: server function related
Helper API
These API provide a necessary API to integrate multi environment features into an app.
@hiogawa/vite-rsc/rsc
importSsr<T>: () => Promise<T>This allows importingssrentry module insiderscenvironment.
@hiogawa/vite-rsc/ssr
importRsc<T>: () => Promise<T>This allows importingrscentry module insidessrenvironment.getAssetsManifest().bootstrapScriptContent: stringThis provides a code to execute browser entry on browser.import.meta.viteRscCss: React.ReactNodeThis allows collecting css which is imported through a current server module and injecting them inside server components.
import "./test.css";
import child from "./child.tsx";
export function ServerPage() {
// this will include css assets for "test.css"
// and any css transitively imported through "child.tsx"
return <>
{import.meta.viteRscCss}
...
</>
}Higher level RSC API
This is a simple wrapper of the first "RSC API". See ./examples/basic for usage.
Also you can read implementations ./src/extra/{rsc,ssr,browser} to understand
how bare RSC API is intended to be used.
@hiogawa/vite-rsc/extra/rsc
renderRequest
@hiogawa/vite-rsc/extra/ssr
renderHtml
@hiogawa/vite-rsc/extra/browser
hydrate
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
12 months ago
12 months ago
12 months ago