Skip to content

Commit

Permalink
Deprecate CatchBoundary in favor of future.v2_errorBoundary
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Mar 8, 2023
1 parent 96813db commit aeae4b7
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 5 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
28 changes: 24 additions & 4 deletions packages/remix-dev/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,10 @@ export async function readConfig(
warnOnce(serverBuildTargetWarning, "v2_serverBuildTarget");
}

if (!appConfig.future?.v2_errorBoundary) {
warnOnce(errorBoundaryWarning, "v2_errorBoundary");
}

let isCloudflareRuntime = ["cloudflare-pages", "cloudflare-workers"].includes(
appConfig.serverBuildTarget ?? ""
);
Expand Down Expand Up @@ -726,11 +730,27 @@ const resolveServerBuildPath = (

// @ts-expect-error available in node 12+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat#browser_compatibility
let listFormat = new Intl.ListFormat("en", {
const listFormat = new Intl.ListFormat("en", {
style: "long",
type: "conjunction",
});

export let serverBuildTargetWarning = `⚠️ DEPRECATED: The "serverBuildTarget" config option is deprecated. Use a combination of "publicPath", "serverBuildPath", "serverConditions", "serverDependenciesToBundle", "serverMainFields", "serverMinify", "serverModuleFormat" and/or "serverPlatform" instead.`;

export let flatRoutesWarning = `⚠️ DEPRECATED: The old nested folders route convention has been deprecated in favor of "flat routes". Please enable the new routing convention via the \`future.v2_routeConvention\` flag in your \`remix.config.js\` file. For more information, please see https://remix.run/docs/en/main/file-conventions/route-files-v2.`;
export const serverBuildTargetWarning =
'⚠️ DEPRECATED: The "serverBuildTarget" config option is deprecated. Use a ' +
'combination of "publicPath", "serverBuildPath", "serverConditions", ' +
'"serverDependenciesToBundle", "serverMainFields", "serverMinify", ' +
'"serverModuleFormat" and/or "serverPlatform" instead.';

export const flatRoutesWarning =
"⚠️ DEPRECATED: The old nested folders route convention has been deprecated " +
'in favor of "flat routes". Please enable the new routing convention via the ' +
"`future.v2_routeConvention` flag in your `remix.config.js` file. For more " +
"information, please see https://remix.run/docs/en/main/file-conventions/route-files-v2.";

export const errorBoundaryWarning =
"⚠️ 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";
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 aeae4b7

Please sign in to comment.