@nrwl/remix 13.7.1 → 14.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +2 -2
  2. package/generators.json +25 -0
  3. package/package.json +1 -1
  4. package/src/generators/action/action.impl.d.ts +3 -0
  5. package/src/generators/action/action.impl.js +48 -0
  6. package/src/generators/action/action.impl.js.map +1 -0
  7. package/src/generators/action/schema.d.ts +4 -0
  8. package/src/generators/action/schema.json +27 -0
  9. package/src/generators/application/files/.gitignore__tmpl__ +4 -0
  10. package/src/generators/application/files/app/entry.client.tsx__tmpl__ +2 -2
  11. package/src/generators/application/files/app/entry.server.tsx__tmpl__ +4 -4
  12. package/src/generators/application/files/app/root.tsx__tmpl__ +10 -156
  13. package/src/generators/application/files/app/routes/index.tsx__tmpl__ +28 -96
  14. package/src/generators/application/files/package.json__tmpl__ +1 -1
  15. package/src/generators/application/files/remix.config.js__tmpl__ +7 -7
  16. package/src/generators/application/files/tsconfig.json__tmpl__ +6 -1
  17. package/src/generators/cypress/cypress.impl.js +3 -3
  18. package/src/generators/cypress/cypress.impl.js.map +1 -1
  19. package/src/generators/loader/loader.impl.d.ts +3 -0
  20. package/src/generators/loader/loader.impl.js +48 -0
  21. package/src/generators/loader/loader.impl.js.map +1 -0
  22. package/src/generators/loader/schema.d.ts +4 -0
  23. package/src/generators/loader/schema.json +27 -0
  24. package/src/generators/meta/meta.impl.d.ts +3 -0
  25. package/src/generators/meta/meta.impl.js +29 -0
  26. package/src/generators/meta/meta.impl.js.map +1 -0
  27. package/src/generators/meta/schema.d.ts +4 -0
  28. package/src/generators/meta/schema.json +27 -0
  29. package/src/generators/resource-route/resource-route.impl.d.ts +3 -0
  30. package/src/generators/resource-route/resource-route.impl.js +32 -0
  31. package/src/generators/resource-route/resource-route.impl.js.map +1 -0
  32. package/src/generators/resource-route/schema.d.ts +6 -0
  33. package/src/generators/resource-route/schema.json +44 -0
  34. package/src/generators/route/route.impl.js +37 -61
  35. package/src/generators/route/route.impl.js.map +1 -1
  36. package/src/generators/route/schema.d.ts +3 -0
  37. package/src/generators/route/schema.json +24 -9
  38. package/src/generators/style/schema.d.ts +4 -0
  39. package/src/generators/style/schema.json +34 -0
  40. package/src/generators/style/style.impl.d.ts +3 -0
  41. package/src/generators/style/style.impl.js +41 -0
  42. package/src/generators/style/style.impl.js.map +1 -0
  43. package/src/utils/get-default-export-name.d.ts +2 -0
  44. package/src/utils/get-default-export-name.js +10 -0
  45. package/src/utils/get-default-export-name.js.map +1 -0
  46. package/src/utils/get-default-export.d.ts +2 -0
  47. package/src/utils/get-default-export.js +16 -0
  48. package/src/utils/get-default-export.js.map +1 -0
  49. package/src/utils/insert-import.d.ts +4 -0
  50. package/src/utils/insert-import.js +55 -0
  51. package/src/utils/insert-import.js.map +1 -0
  52. package/src/utils/insert-statement-after-imports.d.ts +5 -0
  53. package/src/utils/insert-statement-after-imports.js +29 -0
  54. package/src/utils/insert-statement-after-imports.js.map +1 -0
  55. package/src/utils/insert-statement-in-default-function.d.ts +2 -0
  56. package/src/utils/insert-statement-in-default-function.js +24 -0
  57. package/src/utils/insert-statement-in-default-function.js.map +1 -0
  58. package/src/utils/remix-route-utils.d.ts +11 -0
  59. package/src/utils/remix-route-utils.js +53 -0
  60. package/src/utils/remix-route-utils.js.map +1 -0
  61. package/src/generators/application/files/app/routes/demos/about/index.tsx__tmpl__ +0 -17
  62. package/src/generators/application/files/app/routes/demos/about/whoa.tsx__tmpl__ +0 -20
  63. package/src/generators/application/files/app/routes/demos/about.tsx__tmpl__ +0 -44
  64. package/src/generators/application/files/app/routes/demos/actions.tsx__tmpl__ +0 -101
  65. package/src/generators/application/files/app/routes/demos/correct.tsx__tmpl__ +0 -3
  66. package/src/generators/application/files/app/routes/demos/params/$id.tsx__tmpl__ +0 -110
  67. package/src/generators/application/files/app/routes/demos/params/index.tsx__tmpl__ +0 -40
  68. package/src/generators/application/files/app/routes/demos/params.tsx__tmpl__ +0 -43
  69. package/src/generators/application/files/app/styles/dark.css +0 -7
  70. package/src/generators/application/files/app/styles/demos/about.css +0 -26
  71. package/src/generators/application/files/app/styles/global.css +0 -216
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insert-statement-after-imports.js","sourceRoot":"","sources":["../../../../../packages/remix/src/utils/insert-statement-after-imports.ts"],"names":[],"mappings":";;;AAAA,yCAAsE;AACtE,2CAIoB;AAEpB;;GAEG;AACH,SAAgB,2BAA2B,CACzC,IAAU,EACV,IAAY,EACZ,SAAiB;IAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE1C,MAAM,UAAU,GAAG,IAAA,6BAAgB,EAAC,IAAI,EAAE,QAAQ,EAAE,yBAAY,CAAC,MAAM,CAAC,CAAC;IAEzE,MAAM,gBAAgB,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,gCAAmB,CAAC,CAAC;IAC3E,MAAM,KAAK,GACT,gBAAgB,CAAC,MAAM,GAAG,CAAC;QACzB,CAAC,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE;QACxD,CAAC,CAAC,CAAC,CAAC;IAER,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;QAC/B,SAAS,GAAG,KAAK,SAAS,EAAE,CAAC;KAC9B;IAED,MAAM,WAAW,GAAG,IAAA,6BAAoB,EAAC,QAAQ,EAAE;QACjD;YACE,IAAI,EAAE,mBAAU,CAAC,MAAM;YACvB,KAAK;YACL,IAAI,EAAE,SAAS;SAChB;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AA5BD,kEA4BC"}
@@ -0,0 +1,2 @@
1
+ import { Tree } from '@nrwl/devkit';
2
+ export declare function insertStatementInDefaultFunction(tree: Tree, path: string, statement: any): void;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.insertStatementInDefaultFunction = void 0;
4
+ const devkit_1 = require("@nrwl/devkit");
5
+ const get_default_export_1 = require("./get-default-export");
6
+ function insertStatementInDefaultFunction(tree, path, statement) {
7
+ const defaultExport = (0, get_default_export_1.getDefaultExport)(tree, path);
8
+ if (!defaultExport) {
9
+ throw Error('No default export found!');
10
+ }
11
+ const index = defaultExport.body.statements.length > 0
12
+ ? defaultExport.body.statements[0].pos
13
+ : 0;
14
+ const newContents = (0, devkit_1.applyChangesToString)(tree.read(path, 'utf-8'), [
15
+ {
16
+ type: devkit_1.ChangeType.Insert,
17
+ index,
18
+ text: statement,
19
+ },
20
+ ]);
21
+ tree.write(path, newContents);
22
+ }
23
+ exports.insertStatementInDefaultFunction = insertStatementInDefaultFunction;
24
+ //# sourceMappingURL=insert-statement-in-default-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insert-statement-in-default-function.js","sourceRoot":"","sources":["../../../../../packages/remix/src/utils/insert-statement-in-default-function.ts"],"names":[],"mappings":";;;AAAA,yCAAsE;AACtE,6DAAwD;AAExD,SAAgB,gCAAgC,CAC9C,IAAU,EACV,IAAY,EACZ,SAAS;IAET,MAAM,aAAa,GAAG,IAAA,qCAAgB,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAEnD,IAAI,CAAC,aAAa,EAAE;QAClB,MAAM,KAAK,CAAC,0BAA0B,CAAC,CAAC;KACzC;IAED,MAAM,KAAK,GACT,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QACtC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;QACtC,CAAC,CAAC,CAAC,CAAC;IAER,MAAM,WAAW,GAAG,IAAA,6BAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;QACjE;YACE,IAAI,EAAE,mBAAU,CAAC,MAAM;YACvB,KAAK;YACL,IAAI,EAAE,SAAS;SAChB;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AAzBD,4EAyBC"}
@@ -0,0 +1,11 @@
1
+ import { Tree } from '@nrwl/devkit';
2
+ /**
3
+ *
4
+ * @param tree
5
+ * @param path to the route which could be fully specified or just "foo/bar"
6
+ * @param projectName the name of the project where the route should be added
7
+ * @param fileExtension the file extension to add to resolved route file
8
+ * @returns file path to the route
9
+ */
10
+ export declare function resolveRemixRouteFile(tree: Tree, path: string, projectName: string, fileExtension?: string): string;
11
+ export declare function normalizeRoutePath(path: string, projectRoot: string): string;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeRoutePath = exports.resolveRemixRouteFile = void 0;
4
+ const devkit_1 = require("@nrwl/devkit");
5
+ /**
6
+ *
7
+ * @param tree
8
+ * @param path to the route which could be fully specified or just "foo/bar"
9
+ * @param projectName the name of the project where the route should be added
10
+ * @param fileExtension the file extension to add to resolved route file
11
+ * @returns file path to the route
12
+ */
13
+ function resolveRemixRouteFile(tree, path, projectName, fileExtension) {
14
+ const project = (0, devkit_1.readProjectConfiguration)(tree, projectName);
15
+ if (!project)
16
+ throw new Error(`Project does not exist: ${projectName}`);
17
+ const { fileName: routePath } = (0, devkit_1.names)(path.replace(/^\//, '').replace(/\/$/, ''));
18
+ const normalizedRoutePath = normalizeRoutePath(routePath, project.root);
19
+ // if no file extension specified, let's try to find it
20
+ if (!fileExtension) {
21
+ // see if the path already has it
22
+ const extensionMatch = path.match(/(\.[^.]+)$/);
23
+ if (extensionMatch) {
24
+ fileExtension = extensionMatch[0];
25
+ }
26
+ else {
27
+ // look for either .ts or .tsx to exist in tree
28
+ if (tree.exists(`${normalizedRoutePath}.ts`)) {
29
+ fileExtension = '.ts';
30
+ }
31
+ else {
32
+ // default to .tsx if nothing else found
33
+ fileExtension = '.tsx';
34
+ }
35
+ }
36
+ }
37
+ const fileName = normalizedRoutePath.endsWith(fileExtension)
38
+ ? normalizedRoutePath
39
+ : `${normalizedRoutePath}${fileExtension}`;
40
+ // TODO: what if someone changes the Remix app root folder in the remix.config.js?
41
+ const routeFilePath = (0, devkit_1.joinPathFragments)(project.root, 'app/routes', fileName);
42
+ return routeFilePath;
43
+ }
44
+ exports.resolveRemixRouteFile = resolveRemixRouteFile;
45
+ function normalizeRoutePath(path, projectRoot) {
46
+ if (path.indexOf(projectRoot) === -1)
47
+ return path;
48
+ if (path.indexOf('/routes/') > -1)
49
+ return path.substring(path.indexOf('/routes/') + 8);
50
+ return path.substring(projectRoot.length + 1);
51
+ }
52
+ exports.normalizeRoutePath = normalizeRoutePath;
53
+ //# sourceMappingURL=remix-route-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remix-route-utils.js","sourceRoot":"","sources":["../../../../../packages/remix/src/utils/remix-route-utils.ts"],"names":[],"mappings":";;;AAAA,yCAKsB;AAEtB;;;;;;;GAOG;AACH,SAAgB,qBAAqB,CACnC,IAAU,EACV,IAAY,EACZ,WAAmB,EACnB,aAAsB;IAEtB,MAAM,OAAO,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,WAAW,EAAE,CAAC,CAAC;IACxE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAA,cAAK,EACnC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAC3C,CAAC;IACF,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAExE,uDAAuD;IACvD,IAAI,CAAC,aAAa,EAAE;QAClB,iCAAiC;QACjC,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAEhD,IAAI,cAAc,EAAE;YAClB,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;SACnC;aAAM;YACL,+CAA+C;YAC/C,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,mBAAmB,KAAK,CAAC,EAAE;gBAC5C,aAAa,GAAG,KAAK,CAAC;aACvB;iBAAM;gBACL,wCAAwC;gBACxC,aAAa,GAAG,MAAM,CAAC;aACxB;SACF;KACF;IAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC1D,CAAC,CAAC,mBAAmB;QACrB,CAAC,CAAC,GAAG,mBAAmB,GAAG,aAAa,EAAE,CAAC;IAC7C,kFAAkF;IAClF,MAAM,aAAa,GAAG,IAAA,0BAAiB,EAAC,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC9E,OAAO,aAAa,CAAC;AACvB,CAAC;AArCD,sDAqCC;AAED,SAAgB,kBAAkB,CAAC,IAAY,EAAE,WAAmB;IAClE,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC;AALD,gDAKC"}
@@ -1,17 +0,0 @@
1
- import { Link } from "remix";
2
-
3
- export default function AboutIndex() {
4
- return (
5
- <div>
6
- <p>
7
- You are looking at the index route for the <code>/about</code> URL
8
- segment, but there are nested routes as well!
9
- </p>
10
- <p>
11
- <strong>
12
- <Link to="whoa">Check out one of them here.</Link>
13
- </strong>
14
- </p>
15
- </div>
16
- );
17
- }
@@ -1,20 +0,0 @@
1
- import { Link } from "remix";
2
-
3
- export default function AboutIndex() {
4
- return (
5
- <div>
6
- <p>
7
- Whoa, this is a nested route! We render the <code>/about</code> layout
8
- route component, and its <code>Outlet</code> renders our route
9
- component. 🤯
10
- </p>
11
- <p>
12
- <strong>
13
- <Link to="..">
14
- Go back to the <code>/about</code> index.
15
- </Link>
16
- </strong>
17
- </p>
18
- </div>
19
- );
20
- }
@@ -1,44 +0,0 @@
1
- import { Outlet } from "remix";
2
- import type { MetaFunction, LinksFunction } from "remix";
3
-
4
- import stylesUrl from "~/styles/demos/about.css";
5
-
6
- export let meta: MetaFunction = () => {
7
- return {
8
- title: "About Remix"
9
- };
10
- };
11
-
12
- export let links: LinksFunction = () => {
13
- return [{ rel: "stylesheet", href: stylesUrl }];
14
- };
15
-
16
- export default function Index() {
17
- return (
18
- <div className="about">
19
- <div className="about__intro">
20
- <h2>About Us</h2>
21
- <p>
22
- Ok, so this page isn't really <em>about us</em>, but we did want to
23
- show you a few more things Remix can do.
24
- </p>
25
- <p>
26
- Did you notice that things look a little different on this page? The
27
- CSS that we import in the route file and include in its{" "}
28
- <code>links</code> export is only included on this route and its
29
- children.
30
- </p>
31
- <p>
32
- Wait a sec...<em>its children</em>? To understand what we mean by
33
- this,{" "}
34
- <a href="https://remix.run/tutorial/4-nested-routes-params">
35
- read all about nested routes in the docs
36
- </a>
37
- .
38
- </p>
39
- <hr />
40
- <Outlet />
41
- </div>
42
- </div>
43
- );
44
- }
@@ -1,101 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- import type { ActionFunction } from "remix";
3
- import { Form, json, useActionData, redirect } from "remix";
4
-
5
- export function meta() {
6
- return { title: "Actions Demo" };
7
- }
8
-
9
- // When your form sends a POST, the action is called on the server.
10
- // - https://remix.run/api/conventions#action
11
- // - https://remix.run/guides/data-updates
12
- export let action: ActionFunction = async ({ request }) => {
13
- let formData = await request.formData();
14
- let answer = formData.get("answer");
15
-
16
- // Typical action workflows start with validating the form data that just came
17
- // over the network. Clientside validation is fine, but you definitely need it
18
- // server side. If there's a problem, return the the data and the component
19
- // can render it.
20
- if (typeof answer !== "string") {
21
- return json("Come on, at least try!", { status: 400 });
22
- }
23
-
24
- if (answer !== "egg") {
25
- return json(`Sorry, ${answer} is not right.`, { status: 400 });
26
- }
27
-
28
- // Finally, if the data is valid, you'll typically write to a database or send or
29
- // email or log the user in, etc. It's recommended to redirect after a
30
- // successful action, even if it's to the same place so that non-JavaScript workflows
31
- // from the browser doesn't repost the data if the user clicks back.
32
- return redirect("/demos/correct");
33
- };
34
-
35
- export default function ActionsDemo() {
36
- // https://remix.run/api/remix#useactiondata
37
- let actionMessage = useActionData<string>();
38
- let answerRef = useRef<HTMLInputElement>(null);
39
-
40
- // This form works without JavaScript, but when we have JavaScript we can make
41
- // the experience better by selecting the input on wrong answers! Go ahead, disable
42
- // JavaScript in your browser and see what happens.
43
- useEffect(() => {
44
- if (actionMessage && answerRef.current) {
45
- answerRef.current.select();
46
- }
47
- }, [actionMessage]);
48
-
49
- return (
50
- <div className="remix__page">
51
- <main>
52
- <h2>Actions!</h2>
53
- <p>
54
- This form submission will send a post request that we handle in our
55
- `action` export. Any route can export an action to handle data
56
- mutations.
57
- </p>
58
- <Form method="post" className="remix__form">
59
- <h3>Post an Action</h3>
60
- <p>
61
- <i>What is more useful when it is broken?</i>
62
- </p>
63
- <label>
64
- <div>Answer:</div>
65
- <input ref={answerRef} name="answer" type="text" />
66
- </label>
67
- <div>
68
- <button>Answer!</button>
69
- </div>
70
- {actionMessage ? (
71
- <p>
72
- <b>{actionMessage}</b>
73
- </p>
74
- ) : null}
75
- </Form>
76
- </main>
77
-
78
- <aside>
79
- <h3>Additional Resources</h3>
80
- <ul>
81
- <li>
82
- Guide:{" "}
83
- <a href="https://remix.run/guides/data-writes">Data Writes</a>
84
- </li>
85
- <li>
86
- API:{" "}
87
- <a href="https://remix.run/api/conventions#action">
88
- Route Action Export
89
- </a>
90
- </li>
91
- <li>
92
- API:{" "}
93
- <a href="https://remix.run/api/remix#useactiondata">
94
- <code>useActionData</code>
95
- </a>
96
- </li>
97
- </ul>
98
- </aside>
99
- </div>
100
- );
101
- }
@@ -1,3 +0,0 @@
1
- export default function NiceWork() {
2
- return <h1>You got it right!</h1>;
3
- }
@@ -1,110 +0,0 @@
1
- import { useCatch, Link, json, useLoaderData } from "remix";
2
- import type { LoaderFunction, MetaFunction } from "remix";
3
-
4
- // The `$` in route filenames becomes a pattern that's parsed from the URL and
5
- // passed to your loaders so you can look up data.
6
- // - https://remix.run/api/conventions#loader-params
7
- export let loader: LoaderFunction = async ({ params }) => {
8
- // pretend like we're using params.id to look something up in the db
9
-
10
- if (params.id === "this-record-does-not-exist") {
11
- // If the record doesn't exist we can't render the route normally, so
12
- // instead we throw a 404 reponse to stop running code here and show the
13
- // user the catch boundary.
14
- throw new Response("Not Found", { status: 404 });
15
- }
16
-
17
- // now pretend like the record exists but the user just isn't authorized to
18
- // see it.
19
- if (params.id === "shh-its-a-secret") {
20
- // Again, we can't render the component if the user isn't authorized. You
21
- // can even put data in the response that might help the user rectify the
22
- // issue! Like emailing the webmaster for access to the page. (Oh, right,
23
- // `json` is just a Response helper that makes it easier to send JSON
24
- // responses).
25
- throw json({ webmasterEmail: "hello@remix.run" }, { status: 401 });
26
- }
27
-
28
- // Sometimes your code just blows up and you never anticipated it. Remix will
29
- // automatically catch it and send the UI to the error boundary.
30
- if (params.id === "kaboom") {
31
- lol();
32
- }
33
-
34
- // but otherwise the record was found, user has access, so we can do whatever
35
- // else we needed to in the loader and return the data. (This is boring, we're
36
- // just gonna return the params.id).
37
- return { param: params.id };
38
- };
39
-
40
- export default function ParamDemo() {
41
- let data = useLoaderData();
42
- return (
43
- <h1>
44
- The param is <i style={{ color: "red" }}>{data.param}</i>
45
- </h1>
46
- );
47
- }
48
-
49
- // https://remix.run/api/conventions#catchboundary
50
- // https://remix.run/api/remix#usecatch
51
- // https://remix.run/api/guides/not-found
52
- export function CatchBoundary() {
53
- let caught = useCatch();
54
-
55
- let message: React.ReactNode;
56
- switch (caught.status) {
57
- case 401:
58
- message = (
59
- <p>
60
- Looks like you tried to visit a page that you do not have access to.
61
- Maybe ask the webmaster ({caught.data.webmasterEmail}) for access.
62
- </p>
63
- );
64
- case 404:
65
- message = (
66
- <p>Looks like you tried to visit a page that does not exist.</p>
67
- );
68
- default:
69
- message = (
70
- <p>
71
- There was a problem with your request!
72
- <br />
73
- {caught.status} {caught.statusText}
74
- </p>
75
- );
76
- }
77
-
78
- return (
79
- <>
80
- <h2>Oops!</h2>
81
- <p>{message}</p>
82
- <p>
83
- (Isn't it cool that the user gets to stay in context and try a different
84
- link in the parts of the UI that didn't blow up?)
85
- </p>
86
- </>
87
- );
88
- }
89
-
90
- // https://remix.run/api/conventions#errorboundary
91
- // https://remix.run/api/guides/not-found
92
- export function ErrorBoundary({ error }: { error: Error }) {
93
- console.error(error);
94
- return (
95
- <>
96
- <h2>Error!</h2>
97
- <p>{error.message}</p>
98
- <p>
99
- (Isn't it cool that the user gets to stay in context and try a different
100
- link in the parts of the UI that didn't blow up?)
101
- </p>
102
- </>
103
- );
104
- }
105
-
106
- export let meta: MetaFunction = ({ data }) => {
107
- return {
108
- title: data ? `Param: ${data.param}` : "Oops...",
109
- };
110
- };
@@ -1,40 +0,0 @@
1
- import { useCatch, Link, json, useLoaderData, Outlet } from "remix";
2
- import type { LoaderFunction } from "remix";
3
-
4
- export default function Boundaries() {
5
- return (
6
- <>
7
- <h2>Params</h2>
8
- <p>
9
- When you name a route segment with $ like{" "}
10
- <code>routes/users/$userId.js</code>, the $ segment will be parsed from
11
- the URL and sent to your loaders and actions by the same name.
12
- </p>
13
- <h2>Errors</h2>
14
- <p>
15
- When a route throws and error in it's action, loader, or component,
16
- Remix automatically catches it, won't even try to render the component,
17
- but it will render the route's ErrorBoundary instead. If the route
18
- doesn't have one, it will bubble up to the routes above it until it hits
19
- the root.
20
- </p>
21
- <p>So be as granular as you want with your error handling.</p>
22
- <h2>Not Found</h2>
23
- <p>
24
- (and other{" "}
25
- <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses">
26
- client errors
27
- </a>
28
- )
29
- </p>
30
- <p>
31
- Loaders and Actions can throw a <code>Response</code> instead of an
32
- error and Remix will render the CatchBoundary instead of the component.
33
- This is great when loading data from a database isn't found. As soon as
34
- you know you can't render the component normally, throw a 404 response
35
- and send your app into the catch boundary. Just like error boundaries,
36
- catch boundaries bubble, too.
37
- </p>
38
- </>
39
- );
40
- }
@@ -1,43 +0,0 @@
1
- import { useCatch, Link, json, useLoaderData, Outlet } from "remix";
2
-
3
- export function meta() {
4
- return { title: "Boundaries Demo" };
5
- }
6
-
7
- export default function Boundaries() {
8
- return (
9
- <div className="remix__page">
10
- <main>
11
- <Outlet />
12
- </main>
13
-
14
- <aside>
15
- <h2>Click these Links</h2>
16
- <ul>
17
- <li>
18
- <Link to=".">Start over</Link>
19
- </li>
20
- <li>
21
- <Link to="one">
22
- Param: <i>one</i>
23
- </Link>
24
- </li>
25
- <li>
26
- <Link to="two">
27
- Param: <i>two</i>
28
- </Link>
29
- </li>
30
- <li>
31
- <Link to="this-record-does-not-exist">This will be a 404</Link>
32
- </li>
33
- <li>
34
- <Link to="shh-its-a-secret">And this will be 401 Unauthorized</Link>
35
- </li>
36
- <li>
37
- <Link to="kaboom">This one will throw an error</Link>
38
- </li>
39
- </ul>
40
- </aside>
41
- </div>
42
- );
43
- }
@@ -1,7 +0,0 @@
1
- :root {
2
- --color-foreground: hsl(0, 0%, 100%);
3
- --color-background: hsl(0, 0%, 7%);
4
- --color-links: hsl(213, 100%, 73%);
5
- --color-links-hover: hsl(213, 100%, 80%);
6
- --color-border: hsl(0, 0%, 25%);
7
- }
@@ -1,26 +0,0 @@
1
- /*
2
- * Whoa whoa whoa, wait a sec...why are we overriding global CSS selectors?
3
- * Isn't that kind of scary? How do we know this won't have side effects?
4
- *
5
- * In Remix, CSS that is included in a route file will *only* show up on that
6
- * route (and for nested routes, its children). When the user navigates away
7
- * from that route the CSS files linked from those routes will be automatically
8
- * unloaded, making your styles much easier to predict and control.
9
- *
10
- * Read more about styling routes in the docs:
11
- * https://remix.run/guides/styling
12
- */
13
-
14
- :root {
15
- --color-foreground: hsl(0, 0%, 7%);
16
- --color-background: hsl(56, 100%, 50%);
17
- --color-links: hsl(345, 56%, 39%);
18
- --color-links-hover: hsl(345, 51%, 49%);
19
- --color-border: rgb(184, 173, 20);
20
- --font-body: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
21
- Liberation Mono, Courier New, monospace;
22
- }
23
-
24
- .about__intro {
25
- max-width: 500px;
26
- }