silphius/app/entry.server.jsx
2024-11-04 12:39:06 -06:00

146 lines
3.9 KiB
JavaScript

/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/
import {PassThrough} from 'node:stream';
import {createReadableStreamFromReadable} from '@remix-run/node';
import {RemixServer} from '@remix-run/react';
import {isbot} from 'isbot';
import {renderToPipeableStream} from 'react-dom/server';
import {hooks} from 'virtual:sylvite/server';
const ABORT_DELAY = 5_000;
export async function handleUpgrade(request, socket, head) {
const {handleUpgrade} = await import('./websocket.js');
handleUpgrade(request, socket, head);
}
export default function handleRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
loadContext
) {
return isbot(request.headers.get('user-agent') || '')
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
loadContext,
);
}
function handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const {pipe, abort} = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onAllReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);
responseHeaders.set('Content-Type', 'text/html');
resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);
pipe(body);
},
onShellError(error) {
reject(error);
},
onError(error) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
loadContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const {pipe, abort} = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onShellReady() {
shellRendered = true;
const body = hooks.call('@/sylvite/cha0s-remix:requestBody', new PassThrough(), request, loadContext);
const stream = createReadableStreamFromReadable(body);
responseHeaders.set('Content-Type', 'text/html');
hooks.call('@/sylvite/cha0s-remix:responseHeaders', responseHeaders, request, loadContext);
resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);
pipe(body);
},
onShellError(error) {
reject(error);
},
onError(error) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);
setTimeout(abort, ABORT_DELAY);
});
}