From 65d3345cae8a1c3703b737f484096356f535fc21 Mon Sep 17 00:00:00 2001 From: Ryan Florence Date: Wed, 16 Aug 2023 13:01:58 -0600 Subject: [PATCH] feat(meta): add thrown `error` to the `meta` params (#7105) Co-authored-by: Matt Brophy --- .changeset/add-error-to-meta.md | 11 ++++++++ docs/route/meta.md | 10 +++++++ integration/meta-test.ts | 39 ++++++++++++++++++++++++++++ packages/remix-react/components.tsx | 15 ++++++----- packages/remix-react/routeModules.ts | 2 ++ 5 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 .changeset/add-error-to-meta.md diff --git a/.changeset/add-error-to-meta.md b/.changeset/add-error-to-meta.md new file mode 100644 index 00000000000..6d17a4f0756 --- /dev/null +++ b/.changeset/add-error-to-meta.md @@ -0,0 +1,11 @@ +--- +"@remix-run/react": patch +--- + +Add error to meta params so you can render error titles, etc. + +```tsx +export function meta({ error }) { + return [{ title: error.message }] +} +``` diff --git a/docs/route/meta.md b/docs/route/meta.md index 0abafbe963b..1ca7664a8fd 100644 --- a/docs/route/meta.md +++ b/docs/route/meta.md @@ -110,6 +110,16 @@ export const meta: MetaFunction = ({ The route's URL params. See [Dynamic Segments in the Routing Guide][url-params]. +### `error` + +Thrown errors that trigger error boundaries will be passed to the `meta` function. This is useful for generating metadata for error pages. + +```tsx +export const meta: MetaFunction = ({ error }) => { + return [{ title: error ? "oops!" : "Actual title" }]; +}; +``` + ## Accessing Data from Parent Route Loaders In addition to the current route's data, often you'll want to access data from a route higher up in the route hierarchy. You can look it up by its route ID in `matches`. diff --git a/integration/meta-test.ts b/integration/meta-test.ts index 2d3afc52fe1..40e1321741f 100644 --- a/integration/meta-test.ts +++ b/integration/meta-test.ts @@ -149,6 +149,26 @@ test.describe("meta", () => { return

Music

; } `, + + "app/routes/error.tsx": js` + import { Link, useRouteError } from '@remix-run/react' + + export function loader() { + throw new Error('lol oops') + } + + export const meta = (args) => { + return [{ title: args.error ? "Oops!" : "Home"}] + } + + export default function Error() { + return

Error

+ } + + export function ErrorBoundary() { + return

Error boundary

+ } + `, }, }); appFixture = await createAppFixture(fixture); @@ -231,4 +251,23 @@ test.describe("meta", () => { await app.goto("/authors/1"); expect(await app.getHtml('link[rel="canonical"]')).toBeTruthy(); }); + + test("loader errors are passed to meta", async ({ page }) => { + let restoreErrors = hideErrors(); + + new PlaywrightFixture(appFixture, page); + let response = await fixture.requestDocument("/error"); + expect(await response.text()).toMatch("Oops!"); + + restoreErrors(); + }); }); + +function hideErrors() { + let oldConsoleError: any; + oldConsoleError = console.error; + console.error = () => {}; + return () => { + console.error = oldConsoleError; + }; +} diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx index e14aed26339..48d1017219b 100644 --- a/packages/remix-react/components.tsx +++ b/packages/remix-react/components.tsx @@ -482,12 +482,13 @@ export function Meta() { } = useDataRouterStateContext(); let location = useLocation(); - let _matches = errors - ? routerMatches.slice( - 0, - routerMatches.findIndex((m) => errors![m.route.id]) + 1 - ) - : routerMatches; + let _matches: AgnosticDataRouteMatch[] = routerMatches; + let error: any = null; + if (errors) { + let errorIdx = routerMatches.findIndex((m) => errors![m.route.id]); + _matches = routerMatches.slice(0, errorIdx + 1); + error = errors[routerMatches[errorIdx].route.id]; + } let meta: MetaDescriptor[] = []; let leafMeta: MetaDescriptor[] | null = null; @@ -507,6 +508,7 @@ export function Meta() { params: _match.params, pathname: _match.pathname, handle: _match.route.handle, + error, }; matches[i] = match; @@ -518,6 +520,7 @@ export function Meta() { params, location, matches, + error, }) : Array.isArray(routeModule.meta) ? [...routeModule.meta] diff --git a/packages/remix-react/routeModules.ts b/packages/remix-react/routeModules.ts index ff63ec03bb7..621276375e7 100644 --- a/packages/remix-react/routeModules.ts +++ b/packages/remix-react/routeModules.ts @@ -51,6 +51,7 @@ export interface MetaMatch< handle?: unknown; params: DataRouteMatch["params"]; meta: MetaDescriptor[]; + error?: unknown; } export type MetaMatches< @@ -74,6 +75,7 @@ export interface MetaArgs< params: Params; location: Location; matches: MetaMatches; + error?: unknown; } export interface MetaFunction<