/** * 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 type { EntryContext } from '@remix-run/node' import { createReadableStreamFromReadable } from '@remix-run/node' import { RemixServer } from '@remix-run/react' import { isbot } from 'isbot' import { renderToPipeableStream } from 'react-dom/server' // eslint-disable-next-line @typescript-eslint/naming-convention const ABORT_DELAY = 5000 export default async function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) { return isbot(request.headers.get('user-agent') ?? '') ? handleBotRequest( request, responseStatusCode, responseHeaders, remixContext ) : handleBrowserRequest( request, responseStatusCode, responseHeaders, remixContext ) } async function handleBotRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) { return new Promise((resolve, reject) => { let shellRendered = false const { pipe, abort } = renderToPipeableStream( , { 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: unknown) { reject(error) }, onError(error: unknown) { 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) }) } async function handleBrowserRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) { return new Promise((resolve, reject) => { let shellRendered = false const { pipe, abort } = renderToPipeableStream( , { onShellReady() { 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: unknown) { reject(error) }, onError(error: unknown) { 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) }) }