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

124 lines (118 loc) 3.7 kB
'use strict'; var server = require('react-dom/server'); var React = require('react'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(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 server.renderToString( /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, injections.map((callback, i) => /* @__PURE__ */ React__namespace.createElement(React__namespace.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); } } exports.built_for_ssr = true; exports.JSONDecodeStream = JSONDecodeStream; exports.JSONEncodeStream = JSONEncodeStream; exports.createInjectionTransformStream = createInjectionTransformStream; exports.pipeReaderToResponse = pipeReaderToResponse; //# sourceMappingURL=out.js.map //# sourceMappingURL=stream-utils.ssr.cjs.map