< Summary

Information
Class: entry.server.tsx
Assembly: app
File(s): /home/runner/work/ClutterStock/ClutterStock/frontend/app/entry.server.tsx
Tag: 58_25416222083
Line coverage
0%
Covered lines: 0
Uncovered lines: 32
Coverable lines: 32
Total lines: 110
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 9
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/ClutterStock/ClutterStock/frontend/app/entry.server.tsx

#LineLine coverage
 01import { PassThrough } from "node:stream";
 2
 3import type { AppLoadContext, EntryContext } from "react-router";
 4import { createReadableStreamFromReadable } from "@react-router/node";
 5import { ServerRouter } from "react-router";
 6import { isbot } from "isbot";
 7import type { RenderToPipeableStreamOptions } from "react-dom/server";
 8import { renderToPipeableStream } from "react-dom/server";
 9
 10import { startNodeOpenTelemetry } from "~/otel/server";
 11import { withSsrRequestSpan } from "~/otel/ssr-request";
 12
 013startNodeOpenTelemetry();
 14
 015export const streamTimeout = 5_000;
 16
 017export default function handleRequest(
 18  request: Request,
 19  responseStatusCode: number,
 20  responseHeaders: Headers,
 21  routerContext: EntryContext,
 22  loadContext: AppLoadContext,
 23  // If you have middleware enabled:
 24  // loadContext: RouterContextProvider
 25) {
 26  // https://httpwg.org/specs/rfc9110.html#HEAD
 027  if (request.method.toUpperCase() === "HEAD") {
 028    return new Response(null, {
 29      status: responseStatusCode,
 30      headers: responseHeaders,
 31    });
 32  }
 33
 034  return withSsrRequestSpan(request, () => renderHtmlResponse(
 35    request,
 36    responseStatusCode,
 37    responseHeaders,
 38    routerContext,
 39    loadContext,
 40  ));
 41}
 42
 043async function renderHtmlResponse(
 44  request: Request,
 45  responseStatusCode: number,
 46  responseHeaders: Headers,
 47  routerContext: EntryContext,
 48  _loadContext: AppLoadContext,
 49): Promise<Response> {
 050  return new Promise((resolve, reject) => {
 051    let shellRendered = false;
 052    const userAgent = request.headers.get("user-agent");
 53
 54    // Ensure requests from bots and SPA Mode renders wait for all content to load before responding
 55    // https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-
 56    const readyOption: keyof RenderToPipeableStreamOptions =
 057      (userAgent && isbot(userAgent)) || routerContext.isSpaMode
 58        ? "onAllReady"
 59        : "onShellReady";
 60
 61    // Abort the rendering stream after the `streamTimeout` so it has time to
 62    // flush down the rejected boundaries
 063    let timeoutId: ReturnType<typeof setTimeout> | undefined = setTimeout(
 064      () => abort(),
 65      streamTimeout + 1000,
 66    );
 67
 068    const { pipe, abort } = renderToPipeableStream(
 69      <ServerRouter context={routerContext} url={request.url} />,
 70      {
 071        [readyOption]() {
 072          shellRendered = true;
 073          const body = new PassThrough({
 074            final(callback) {
 75              // Clear the timeout to prevent retaining the closure and memory leak
 076              clearTimeout(timeoutId);
 077              timeoutId = undefined;
 078              callback();
 79            },
 80          });
 081          const stream = createReadableStreamFromReadable(body);
 82
 083          responseHeaders.set("Content-Type", "text/html");
 84
 085          pipe(body);
 86
 087          resolve(
 88            new Response(stream, {
 89              headers: responseHeaders,
 90              status: responseStatusCode,
 91            }),
 92          );
 93        },
 094        onShellError(error: unknown) {
 095          reject(error);
 96        },
 097        onError(error: unknown) {
 098          responseStatusCode = 500;
 99          // Log streaming rendering errors from inside the shell.  Don't log
 100          // errors encountered during initial shell rendering since they'll
 101          // reject and get logged in handleDocumentRequest.
 0102          if (shellRendered) {
 0103            console.error(error);
 104          }
 105        },
 106      },
 107    );
 108  });
 109}
 110