vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
113 lines (110 loc) • 3.65 kB
JavaScript
/**
* vite-plugin-react-server
* Copyright (c) Nico Brinkkemper
* MIT License
*/
import { PassThrough } from 'node:stream';
import { parentPort } from 'node:worker_threads';
import * as ReactDOMServer from 'react-dom/server';
import 'react';
import { createFromNodeStream } from 'react-server-dom-esm/client.node';
const activeRenders = /* @__PURE__ */ new Map();
const htmlContent = /* @__PURE__ */ new Map();
const htmlPromises = /* @__PURE__ */ new Map();
const messageHandler = async (message) => {
try {
switch (message.type) {
case "RSC_CHUNK": {
const { id, chunk, moduleRootPath, moduleBaseURL, htmlOutputPath, pipableStreamOptions } = message;
const render = activeRenders.get(id);
if (!render) {
activeRenders.set(id, {
chunks: [chunk],
id,
complete: false,
rendered: false,
moduleRootPath,
moduleBaseURL,
outDir: "",
htmlOutputPath,
pipableStreamOptions
});
} else {
render.chunks = [...render.chunks, chunk];
}
break;
}
case "RSC_END": {
const { id } = message;
const render = activeRenders.get(id);
if (!render) {
throw new Error(`No render state found for ${id}`);
}
render.complete = true;
const rscStream = new PassThrough();
for (const chunk of render.chunks) {
rscStream.write(chunk);
}
rscStream.end();
const reactElements = await createFromNodeStream(
rscStream,
render.moduleRootPath,
render.moduleBaseURL
);
const htmlPromise = new Promise((resolve) => {
const collectStream = new PassThrough();
let html = "";
collectStream.on("data", (chunk) => {
html += chunk.toString();
});
collectStream.on("end", () => {
resolve(html);
render.rendered = true;
parentPort?.postMessage({
type: "ALL_READY",
id,
html,
outputPath: render.htmlOutputPath
});
});
const stream = ReactDOMServer.renderToPipeableStream(
reactElements,
{
...render.pipableStreamOptions,
// Calculate relative paths based on route depth
bootstrapModules: render.pipableStreamOptions?.bootstrapModules?.map((path) => {
if (!path) return path;
if (render.moduleBaseURL && render.moduleBaseURL !== "") {
return new URL(path, render.moduleBaseURL).toString();
}
const depth = id.split("/").filter(Boolean).length;
const prefix = depth > 0 ? "../".repeat(depth) : "/";
return path.startsWith("/") ? prefix + path.slice(1) : prefix + path;
}),
onShellReady() {
parentPort?.postMessage({ type: "SHELL_READY", id });
}
}
);
stream.pipe(collectStream);
});
htmlPromises.set(id, htmlPromise);
rscStream.destroy();
activeRenders.delete(id);
htmlContent.delete(id);
htmlPromises.delete(id);
break;
}
case "SHUTDOWN": {
console.log("Received shutdown signal");
parentPort?.close();
break;
}
}
} catch (error) {
console.error("Error in messageHandler:", error);
throw error;
}
};
export { messageHandler };
//# sourceMappingURL=messageHandler.js.map