Skip to content

Commit

Permalink
Deprecate CatchBoundary in favor of future.v2_errorBoundary (remix-ru…
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 authored and fernandojbf committed Mar 21, 2023
1 parent b2d4fa1 commit 97696de
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .changeset/three-cheetahs-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@remix-run/dev": patch
"@remix-run/react": patch
"@remix-run/server-runtime": patch
---

Deprecate `CatchBoundary` in favor of `future.v2_errorBoundary`
4 changes: 4 additions & 0 deletions docs/route/catch-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ title: CatchBoundary

# `CatchBoundary`

<docs-warning>The separation of `CatchBoundary` and `ErrorBoundary` has been deprecated and Remix v2 will use a singular `ErrorBoundary` for all thrown Responses and Errors. It is recommended that you opt-into the new behavior in Remix v1 via the `future.v2_errorBoundary` flag in your `remix.config.js` file. Please refer to the [ErrorBoundary (v2)][error-boundary-v2] docs for more information.</docs-warning>

A `CatchBoundary` is a React component that renders whenever an action or loader throws a `Response`.

**Note:** We use the word "catch" to represent the codepath taken when a `Response` type is thrown; you thought about bailing from the "happy path". This is different from an uncaught error you did not expect to occur.
Expand All @@ -29,3 +31,5 @@ export function CatchBoundary() {
);
}
```

[error-boundary-v2]: ./error-boundary-v2
11 changes: 11 additions & 0 deletions docs/route/error-boundary-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: ErrorBoundary (v2)
---

# `ErrorBoundary (v2)`

<docs-info>You can opt into the Remix v2 `ErrorBoundary` behavior via the `future.v2_errorBoundary` flag in your `remix.config.js`</docs-info>

If you export an `ErrorBoundary` component from your route module, it will be used as the React Router [`errorElement`][rr-error-element] and will render if you throw from a loader/action or if React throws during rendering your Route component.

[rr-error-element]: https://reactrouter.com/route/error-element
3 changes: 3 additions & 0 deletions docs/route/error-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ title: ErrorBoundary

# `ErrorBoundary`

<docs-warning>The separation of `CatchBoundary` and `ErrorBoundary` has been deprecated and Remix v2 will use a singular `ErrorBoundary` for all thrown Responses and Errors. It is recommended that you opt-into the new behavior in Remix v1 via the `future.v2_errorBoundary` flag in your `remix.config.js` file. Please refer to the [ErrorBoundary (v2)][error-boundary-v2] docs for more information.</docs-warning>

An `ErrorBoundary` is a React component that renders whenever there is an error anywhere on the route, either during rendering or during data loading.

**Note:** We use the word "error" to mean an uncaught exception; something you didn't anticipate happening. This is different from other types of "errors" that you are able to recover from easily, for example a 404 error where you can still show something in the user interface to indicate you weren't able to find some data.
Expand All @@ -26,3 +28,4 @@ export function ErrorBoundary({ error }) {
```

[error-boundaries]: https://reactjs.org/docs/error-boundaries.html
[error-boundary-v2]: ./error-boundary-v2
5 changes: 4 additions & 1 deletion integration/action-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ test.describe("actions", () => {

test.beforeAll(async () => {
fixture = await createFixture({
future: { v2_routeConvention: true },
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
},
files: {
"app/routes/urlencoded.jsx": js`
import { Form, useActionData } from "@remix-run/react";
Expand Down
9 changes: 4 additions & 5 deletions integration/defer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ test.describe("non-aborted", () => {

test.beforeAll(async () => {
fixture = await createFixture({
future: { v2_routeConvention: true },
////////////////////////////////////////////////////////////////////////////
// 💿 Next, add files to this object, just like files in a real app,
// `createFixture` will make an app and run your tests against it.
////////////////////////////////////////////////////////////////////////////
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
},
files: {
"app/components/counter.tsx": js`
import { useState } from "react";
Expand Down
1 change: 1 addition & 0 deletions integration/hmr-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ let fixture = (options: { port: number; appServerPort: number }) => ({
},
unstable_tailwind: true,
v2_routeConvention: true,
v2_errorBoundary: true,
},
files: {
"package.json": json({
Expand Down
13 changes: 13 additions & 0 deletions packages/remix-react/browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { deserializeErrors } from "./errors";
import type { RouteModules } from "./routeModules";
import { createClientRoutes } from "./routes";
import { warnOnce } from "./warnings";

/* eslint-disable prefer-let/prefer-let */
declare global {
Expand Down Expand Up @@ -138,6 +139,18 @@ if (import.meta && import.meta.hot) {
*/
export function RemixBrowser(_props: RemixBrowserProps): ReactElement {
if (!router) {
if (!window.__remixContext.future.v2_errorBoundary) {
warnOnce(
false,
"⚠️ DEPRECATED: The separation of `CatchBoundary` and `ErrorBoundary` has " +
"been deprecated and Remix v2 will use a singular `ErrorBoundary` for " +
"all thrown values (`Response` and `Error`). Please migrate to the new " +
"behavior in Remix v1 via the `future.v2_errorBoundary` flag in your " +
"`remix.config.js` file. For more information, see " +
"https://remix.run/docs/route/error-boundary-v2"
);
}

let routes = createClientRoutes(
window.__remixManifest.routes,
window.__remixRouteModules,
Expand Down
2 changes: 2 additions & 0 deletions packages/remix-react/errorBoundaries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ let RemixCatchContext = React.createContext<ThrownResponse | undefined>(
/**
* Returns the status code and thrown response data.
*
* @deprecated Please enable the v2_errorBoundary flag
*
* @see https://remix.run/route/catch-boundary
*/
export function useCatch<
Expand Down
4 changes: 4 additions & 0 deletions packages/remix-react/routeModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ export interface RouteModule {
/**
* A React component that is rendered when the server throws a Response.
*
* @deprecated Please enable the v2_errorBoundary flag
*
* @see https://remix.run/route/catch-boundary
*/
export type CatchBoundaryComponent = ComponentType<{}>;

/**
* A React component that is rendered when there is an error on a route.
*
* @deprecated Please enable the v2_errorBoundary flag
*
* @see https://remix.run/route/error-boundary
*/
export type ErrorBoundaryComponent = ComponentType<{ error: Error }>;
Expand Down
13 changes: 12 additions & 1 deletion packages/remix-server-runtime/routeModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,25 @@ export interface ActionFunction {

/**
* A React component that is rendered when the server throws a Response.
*
* @deprecated Please enable the v2_errorBoundary flag
*/
export type CatchBoundaryComponent = ComponentType;

/**
* A React component that is rendered when there is an error on a route.
*
* @deprecated Please enable the v2_errorBoundary flag
*/
export type ErrorBoundaryComponent = ComponentType<{ error: Error }>;

/**
* V2 version of the ErrorBoundary that eliminates the distinction between
* Error and Catch Boundaries and behaves like RR 6.4 errorElement and captures
* errors with useRouteError()
*/
export type V2_ErrorBoundaryComponent = ComponentType;

/**
* 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.
Expand Down Expand Up @@ -224,7 +235,7 @@ export type RouteHandle = any;

export interface EntryRouteModule {
CatchBoundary?: CatchBoundaryComponent;
ErrorBoundary?: ErrorBoundaryComponent;
ErrorBoundary?: ErrorBoundaryComponent | V2_ErrorBoundaryComponent;
default: RouteComponent;
handle?: RouteHandle;
links?: LinksFunction;
Expand Down

0 comments on commit 97696de

Please sign in to comment.