awesome-uses/src/entry.server.tsx

82 lines
2.3 KiB
TypeScript
Raw Normal View History

2023-02-20 20:41:29 +00:00
import type { EntryContext } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
2023-02-21 21:11:11 +00:00
import { renderToReadableStream } from 'react-dom/server';
2023-02-20 20:41:29 +00:00
const ABORT_DELAY = 5000;
2023-02-21 22:05:08 +00:00
export async function streamToText(stream: ReadableStream<Uint8Array>): Promise<string> {
let result = '';
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
while (true) { // eslint-disable-line no-constant-condition
const { done, value } = await reader.read();
if (done) {
break;
}
result += value;
}
return result;
}
2023-02-21 19:23:59 +00:00
type CachedResponse = {
2023-02-21 21:11:11 +00:00
html: string;
2023-02-21 19:23:59 +00:00
date: Date;
}
const cache = new Map<string, CachedResponse>();
2023-02-21 21:11:11 +00:00
export default async function handleRequest(
2023-02-20 20:41:29 +00:00
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
2023-02-22 18:47:13 +00:00
// check if we have a cached response in memory
const cachedResponse = cache.get(request.url);
2023-02-23 15:45:43 +00:00
if (cachedResponse) {
2023-02-23 15:37:25 +00:00
// console.log('Serving from cache', request.url);
2023-02-22 18:47:13 +00:00
// if we have a cached response, check if it's less than 5 seconds old
const now = new Date();
const diff = now.getTime() - cachedResponse.date.getTime();
if (true || diff < 5000) {
// if it's less than 5 seconds old, return the cached response
responseHeaders.set('Content-Type', 'text/html');
return new Response(cachedResponse.html, {
headers: responseHeaders,
status: responseStatusCode,
});
}
}
2023-02-20 20:41:29 +00:00
2023-02-21 21:11:11 +00:00
let didError = false;
const chunks: Uint8Array[] = [];
2023-02-21 19:23:59 +00:00
2023-02-21 21:11:11 +00:00
const body = await renderToReadableStream(
<RemixServer context={remixContext} url={request.url} />,
{
onError: (error: unknown) => {
didError = true;
console.error(error);
}
}
);
2023-02-20 20:41:29 +00:00
2023-02-22 18:47:13 +00:00
// tee the stream so we can cache it and send it to the client
2023-02-21 22:05:08 +00:00
const [toReponse, toCache] = body.tee();
2023-02-23 15:37:25 +00:00
streamToText(toCache).then(html => {
console.log('Caching', request.url);
cache.set(request.url, {
html: html.replace('Rendered Fresh', `Rendered from cache ${new Date().toISOString()}`),
date: new Date(),
});
2023-02-22 18:47:13 +00:00
});
2023-02-20 20:41:29 +00:00
2023-02-21 21:11:11 +00:00
const headers = new Headers(responseHeaders);
headers.set("Content-Type", "text/html");
2023-02-21 22:05:08 +00:00
const response = new Response(toReponse, {
2023-02-21 21:11:11 +00:00
headers,
status: didError ? 500 : responseStatusCode,
2023-02-21 22:05:08 +00:00
});
return response;
2023-02-20 20:41:29 +00:00
}