@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
55 lines • 2.26 kB
JSX
import { ReadableStream as NodeReadableStream } from 'node:stream/web';
import * as Vue from 'vue';
import { pipeToWebWritable, renderToString } from 'vue/server-renderer';
import { isbot } from 'isbot';
import { transformReadableStreamWithRouter } from '@tanstack/router-core/ssr/server';
function prependDoctype(readable) {
const encoder = new TextEncoder();
let sentDoctype = false;
return new NodeReadableStream({
start(controller) {
const reader = readable.getReader();
async function pump() {
const { done, value } = await reader.read();
if (done) {
controller.close();
return;
}
if (!sentDoctype) {
sentDoctype = true;
controller.enqueue(encoder.encode('<!DOCTYPE html>'));
}
controller.enqueue(value);
return pump();
}
pump().catch((err) => controller.error(err));
},
});
}
export const renderRouterToStream = async ({ request, router, responseHeaders, App, }) => {
const app = Vue.createSSRApp(App, { router });
if (isbot(request.headers.get('User-Agent'))) {
let fullHtml = await renderToString(app);
const htmlOpenIndex = fullHtml.indexOf('<html');
const htmlCloseIndex = fullHtml.indexOf('</html>');
if (htmlOpenIndex !== -1 && htmlCloseIndex !== -1) {
fullHtml = fullHtml.slice(htmlOpenIndex, htmlCloseIndex + 7);
}
else if (htmlOpenIndex !== -1) {
fullHtml = fullHtml.slice(htmlOpenIndex);
}
return new Response(`<!DOCTYPE html>${fullHtml}`, {
status: router.stores.statusCode.get(),
headers: responseHeaders,
});
}
const { writable, readable } = new TransformStream();
pipeToWebWritable(app, {}, writable);
const doctypedStream = prependDoctype(readable);
const responseStream = transformReadableStreamWithRouter(router, doctypedStream);
return new Response(responseStream, {
status: router.stores.statusCode.get(),
headers: responseHeaders,
});
};
//# sourceMappingURL=renderRouterToStream.jsx.map