@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
JavaScript
;
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