2023-02-20 20:41:29 +00:00
|
|
|
import { PassThrough } from 'stream';
|
|
|
|
|
import type { EntryContext } from '@remix-run/node';
|
|
|
|
|
import { Response } from '@remix-run/node';
|
|
|
|
|
import { RemixServer } from '@remix-run/react';
|
|
|
|
|
import { renderToPipeableStream } from 'react-dom/server';
|
|
|
|
|
|
|
|
|
|
const ABORT_DELAY = 5000;
|
|
|
|
|
|
2023-02-21 19:23:59 +00:00
|
|
|
type CachedResponse = {
|
|
|
|
|
html:string;
|
|
|
|
|
date: Date;
|
|
|
|
|
}
|
|
|
|
|
const cache = new Map<string, CachedResponse>();
|
|
|
|
|
|
|
|
|
|
|
2023-02-20 20:41:29 +00:00
|
|
|
export default function handleRequest(
|
|
|
|
|
request: Request,
|
|
|
|
|
responseStatusCode: number,
|
|
|
|
|
responseHeaders: Headers,
|
|
|
|
|
remixContext: EntryContext
|
|
|
|
|
) {
|
2023-02-21 19:37:55 +00:00
|
|
|
// console.log(request.url);
|
|
|
|
|
// // check if we have a cached response in memory
|
|
|
|
|
// const cachedResponse = cache.get(request.url);
|
|
|
|
|
// if (cachedResponse) {
|
|
|
|
|
// console.log('Serving from cache', request.url);
|
|
|
|
|
// // 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-21 19:23:59 +00:00
|
|
|
|
|
|
|
|
|
2023-02-20 20:41:29 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
let didError = false;
|
2023-02-21 19:23:59 +00:00
|
|
|
const chunks: Uint8Array[] = [];
|
2023-02-20 20:41:29 +00:00
|
|
|
|
|
|
|
|
const { pipe, abort } = renderToPipeableStream(
|
|
|
|
|
<RemixServer context={remixContext} url={request.url} />,
|
|
|
|
|
{
|
|
|
|
|
onShellReady: () => {
|
|
|
|
|
const body = new PassThrough();
|
|
|
|
|
|
2023-02-21 19:23:59 +00:00
|
|
|
body
|
|
|
|
|
.on('data', (data) => {
|
|
|
|
|
chunks.push(data);
|
|
|
|
|
})
|
|
|
|
|
.on('end', () => {
|
|
|
|
|
const html = Buffer.concat(chunks).toString('utf8');
|
|
|
|
|
cache.set(request.url, { html: html.replace('Rendered Fresh', `Served from Cache ${new Date().toString()}`), date: new Date() });
|
|
|
|
|
})
|
|
|
|
|
|
2023-02-20 20:41:29 +00:00
|
|
|
responseHeaders.set('Content-Type', 'text/html');
|
|
|
|
|
|
|
|
|
|
resolve(
|
|
|
|
|
new Response(body, {
|
|
|
|
|
headers: responseHeaders,
|
|
|
|
|
status: didError ? 500 : responseStatusCode,
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
pipe(body);
|
|
|
|
|
},
|
|
|
|
|
onShellError: (err: unknown) => {
|
|
|
|
|
reject(err);
|
|
|
|
|
},
|
|
|
|
|
onError: (error: unknown) => {
|
|
|
|
|
didError = true;
|
|
|
|
|
|
|
|
|
|
console.error(error);
|
2023-02-21 19:23:59 +00:00
|
|
|
}
|
2023-02-20 20:41:29 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setTimeout(abort, ABORT_DELAY);
|
|
|
|
|
});
|
|
|
|
|
}
|