From 6352d2ed1d10b74b427bd473c3d08554aaf50abc Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Mon, 16 Dec 2024 12:20:06 -0500 Subject: [PATCH 1/2] Slight reorg of the RouteModule types --- .changeset/slimy-cows-begin.md | 5 ++ packages/react-router/index.ts | 8 +- .../react-router/lib/dom/ssr/routeModules.ts | 83 +++++++++++++++++++ .../react-router/lib/server-runtime/entry.ts | 6 +- .../lib/server-runtime/routeModules.ts | 56 ------------- .../react-router/lib/server-runtime/routes.ts | 2 +- 6 files changed, 95 insertions(+), 65 deletions(-) create mode 100644 .changeset/slimy-cows-begin.md delete mode 100644 packages/react-router/lib/server-runtime/routeModules.ts diff --git a/.changeset/slimy-cows-begin.md b/.changeset/slimy-cows-begin.md new file mode 100644 index 0000000000..e4df135e9d --- /dev/null +++ b/.changeset/slimy-cows-begin.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +Internal reorg of the `RouteModule` interfaces for deduplication and documentation purposes diff --git a/packages/react-router/index.ts b/packages/react-router/index.ts index 22d1bae6cd..e83808b47c 100644 --- a/packages/react-router/index.ts +++ b/packages/react-router/index.ts @@ -200,10 +200,13 @@ export type { ClientActionFunctionArgs, ClientLoaderFunction, ClientLoaderFunctionArgs, + HeadersArgs, + HeadersFunction, MetaArgs, MetaDescriptor, MetaFunction, LinksFunction, + ServerRouteModule, } from "./lib/dom/ssr/routeModules"; export type { ServerRouterProps } from "./lib/dom/ssr/server"; export { ServerRouter } from "./lib/dom/ssr/server"; @@ -251,11 +254,6 @@ export type { LinkDescriptor, } from "./lib/router/links"; -export type { - HeadersArgs, - HeadersFunction, -} from "./lib/server-runtime/routeModules"; - export type { RequestHandler } from "./lib/server-runtime/server"; export type { diff --git a/packages/react-router/lib/dom/ssr/routeModules.ts b/packages/react-router/lib/dom/ssr/routeModules.ts index fa70b57e86..f4efed0433 100644 --- a/packages/react-router/lib/dom/ssr/routeModules.ts +++ b/packages/react-router/lib/dom/ssr/routeModules.ts @@ -18,19 +18,84 @@ export interface RouteModules { [routeId: string]: RouteModule | undefined; } +/** + * The shape of a route module shipped to the client + */ export interface RouteModule { + /** + * Action function called only in the browser. Route client loaders provide + * data to route components in addition to, or in place of, route loaders. + */ clientAction?: ClientActionFunction; + /** + * Like route actions but only called in the browser. + */ clientLoader?: ClientLoaderFunction; + /** + * When other route module APIs throw, the route module `ErrorBoundary` will + * render instead of the route component. + */ ErrorBoundary?: ErrorBoundaryComponent; + /** + * On initial page load, the route component renders only after the client + * loader is finished. If exported, a `HydrateFallback` can render + * immediately in place of the route component. + */ HydrateFallback?: HydrateFallbackComponent; + /** + * The `Layout` export is only applicable to the root route. Because the root + * route manages the document for all routes, it supports an additional optional + * `Layout` export that will be wrapped around the rendered UI, which may come + * from the default `Component` export, the `ErrorBoundary`, or the `HydrateFallback` + */ Layout?: LayoutComponent; + /** + * Defines the component that will render when the route matches. + */ default: RouteComponent; + /** + * Route handle allows apps to add anything to a route match in `useMatches` + * to create abstractions (like breadcrumbs, etc.). + */ handle?: RouteHandle; + /** + * Route links define [`` element][link-element]s to be rendered in the + * document ``. + */ links?: LinksFunction; + /** + * Route meta defines meta tags to be rendered in the `` of the document. + */ meta?: MetaFunction; + /** + * By default, all routes are revalidated after actions. This function allows + * a route to opt-out of revalidation for actions that don't affect its data. + */ shouldRevalidate?: ShouldRevalidateFunction; } +/** + * The shape of a route module file for your application + */ +export interface ServerRouteModule extends RouteModule { + /** + * Route actions allow server-side data mutations with automatic revalidation + * of all loader data on the page when called from `
`, `useFetcher`, + * and `useSubmit`. + * */ + action?: ActionFunction; + /** + * Route headers define HTTP headers to be sent with the response when server rendering. + */ + headers?: HeadersFunction | { [name: string]: string }; + /** + * Route loaders provide data to route components before they are rendered. + * They are only called on the server when server rendering or during the + * build with pre-rendering. + */ + loader?: LoaderFunction; +} + /** * A function that handles data mutations for a route on the client */ @@ -66,6 +131,24 @@ export type ClientLoaderFunctionArgs = LoaderFunctionArgs & { */ export type ErrorBoundaryComponent = ComponentType; +/** + * Parameters passed to the [`headers`]{@link HeadersFunction} function + */ +export type HeadersArgs = { + loaderHeaders: Headers; + parentHeaders: Headers; + actionHeaders: Headers; + errorHeaders: Headers | undefined; +}; + +/** + * A function that returns HTTP headers to be used for a route. These headers + * will be merged with (and take precedence over) headers from parent routes. + */ +export interface HeadersFunction { + (args: HeadersArgs): Headers | HeadersInit; +} + /** * `` component to render on initial loads * when client loaders are present diff --git a/packages/react-router/lib/server-runtime/entry.ts b/packages/react-router/lib/server-runtime/entry.ts index b4895260e6..1dae91fd6c 100644 --- a/packages/react-router/lib/server-runtime/entry.ts +++ b/packages/react-router/lib/server-runtime/entry.ts @@ -1,14 +1,14 @@ +import type { RouteModules } from "../dom/ssr/routeModules"; import type { ServerRouteManifest } from "./routes"; -import type { RouteModules, EntryRouteModule } from "./routeModules"; export function createEntryRouteModules( manifest: ServerRouteManifest -): RouteModules { +): RouteModules { return Object.keys(manifest).reduce((memo, routeId) => { let route = manifest[routeId]; if (route) { memo[routeId] = route.module; } return memo; - }, {} as RouteModules); + }, {} as RouteModules); } diff --git a/packages/react-router/lib/server-runtime/routeModules.ts b/packages/react-router/lib/server-runtime/routeModules.ts deleted file mode 100644 index 18e03a1b85..0000000000 --- a/packages/react-router/lib/server-runtime/routeModules.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { ActionFunction, LoaderFunction } from "../router/utils"; -import type { - ClientActionFunction, - ClientLoaderFunction, - LinksFunction, - MetaFunction, -} from "../dom/ssr/routeModules"; - -export interface RouteModules { - [routeId: string]: RouteModule | undefined; -} - -export type HeadersArgs = { - loaderHeaders: Headers; - parentHeaders: Headers; - actionHeaders: Headers; - errorHeaders: Headers | undefined; -}; - -/** - * A function that returns HTTP headers to be used for a route. These headers - * will be merged with (and take precedence over) headers from parent routes. - */ -export interface HeadersFunction { - (args: HeadersArgs): Headers | HeadersInit; -} - -type LdJsonObject = { [Key in string]: LdJsonValue } & { - [Key in string]?: LdJsonValue | undefined; -}; -type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[]; -type LdJsonPrimitive = string | number | boolean | null; -type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray; - -/** - * An arbitrary object that is associated with a route. - */ -export type RouteHandle = unknown; - -export interface EntryRouteModule { - clientAction?: ClientActionFunction; - clientLoader?: ClientLoaderFunction; - ErrorBoundary?: any; // Weakly typed because server-runtime is not React-aware - HydrateFallback?: any; // Weakly typed because server-runtime is not React-aware - Layout?: any; // Weakly typed because server-runtime is not React-aware - default: any; // Weakly typed because server-runtime is not React-aware - handle?: RouteHandle; - links?: LinksFunction; - meta?: MetaFunction; -} - -export interface ServerRouteModule extends EntryRouteModule { - action?: ActionFunction; - headers?: HeadersFunction | { [name: string]: string }; - loader?: LoaderFunction; -} diff --git a/packages/react-router/lib/server-runtime/routes.ts b/packages/react-router/lib/server-runtime/routes.ts index cb090db81b..e9d4bf7dc7 100644 --- a/packages/react-router/lib/server-runtime/routes.ts +++ b/packages/react-router/lib/server-runtime/routes.ts @@ -6,8 +6,8 @@ import type { } from "../router/utils"; import { callRouteHandler } from "./data"; import type { FutureConfig } from "../dom/ssr/entry"; +import type { ServerRouteModule } from "../dom/ssr/routeModules"; import type { Route } from "../dom/ssr/routes"; -import type { ServerRouteModule } from "./routeModules"; import type { SingleFetchResult, SingleFetchResults, From 5bddcce4e0265d0205d54e3f673231b9e8c594c9 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Mon, 16 Dec 2024 12:45:16 -0500 Subject: [PATCH 2/2] Add cross-links to route modules docs page --- docs/start/framework/route-module.md | 69 +++++++++++++++---- .../react-router/lib/dom/ssr/routeModules.ts | 39 +++-------- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/docs/start/framework/route-module.md b/docs/start/framework/route-module.md index 52b31b1923..5baa95af80 100644 --- a/docs/start/framework/route-module.md +++ b/docs/start/framework/route-module.md @@ -23,6 +23,8 @@ Route modules are the foundation of React Router's framework features, they defi This guide is a quick overview of every route module feature. The rest of the getting started guides will cover these features in more detail. +For additional details, please refer to the API documentation for a [Route Module][route-module] + ## Component (`default`) Defines the component that will render when the route matches. @@ -40,6 +42,10 @@ export default function MyRouteComponent() { } ``` +See also: + +- [`default` export Component props][component-props] + ## `loader` Route loaders provide data to route components before they are rendered. They are only called on the server when server rendering or during the build with pre-rendering. @@ -130,6 +136,10 @@ export async function action({ request }) { } ``` +See also: + +- [`action` params][action-params] + ## `clientAction` Like route actions but only called in the browser. @@ -157,9 +167,7 @@ import { useRouteError, } from "react-router"; -export function ErrorBoundary() { - const error = useRouteError(); - +export function ErrorBoundary({ error }) { if (isRouteErrorResponse(error)) { return (
@@ -184,6 +192,12 @@ export function ErrorBoundary() { } ``` +See also: + +- [`ErrorBoundary` props][errorboundary-props] +- [`isRouteErorResponse` docs][is-route-error-response] +- [React Error Boundaries docs][error-boundaries] + ## `HydrateFallback` On initial page load, the route component renders only after the client loader is finished. If exported, a `HydrateFallback` can render immediately in place of the route component. @@ -203,9 +217,13 @@ export default function Component({ loaderData }) { } ``` +See also: + +- [`HydrateFallback` props][hydratefallback-props] + ## `headers` -Route headers define HTTP headers to be sent with the response when server rendering. +Route headers define HTTP [headers] to be sent with the response when server rendering. ```tsx export function headers() { @@ -216,6 +234,11 @@ export function headers() { } ``` +See also: + +- [`headers` params][headers-params] +- [`Cache-Control` header][cache-control-header] + ## `handle` Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.). @@ -226,6 +249,11 @@ export const handle = { }; ``` +See also: + +- [`handle` docs][handle] +- [`useMatches` docs][use-matches] + ## `links` Route links define [`` element][link-element]s to be rendered in the document ``. @@ -269,9 +297,13 @@ export default function Root() { } ``` +See also: + +- [`links` params][links-params] + ## `meta` -Route meta defines meta tags to be rendered in the `` of the document. +Route meta defines [``][meta-element] tags to be rendered in the `` of the document. ```tsx export function meta() { @@ -307,7 +339,7 @@ export default function Root() { } ``` -**See also** +See also: - [`meta` params][meta-params] @@ -325,22 +357,31 @@ export function shouldRevalidate( } ``` +See also: + +- [`shouldRevalidate` params][shouldrevalidate-params] + --- Next: [Rendering Strategies](./rendering) -[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API -[loader-params]: https://api.reactrouter.com/v7/interfaces/react_router.LoaderFunctionArgs -[client-loader-params]: https://api.reactrouter.com/v7/types/react_router.ClientLoaderFunctionArgs -[action-params]: https://api.reactrouter.com/v7/interfaces/react_router.ActionFunctionArgs -[client-action-params]: https://api.reactrouter.com/v7/types/react_router.ClientActionFunctionArgs [error-boundaries]: https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary -[use-route-error]: https://api.reactrouter.com/v7/functions/react_router.useRouteError [is-route-error-response]: https://api.reactrouter.com/v7/functions/react_router.isRouteErrorResponse [cache-control-header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control [headers]: https://developer.mozilla.org/en-US/docs/Web/API/Response [use-matches]: https://api.reactrouter.com/v7/functions/react_router.useMatches [link-element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link [meta-element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta -[meta-params]: https://api.reactrouter.com/v7/interfaces/react_router.MetaArgs -[use-revalidator]: https://api.reactrouter.com/v7/functions/react_router.useRevalidator.html +[route-module]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html +[component-props]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#default +[loader-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#loader +[client-loader-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#clientLoader +[action-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#actioin +[client-action-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#clientAction +[meta-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#meta +[links-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#links +[handle]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#handle +[errorboundary-props]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#ErrorBoundary +[hydratefallback-props]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#HydrateFallback +[headers-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#headers +[shouldrevalidate-params]: https://api.reactrouter.com/v7/interfaces/react_router.ServerRouteModule.html#shouldRevalidate diff --git a/packages/react-router/lib/dom/ssr/routeModules.ts b/packages/react-router/lib/dom/ssr/routeModules.ts index f4efed0433..6a0b80e5a6 100644 --- a/packages/react-router/lib/dom/ssr/routeModules.ts +++ b/packages/react-router/lib/dom/ssr/routeModules.ts @@ -1,4 +1,4 @@ -import type { ComponentType, ReactElement } from "react"; +import type * as React from "react"; import type { Location } from "../../router/history"; import type { ActionFunction, @@ -32,16 +32,14 @@ export interface RouteModule { */ clientLoader?: ClientLoaderFunction; /** - * When other route module APIs throw, the route module `ErrorBoundary` will - * render instead of the route component. + * ErrorBoundary to display for this route */ - ErrorBoundary?: ErrorBoundaryComponent; + ErrorBoundary?: React.ComponentType; /** - * On initial page load, the route component renders only after the client - * loader is finished. If exported, a `HydrateFallback` can render - * immediately in place of the route component. + * `` component to render on initial loads + * when client loaders are present */ - HydrateFallback?: HydrateFallbackComponent; + HydrateFallback?: React.ComponentType; /** * The `Layout` export is only applicable to the root route. Because the root * route manages the document for all routes, it supports an additional optional @@ -52,7 +50,7 @@ export interface RouteModule { /** * Defines the component that will render when the route matches. */ - default: RouteComponent; + default: React.ComponentType<{}>; /** * Route handle allows apps to add anything to a route match in `useMatches` * to create abstractions (like breadcrumbs, etc.). @@ -126,11 +124,6 @@ export type ClientLoaderFunctionArgs = LoaderFunctionArgs & { serverLoader: () => Promise>; }; -/** - * ErrorBoundary to display for this route - */ -export type ErrorBoundaryComponent = ComponentType; - /** * Parameters passed to the [`headers`]{@link HeadersFunction} function */ @@ -149,22 +142,13 @@ export interface HeadersFunction { (args: HeadersArgs): Headers | HeadersInit; } -/** - * `` component to render on initial loads - * when client loaders are present - */ -export type HydrateFallbackComponent = ComponentType; - /** * Optional, root-only `` component to wrap the root content in. * Useful for defining the // document shell shared by the * Component, HydrateFallback, and ErrorBoundary */ -export type LayoutComponent = ComponentType<{ - children: ReactElement< - unknown, - ErrorBoundaryComponent | HydrateFallbackComponent | RouteComponent - >; +export type LayoutComponent = React.ComponentType<{ + children: React.ReactElement; }>; /** @@ -301,11 +285,6 @@ type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[]; type LdJsonPrimitive = string | number | boolean | null; type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray; -/** - * A React component that is rendered for a route. - */ -export type RouteComponent = ComponentType<{}>; - /** * An arbitrary object that is associated with a route. *