diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-07-27 19:02:58 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-07-27 19:02:58 +0900 |
| commit | b70fa3abf9c96871cc3e39090e9a00da4ad87b8b (patch) | |
| tree | 848da44374c48edec603fb014c59ad0fbb9307e6 /frontend/app/entry.server.tsx | |
| parent | e487036c5cc9f5b59e9efbaec132a2fd60896317 (diff) | |
| parent | 7cbf34204233df7c7e9e4b24998e25dbd8d2a423 (diff) | |
| download | phperkaigi-2025-albatross-b70fa3abf9c96871cc3e39090e9a00da4ad87b8b.tar.gz phperkaigi-2025-albatross-b70fa3abf9c96871cc3e39090e9a00da4ad87b8b.tar.zst phperkaigi-2025-albatross-b70fa3abf9c96871cc3e39090e9a00da4ad87b8b.zip | |
Merge branch 'remix'
Diffstat (limited to 'frontend/app/entry.server.tsx')
| -rw-r--r-- | frontend/app/entry.server.tsx | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/frontend/app/entry.server.tsx b/frontend/app/entry.server.tsx new file mode 100644 index 0000000..77b6f15 --- /dev/null +++ b/frontend/app/entry.server.tsx @@ -0,0 +1,124 @@ +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"; + +const ABORT_DELAY = 5_000; + +export default 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, + ); +} + +function handleBotRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + 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: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + if (shellRendered) { + console.error(error); + } + }, + }, + ); + + setTimeout(abort, ABORT_DELAY); + }); +} + +function handleBrowserRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + 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 = 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; + if (shellRendered) { + console.error(error); + } + }, + }, + ); + + setTimeout(abort, ABORT_DELAY); + }); +} |
