Skip to content

Commit f0b8d0a

Browse files
authored
refactor(catch-boundary): Switch to V2 + Vite (#511)
1 parent 86c9a39 commit f0b8d0a

19 files changed

+248
-151
lines changed

catch-boundary/.eslintrc.js

-4
This file was deleted.

catch-boundary/app/routes/users.$userId.tsx

-64
This file was deleted.

catch-boundary/package.json

-29
This file was deleted.

catch-boundary/remix.config.js

-11
This file was deleted.

catch-boundary/remix.env.d.ts

-2
This file was deleted.

catch-boundary/tsconfig.json

-22
This file was deleted.

error-boundary/.eslintrc.cjs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* This is intended to be a basic starting point for linting in your app.
3+
* It relies on recommended configs out of the box for simplicity, but you can
4+
* and should modify this configuration to best suit your team's needs.
5+
*/
6+
7+
/** @type {import('eslint').Linter.Config} */
8+
module.exports = {
9+
root: true,
10+
parserOptions: {
11+
ecmaVersion: "latest",
12+
sourceType: "module",
13+
ecmaFeatures: {
14+
jsx: true,
15+
},
16+
},
17+
env: {
18+
browser: true,
19+
commonjs: true,
20+
es6: true,
21+
},
22+
ignorePatterns: ["!**/.server", "!**/.client"],
23+
24+
// Base config
25+
extends: ["eslint:recommended"],
26+
27+
overrides: [
28+
// React
29+
{
30+
files: ["**/*.{js,jsx,ts,tsx}"],
31+
plugins: ["react", "jsx-a11y"],
32+
extends: [
33+
"plugin:react/recommended",
34+
"plugin:react/jsx-runtime",
35+
"plugin:react-hooks/recommended",
36+
"plugin:jsx-a11y/recommended",
37+
],
38+
settings: {
39+
react: {
40+
version: "detect",
41+
},
42+
formComponents: ["Form"],
43+
linkComponents: [
44+
{ name: "Link", linkAttribute: "to" },
45+
{ name: "NavLink", linkAttribute: "to" },
46+
],
47+
"import/resolver": {
48+
typescript: {},
49+
},
50+
},
51+
},
52+
53+
// Typescript
54+
{
55+
files: ["**/*.{ts,tsx}"],
56+
plugins: ["@typescript-eslint", "import"],
57+
parser: "@typescript-eslint/parser",
58+
settings: {
59+
"import/internal-regex": "^~/",
60+
"import/resolver": {
61+
node: {
62+
extensions: [".ts", ".tsx"],
63+
},
64+
typescript: {
65+
alwaysTryTypes: true,
66+
},
67+
},
68+
},
69+
extends: [
70+
"plugin:@typescript-eslint/recommended",
71+
"plugin:import/recommended",
72+
"plugin:import/typescript",
73+
],
74+
},
75+
76+
// Node
77+
{
78+
files: [".eslintrc.cjs"],
79+
env: {
80+
node: true,
81+
},
82+
},
83+
],
84+
};

catch-boundary/.gitignore renamed to error-boundary/.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ node_modules
22

33
/.cache
44
/build
5-
/public/build
65
.env
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# CatchBoundary Example
1+
# ErrorBoundary Example
22

3-
If you want to handle _expected_ errors, you use a `CatchBoundary` to catch those types of errors. Think about HTTP-400-level errors like unauthorized etc.
3+
If you want to handle errors, export an `ErrorBoundary` from your route.
44

55
## Preview
66

77
Open this example on [CodeSandbox](https://codesandbox.com):
88

9-
[![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/remix-run/examples/tree/main/catch-boundary)
9+
[![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/remix-run/examples/tree/main/error-boundary)
1010

1111
## Example
1212

13-
In this example, we have a list of users and one user that does not exist. When you navigate to the user that does not exist, our CatchBoundary renders in place of the component for that route.
13+
In this example, we have a list of users and one user that does not exist. When you navigate to the user that does not exist, our ErrorBoundary renders in place of the component for that route.
1414

15-
Check [app/routes/users/$userId.tsx](app/routes/users/$userId.tsx) to see the CatchBoundary in action.
15+
Check [app/routes/users/$userId.tsx](app/routes/users/$userId.tsx) to see the ErrorBoundary in action.
1616

1717
## Related Links
1818

19-
- [CatchBoundary in the Remix Docs](https://remix.run/route/catch-boundary)
19+
- [ErrorBoundary in the Remix Docs](https://remix.run/route/error-boundary)
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
1-
import type { MetaFunction } from "@remix-run/node";
21
import {
32
Links,
4-
LiveReload,
53
Meta,
64
Outlet,
75
Scripts,
86
ScrollRestoration,
97
} from "@remix-run/react";
108

11-
export const meta: MetaFunction = () => ({
12-
charset: "utf-8",
13-
title: "New Remix App",
14-
viewport: "width=device-width,initial-scale=1",
15-
});
16-
17-
export default function App() {
9+
export function Layout({ children }: { children: React.ReactNode }) {
1810
return (
1911
<html lang="en">
2012
<head>
13+
<meta charSet="utf-8" />
14+
<meta name="viewport" content="width=device-width, initial-scale=1" />
2115
<Meta />
2216
<Links />
2317
</head>
2418
<body>
25-
<Outlet />
19+
{children}
2620
<ScrollRestoration />
2721
<Scripts />
28-
<LiveReload />
2922
</body>
3023
</html>
3124
);
3225
}
26+
27+
export default function App() {
28+
return <Outlet />;
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
2+
import { json } from "@remix-run/node";
3+
import {
4+
isRouteErrorResponse,
5+
useLoaderData,
6+
useParams,
7+
useRouteError,
8+
} from "@remix-run/react";
9+
10+
import { getUsers } from "~/data.server";
11+
12+
export const meta: MetaFunction<typeof loader> = ({ data }) => {
13+
// Handle our 404 gracefully by setting a generic error as page title
14+
if (!data || !data.user) {
15+
return [{ title: "User not found!" }];
16+
}
17+
return [{ title: data.user.name }];
18+
};
19+
20+
export const loader = async ({ params }: LoaderFunctionArgs) => {
21+
const userId = params.userId;
22+
23+
const users = getUsers();
24+
const user = users.find(({ id }) => id === userId);
25+
26+
if (!user) {
27+
// When there's an expected error (like no found user) throw a response.
28+
throw new Response("Not Found", { status: 404 });
29+
}
30+
31+
return json({ user });
32+
};
33+
34+
export default function User() {
35+
const { user } = useLoaderData<typeof loader>();
36+
return <div>Hi there {user.name}!</div>;
37+
}
38+
39+
// Export an ErrorBoundary and use the useRouteError/isRouteErrorResponse
40+
// combo to handle thrown responses like the 404 we have in our loader.
41+
// You can also catch thrown responses from actions as well.
42+
export function ErrorBoundary() {
43+
const error = useRouteError();
44+
const params = useParams();
45+
46+
if (isRouteErrorResponse(error) && error.status === 404) {
47+
return (
48+
<span style={{ color: "red" }}>
49+
User with ID "{params.userId}" not found!
50+
</span>
51+
);
52+
}
53+
54+
console.error(error);
55+
56+
return (
57+
<div>
58+
<pre>{JSON.stringify(error, null, 2)}</pre>
59+
</div>
60+
);
61+
}

catch-boundary/app/routes/users.tsx renamed to error-boundary/app/routes/users.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Link, Outlet, useLoaderData } from "@remix-run/react";
55
import { getUsers } from "~/data.server";
66

77
export const meta: MetaFunction = () => {
8-
return { title: "Users" };
8+
return [{ title: "Users" }];
99
};
1010

1111
export const loader = async () => {

0 commit comments

Comments
 (0)