fully-react
Version:
React Server for Vite
251 lines (248 loc) • 7.83 kB
JavaScript
import {
renderServerComponent
} from "./chunk-U26WWCBL.js";
import {
sanitize
} from "./chunk-NHKA32FP.js";
// src/server/html.tsx
import { use, useMemo } from "react";
import {
createFromFetch as createElementFromFetch,
createFromReadableStream as createElementFromStream
} from "react-server-dom-webpack/client.edge";
import { renderToReadableStream as _renderToHTMLStream } from "react-dom/server.edge";
import { jsx, jsxs } from "react/jsx-runtime";
function useServerElement(serverElementStream, flightResponseRef, writable, onChunk = () => {
}) {
if (flightResponseRef.current !== null) {
return flightResponseRef.current;
}
if (writable && !writable.locked) {
let read2 = function() {
forwardReader.read().then(({ done, value }) => {
if (value) {
onChunk(value);
}
if (done) {
flightResponseRef.current = null;
writer.close();
} else {
writer.write(value);
read2();
}
});
};
var read = read2;
const [renderStream, forwardStream] = serverElementStream.tee();
const res = createElementFromStream(renderStream, {
callServer: (method, args) => {
throw new Error("Not implemented");
}
// moduleMap: isEdgeRuntime
// ? clientReferenceManifest.edgeSSRModuleMapping
// : clientReferenceManifest.ssrModuleMapping,
});
flightResponseRef.current = res;
const forwardReader = forwardStream.getReader();
const writer = writable.getWriter();
read2();
return res;
} else {
return createElementFromStream(serverElementStream, {
callServer: (method, args) => {
throw new Error("Not implemented");
}
// moduleMap: isEdgeRuntime
// ? clientReferenceManifest.edgeSSRModuleMapping
// : clientReferenceManifest.ssrModuleMapping,
});
}
}
function createServerComponentRenderer(src, {
dataStream: writable,
...env
}) {
const flightResponseRef = { current: null };
return function ServerComponentWrapper(props) {
const response = useMemo(() => {
if (!writable || writable.locked) {
return createElementFromFetch(
renderServerComponent(src, props, env).then(
(r) => ({ body: r })
),
{
callServer: (method, args) => {
throw new Error("Not implemented");
}
}
);
}
const res = createElementFromFetch(
renderServerComponent(src, props, env).then((r) => {
const [renderStream, forwardStream] = r.tee();
const forwardReader = forwardStream.getReader();
const writer = writable.getWriter();
function read() {
forwardReader.read().then(({ done, value }) => {
if (value) {
}
if (done) {
flightResponseRef.current = null;
writer.close();
} else {
writer.write(value);
read();
}
});
}
read();
return { body: renderStream };
}),
{
callServer: (method, args) => {
throw new Error("Not implemented");
}
}
);
flightResponseRef.current = res;
return res;
}, [writable]);
if (!props) {
console.log("called with no props");
throw new Error("");
}
return use(response);
};
}
async function renderToHTMLStream(component, props, renderOptions) {
const ServerComponent = createServerComponentRenderer(
component,
renderOptions
);
const htmlStream = await _renderToHTMLStream(
/* @__PURE__ */ jsx(ServerComponent, { ...props }),
renderOptions
);
return htmlStream.pipeThrough(bufferedTransformStream());
}
async function createHTMLResponse(component, props, renderOptions, responseInit = {}) {
const transformStream = new TransformStream();
try {
const htmlStream = await renderToHTMLStream(component, props, {
...renderOptions,
dataStream: transformStream.writable
});
return new Response(
htmlStream.pipeThrough(
inlineInitialServerComponent(transformStream.readable)
),
{
...responseInit,
headers: {
"Content-Type": "text/html",
...responseInit.headers ?? {}
}
}
);
} catch (e) {
const htmlStream = await _renderToHTMLStream(
/* @__PURE__ */ jsxs("html", { id: "__error__", children: [
/* @__PURE__ */ jsx("head", {}),
/* @__PURE__ */ jsx("body", {})
] }),
renderOptions
);
console.log({ error: e });
return new Response(
htmlStream.pipeThrough(bufferedTransformStream()).pipeThrough(inlineInitialServerComponent(transformStream.readable)),
{
headers: { "Content-Type": "text/html" }
}
);
}
}
async function nextMacroTask() {
return new Promise((resolve) => setTimeout(resolve, 0));
}
var closingBodyHtmlText = `</body></html>`;
function inlineInitialServerComponent(serverElementStream) {
let removedClosingBodyHtmlText = false;
let insertingServerElementStreamScripts;
let finishedInsertingServerElementStreamScripts = false;
const textDecoder = new TextDecoder();
const textEncoder = new TextEncoder();
return new TransformStream({
transform(chunk, controller) {
const text = textDecoder.decode(chunk);
if (text.endsWith(closingBodyHtmlText) && !finishedInsertingServerElementStreamScripts) {
const [withoutClosingBodyHtmlText] = text.split(closingBodyHtmlText);
controller.enqueue(textEncoder.encode(withoutClosingBodyHtmlText));
removedClosingBodyHtmlText = true;
} else {
controller.enqueue(chunk);
}
if (!insertingServerElementStreamScripts) {
const reader = serverElementStream.getReader();
controller.enqueue(
textEncoder.encode(
`<script>(()=>{const{writable,readable}=new TransformStream();const writer=writable.getWriter();self.init_server=readable;self.chunk=(text)=>writer.write(new TextEncoder().encode(text))})()</script>`
)
);
insertingServerElementStreamScripts = new Promise(async (resolve) => {
try {
while (true) {
const result = await reader.read();
if (result.done) {
finishedInsertingServerElementStreamScripts = true;
if (removedClosingBodyHtmlText) {
controller.enqueue(textEncoder.encode(closingBodyHtmlText));
}
return resolve();
}
await nextMacroTask();
controller.enqueue(
textEncoder.encode(
`<script>self.chunk(${sanitize(
JSON.stringify(textDecoder.decode(result.value))
)});</script>`
)
);
}
} catch (error) {
controller.error(error);
}
});
}
},
async flush() {
return insertingServerElementStreamScripts;
}
});
}
function bufferedTransformStream() {
let bufferedText = ``;
let buffering;
return new TransformStream({
transform(chunk, controller) {
bufferedText += new TextDecoder().decode(chunk);
buffering ||= new Promise(async (resolve) => {
await nextMacroTask();
controller.enqueue(new TextEncoder().encode(bufferedText));
bufferedText = ``;
buffering = void 0;
resolve();
});
},
async flush() {
return buffering;
}
});
}
export {
useServerElement,
createServerComponentRenderer,
renderToHTMLStream,
createHTMLResponse,
inlineInitialServerComponent,
bufferedTransformStream
};