Skip to content
85 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Fast pages, required checks on the branch, self-hosted runners, honest incidents1import type { EntryContext, RouterContextProvider, ServerInstrumentation } from "react-router";
2import { ServerRouter } from "react-router";
3import { isbot } from "isbot";
4import { renderToReadableStream } from "react-dom/server";
5
The site's pages run only their own scripts: a nonce policy, nosniff, a referrer policy and no framing6import { NonceContext } from "./lib/nonce";
7import { makeNonce, pagePolicy } from "./lib/page-headers";
Fast pages, required checks on the branch, self-hosted runners, honest incidents8import { recordHandler } from "./lib/perf.server";
9
10// React Router's own server entry, plus the timing of every loader and
11// action for the Server-Timing header (lib/perf.server.ts).
12
13export const streamTimeout = 5_000;
14
15export const instrumentations: ServerInstrumentation[] = [
16 {
17 route(route) {
18 route.instrument({
19 async loader(handle) {
20 const started = Date.now();
21 await handle();
22 recordHandler(route.id, "loader", Date.now() - started);
23 },
24 async action(handle) {
25 const started = Date.now();
26 await handle();
27 recordHandler(route.id, "action", Date.now() - started);
28 },
29 });
30 },
31 },
32];
33
34export default async function handleRequest(
35 request: Request,
36 responseStatusCode: number,
37 responseHeaders: Headers,
38 routerContext: EntryContext,
39 _loadContext: RouterContextProvider,
40) {
41 // https://httpwg.org/specs/rfc9110.html#HEAD
42 if (request.method.toUpperCase() === "HEAD") {
43 return new Response(null, {
44 status: responseStatusCode,
45 headers: responseHeaders,
46 });
47 }
48
49 let shellRendered = false;
50 const userAgent = request.headers.get("user-agent");
51
The site's pages run only their own scripts: a nonce policy, nosniff, a referrer policy and no framing52 // The page's inline scripts carry this nonce, and its policy allows only
53 // them (lib/page-headers.ts). Not in development, where Vite adds its own.
54 const nonce = import.meta.env.DEV ? undefined : makeNonce();
55 const body = await renderToReadableStream(
56 <NonceContext value={nonce}>
57 <ServerRouter context={routerContext} url={request.url} nonce={nonce} />
58 </NonceContext>,
59 {
60 nonce,
61 signal: AbortSignal.timeout(streamTimeout + 1000),
62 onError(error: unknown) {
63 responseStatusCode = 500;
64 // Errors while streaming after the shell; those in the shell reject
65 // and are logged by React Router.
66 if (shellRendered) {
67 console.error(error);
68 }
69 },
Fast pages, required checks on the branch, self-hosted runners, honest incidents70 },
The site's pages run only their own scripts: a nonce policy, nosniff, a referrer policy and no framing71 );
Fast pages, required checks on the branch, self-hosted runners, honest incidents72 shellRendered = true;
73
74 // Crawlers get the whole page at once, deferred panels included.
75 if ((userAgent && isbot(userAgent)) || routerContext.isSpaMode) {
76 await body.allReady;
77 }
78
79 responseHeaders.set("Content-Type", "text/html");
The site's pages run only their own scripts: a nonce policy, nosniff, a referrer policy and no framing80 if (nonce) responseHeaders.set("Content-Security-Policy", pagePolicy(nonce));
Fast pages, required checks on the branch, self-hosted runners, honest incidents81 return new Response(body, {
82 headers: responseHeaders,
83 status: responseStatusCode,
84 });
85}