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