From 739a701ba2da3f2fe47afb6162a50b1003500f2b Mon Sep 17 00:00:00 2001 From: Michael Schwobe Date: Mon, 11 Dec 2023 17:46:32 -0600 Subject: [PATCH] Added route configurable `abortDelay` and `isDehydrated` handle keys and validation --- app/entry.server.tsx | 13 +++++++++++-- app/root.tsx | 10 +++++++++- app/utils/matches-validation.ts | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 app/utils/matches-validation.ts diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 8763900..38cd644 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -111,11 +111,20 @@ function handleBrowserRequest( ) { return new Promise((resolve, reject) => { let shellRendered = false; + + /** + * Use the abortDelay from the route handle if it's defined, + * otherwise use the default. + */ + const abortDelay = + remixContext.staticHandlerContext.matches.at(-1)?.route.handle + ?.abortDelay ?? ABORT_DELAY; + const { pipe, abort } = renderToPipeableStream( , { onShellReady() { @@ -149,6 +158,6 @@ function handleBrowserRequest( }, ); - setTimeout(abort, ABORT_DELAY); + setTimeout(abort, abortDelay); }); } diff --git a/app/root.tsx b/app/root.tsx index 1081c19..1fb413f 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -16,6 +16,7 @@ import { Scripts, ScrollRestoration, useLoaderData, + useMatches, } from "@remix-run/react"; import rdtStylesheetUrl from "remix-development-tools/index.css"; import { GeneralErrorBoundary } from "~/components/error-boundary"; @@ -26,6 +27,7 @@ import tailwindStylesheetUrl from "~/tailwind.css"; import { getUser } from "~/utils/auth.server"; import { ClientHintCheck, getClientHints } from "~/utils/client-hints"; import { getEnv } from "~/utils/env.server"; +import { MatchesSchema } from "~/utils/matches-validation"; import { cn, combineHeaders, @@ -143,6 +145,12 @@ function Document({ env?: Record; theme?: Theme; }) { + const matches = useMatches(); + const matchesResults = MatchesSchema.safeParse(matches); + const isDehydrated = matchesResults.success + ? matchesResults.data?.some((match) => match.handle?.isDehydrated === true) + : false; + return ( @@ -179,7 +187,7 @@ function Document({ }} /> - + {isDehydrated ? null : } diff --git a/app/utils/matches-validation.ts b/app/utils/matches-validation.ts new file mode 100644 index 0000000..cc7db95 --- /dev/null +++ b/app/utils/matches-validation.ts @@ -0,0 +1,18 @@ +import * as z from "zod"; + +const HandleSchema = z + .object({ + abortDelay: z.number().int().min(250).max(180_000), // 3 minutes + isDehydrated: z.boolean(), + }) + .partial(); + +export type Handle = z.infer; + +export const MatchesSchema = z.array( + z.object({ + handle: HandleSchema.optional(), + }), +); + +export type Matches = z.infer;