UNPKG

@apollo/client-react-streaming

Version:

This package provides building blocks to create framework-level integration of Apollo Client with React's streaming SSR. See the [@apollo/client-integration-nextjs](https://github.com/apollographql/apollo-client-integrations/tree/main/packages/nextjs) pac

99 lines (96 loc) 3.04 kB
import { renderToString } from 'react-dom/server'; import * as React from 'react'; // src/stream-utils/JSONTransformStreams.tsx var JSONEncodeStream = class extends TransformStream { constructor() { super({ transform(chunk, controller) { controller.enqueue(JSON.stringify(chunk)); } }); } }; var JSONDecodeStream = class extends TransformStream { constructor() { super({ transform(chunk, controller) { if (typeof chunk !== "string") { chunk = new TextDecoder().decode(chunk); } controller.enqueue(JSON.parse(chunk)); } }); } }; function createInjectionTransformStream() { let queuedInjections = []; async function renderInjectedHtml() { const injections = [...queuedInjections]; queuedInjections = []; return renderToString( /* @__PURE__ */ React.createElement(React.Fragment, null, injections.map((callback, i) => /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, callback()))) ); } let headInserted = false; let currentlyStreaming = false; let tailOfLastChunk = ""; const textDecoder = new TextDecoder(); const textEncoder = new TextEncoder(); const HEAD_END = "</head>"; const KEEP_BYTES = HEAD_END.length; const transformStream = new TransformStream({ async transform(chunk, controller) { if (currentlyStreaming) { controller.enqueue(chunk); return; } if (!headInserted) { const content = tailOfLastChunk + textDecoder.decode(chunk, { stream: true }); const index = content.indexOf(HEAD_END); if (index !== -1) { const insertedHeadContent = content.slice(0, index) + await renderInjectedHtml() + content.slice(index); controller.enqueue(textEncoder.encode(insertedHeadContent)); currentlyStreaming = true; setImmediate(() => { currentlyStreaming = false; }); headInserted = true; } else { tailOfLastChunk = content.slice(-KEEP_BYTES); controller.enqueue(textEncoder.encode(content.slice(0, -KEEP_BYTES))); } } else { controller.enqueue(textEncoder.encode(await renderInjectedHtml())); controller.enqueue(chunk); currentlyStreaming = true; setImmediate(() => { currentlyStreaming = false; }); } } }); return { transformStream, injectIntoStream: (callback) => queuedInjections.push(callback) }; } // src/stream-utils/pipeReaderToResponse.ts async function pipeReaderToResponse(reader, res) { try { while (true) { const { done, value } = await reader.read(); if (done) { res.end(); return; } else { res.write(value); } } } catch (e) { res.destroy(e); } } const built_for_ssr = true; export { JSONDecodeStream, JSONEncodeStream, built_for_ssr, createInjectionTransformStream, pipeReaderToResponse }; //# sourceMappingURL=out.js.map //# sourceMappingURL=stream-utils.ssr.js.map