Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 461534e

Browse files
authoredSep 5, 2024··
Merge pull request #11957 from remix-run/pedro/params-and-data-as-props
`params`, `loaderData`, and `actionData` as props for route component exports
2 parents 59736e5 + b81f121 commit 461534e

File tree

10 files changed

+208
-493
lines changed

10 files changed

+208
-493
lines changed
 

‎integration/error-boundary-test.ts

Lines changed: 0 additions & 250 deletions
Original file line numberDiff line numberDiff line change
@@ -655,256 +655,6 @@ test.describe("ErrorBoundary", () => {
655655
});
656656
});
657657

658-
test.describe("loaderData in ErrorBoundary", () => {
659-
let fixture: Fixture;
660-
let appFixture: AppFixture;
661-
let consoleErrors: string[];
662-
let oldConsoleError: () => void;
663-
664-
test.beforeAll(async () => {
665-
fixture = await createFixture({
666-
files: {
667-
"app/root.tsx": js`
668-
import { Links, Meta, Outlet, Scripts } from "react-router";
669-
670-
export default function Root() {
671-
return (
672-
<html lang="en">
673-
<head>
674-
<Meta />
675-
<Links />
676-
</head>
677-
<body>
678-
<main>
679-
<Outlet />
680-
</main>
681-
<Scripts />
682-
</body>
683-
</html>
684-
);
685-
}
686-
`,
687-
688-
"app/routes/parent.tsx": js`
689-
import { Outlet, useLoaderData, useMatches, useRouteError } from "react-router";
690-
691-
export function loader() {
692-
return "PARENT";
693-
}
694-
695-
export default function () {
696-
return (
697-
<div>
698-
<p id="parent-data">{useLoaderData()}</p>
699-
<Outlet />
700-
</div>
701-
)
702-
}
703-
704-
export function ErrorBoundary() {
705-
let error = useRouteError();
706-
return (
707-
<>
708-
<p id="parent-data">{useLoaderData()}</p>
709-
<p id="parent-matches-data">
710-
{useMatches().find(m => m.id === 'routes/parent').data}
711-
</p>
712-
<p id="parent-error">{error.message}</p>
713-
</>
714-
);
715-
}
716-
`,
717-
718-
"app/routes/parent.child-with-boundary.tsx": js`
719-
import { Form, useLoaderData, useRouteError } from "react-router";
720-
721-
export function loader() {
722-
return "CHILD";
723-
}
724-
725-
export function action() {
726-
throw new Error("Broken!");
727-
}
728-
729-
export default function () {
730-
return (
731-
<>
732-
<p id="child-data">{useLoaderData()}</p>
733-
<Form method="post">
734-
<button type="submit" name="key" value="value">
735-
Submit
736-
</button>
737-
</Form>
738-
</>
739-
)
740-
}
741-
742-
export function ErrorBoundary() {
743-
let error = useRouteError();
744-
return (
745-
<>
746-
<p id="child-data">{useLoaderData()}</p>
747-
<p id="child-error">{error.message}</p>
748-
</>
749-
);
750-
}
751-
`,
752-
753-
"app/routes/parent.child-without-boundary.tsx": js`
754-
import { Form, useLoaderData } from "react-router";
755-
756-
export function loader() {
757-
return "CHILD";
758-
}
759-
760-
export function action() {
761-
throw new Error("Broken!");
762-
}
763-
764-
export default function () {
765-
return (
766-
<>
767-
<p id="child-data">{useLoaderData()}</p>
768-
<Form method="post">
769-
<button type="submit" name="key" value="value">
770-
Submit
771-
</button>
772-
</Form>
773-
</>
774-
)
775-
}
776-
`,
777-
},
778-
});
779-
780-
appFixture = await createAppFixture(fixture, ServerMode.Development);
781-
});
782-
783-
test.afterAll(() => {
784-
appFixture.close();
785-
});
786-
787-
test.beforeEach(({ page }) => {
788-
oldConsoleError = console.error;
789-
console.error = () => {};
790-
consoleErrors = [];
791-
// Listen for all console events and handle errors
792-
page.on("console", (msg) => {
793-
if (msg.type() === "error") {
794-
consoleErrors.push(msg.text());
795-
}
796-
});
797-
});
798-
799-
test.afterEach(() => {
800-
console.error = oldConsoleError;
801-
});
802-
803-
test.describe("without JavaScript", () => {
804-
test.use({ javaScriptEnabled: false });
805-
runBoundaryTests();
806-
});
807-
808-
test.describe("with JavaScript", () => {
809-
test.use({ javaScriptEnabled: true });
810-
runBoundaryTests();
811-
});
812-
813-
function runBoundaryTests() {
814-
test("Prevents useLoaderData in self ErrorBoundary", async ({
815-
page,
816-
javaScriptEnabled,
817-
}) => {
818-
let app = new PlaywrightFixture(appFixture, page);
819-
await app.goto("/parent/child-with-boundary");
820-
821-
expect(await app.getHtml("#parent-data")).toEqual(
822-
'<p id="parent-data">PARENT</p>'
823-
);
824-
expect(await app.getHtml("#child-data")).toEqual(
825-
'<p id="child-data">CHILD</p>'
826-
);
827-
expect(consoleErrors).toEqual([]);
828-
829-
await app.clickSubmitButton("/parent/child-with-boundary");
830-
await page.waitForSelector("#child-error");
831-
832-
expect(await app.getHtml("#child-error")).toEqual(
833-
'<p id="child-error">Broken!</p>'
834-
);
835-
expect(await app.getHtml("#parent-data")).toEqual(
836-
'<p id="parent-data">PARENT</p>'
837-
);
838-
expect(await app.getHtml("#child-data")).toEqual(
839-
'<p id="child-data"></p>'
840-
);
841-
842-
// Only look for this message. Chromium browsers will also log the
843-
// network error but firefox does not
844-
// "Failed to load resource: the server responded with a status of 500 (Internal Server Error)",
845-
let msg =
846-
"You cannot `useLoaderData` in an errorElement (routeId: routes/parent.child-with-boundary)";
847-
if (javaScriptEnabled) {
848-
expect(consoleErrors.filter((m) => m === msg)).toEqual([msg]);
849-
} else {
850-
// We don't get the useLoaderData message in the client when JS is disabled
851-
expect(consoleErrors.filter((m) => m === msg)).toEqual([]);
852-
}
853-
});
854-
855-
test("Prevents useLoaderData in bubbled ErrorBoundary", async ({
856-
page,
857-
javaScriptEnabled,
858-
}) => {
859-
let app = new PlaywrightFixture(appFixture, page);
860-
await app.goto("/parent/child-without-boundary");
861-
862-
expect(await app.getHtml("#parent-data")).toEqual(
863-
'<p id="parent-data">PARENT</p>'
864-
);
865-
expect(await app.getHtml("#child-data")).toEqual(
866-
'<p id="child-data">CHILD</p>'
867-
);
868-
expect(consoleErrors).toEqual([]);
869-
870-
await app.clickSubmitButton("/parent/child-without-boundary");
871-
await page.waitForSelector("#parent-error");
872-
873-
expect(await app.getHtml("#parent-error")).toEqual(
874-
'<p id="parent-error">Broken!</p>'
875-
);
876-
if (javaScriptEnabled) {
877-
// This data remains in single fetch with JS because we don't revalidate
878-
// due to the 500 action response
879-
expect(await app.getHtml("#parent-matches-data")).toEqual(
880-
'<p id="parent-matches-data">PARENT</p>'
881-
);
882-
} else {
883-
// But without JS document requests call all loaders up to the
884-
// boundary route so parent's data clears out
885-
expect(await app.getHtml("#parent-matches-data")).toEqual(
886-
'<p id="parent-matches-data"></p>'
887-
);
888-
}
889-
expect(await app.getHtml("#parent-data")).toEqual(
890-
'<p id="parent-data"></p>'
891-
);
892-
893-
// Only look for this message. Chromium browsers will also log the
894-
// network error but firefox does not
895-
// "Failed to load resource: the server responded with a status of 500 (Internal Server Error)",
896-
let msg =
897-
"You cannot `useLoaderData` in an errorElement (routeId: routes/parent)";
898-
if (javaScriptEnabled) {
899-
expect(consoleErrors.filter((m) => m === msg)).toEqual([msg]);
900-
} else {
901-
// We don't get the useLoaderData message in the client when JS is disabled
902-
expect(consoleErrors.filter((m) => m === msg)).toEqual([]);
903-
}
904-
});
905-
}
906-
});
907-
908658
test.describe("Default ErrorBoundary", () => {
909659
let fixture: Fixture;
910660
let appFixture: AppFixture;
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/consistent-type-imports */
22
import type { NodePath } from "@babel/traverse";
3-
import type { types as BabelTypes } from "@babel/core";
4-
import { parse } from "@babel/parser";
3+
import type { types as Babel } from "@babel/core";
4+
import { parse, type ParseResult } from "@babel/parser";
55
import * as t from "@babel/types";
66

77
// These `require`s were needed to support building within vite-ecosystem-ci,
@@ -12,4 +12,4 @@ const generate = require("@babel/generator")
1212
.default as typeof import("@babel/generator").default;
1313

1414
export { traverse, generate, parse, t };
15-
export type { BabelTypes, NodePath };
15+
export type { Babel, NodePath, ParseResult };

‎packages/react-router-dev/vite/plugin.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import colors from "picocolors";
2929
import { type RouteManifestEntry, type RouteManifest } from "../config/routes";
3030
import type { Manifest as ReactRouterManifest } from "../manifest";
3131
import invariant from "../invariant";
32+
import { generate, parse } from "./babel";
3233
import type { NodeRequestHandler } from "./node-adapter";
3334
import { fromNodeRequest, toNodeRequest } from "./node-adapter";
3435
import { getStylesForUrl, isCssModulesFile } from "./styles";
@@ -44,6 +45,7 @@ import {
4445
resolveEntryFiles,
4546
resolvePublicPath,
4647
} from "./config";
48+
import { withProps } from "./with-props";
4749

4850
export async function resolveViteConfig({
4951
configFile,
@@ -1263,7 +1265,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
12631265
{
12641266
name: "react-router-route-entry",
12651267
enforce: "pre",
1266-
async transform(code, id, options) {
1268+
async transform(_code, id, options) {
12671269
if (!isRouteEntry(id)) return;
12681270
let routeModuleId = id.replace(ROUTE_ENTRY_QUERY_STRING, "");
12691271

@@ -1450,7 +1452,10 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
14501452

14511453
let [filepath] = id.split("?");
14521454

1453-
return removeExports(code, SERVER_ONLY_ROUTE_EXPORTS, {
1455+
let ast = parse(code, { sourceType: "module" });
1456+
removeExports(ast, SERVER_ONLY_ROUTE_EXPORTS);
1457+
withProps(ast);
1458+
return generate(ast, {
14541459
sourceMaps: true,
14551460
filename: id,
14561461
sourceFileName: filepath,
@@ -1586,7 +1591,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
15861591
}
15871592
}
15881593

1589-
server.ws.send({
1594+
server.hot.send({
15901595
type: "custom",
15911596
event: "react-router:hmr",
15921597
data: hmrEventData,

0 commit comments

Comments
 (0)
Please sign in to comment.