Skip to content

Commit 7db49e8

Browse files
Support RSC lazy default export as Component fallback (#13763)
1 parent a417996 commit 7db49e8

File tree

16 files changed

+60
-41
lines changed

16 files changed

+60
-41
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export function Component() {
1+
export default function HomeRoute() {
22
return <h2>Home</h2>;
33
}

integration/rsc/rsc-test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ implementations.forEach((implementation) => {
109109
export function loader() {
110110
return { message: "Loader Data" };
111111
}
112-
export function Component({ loaderData }) {
112+
export default function HomeRoute({ loaderData }) {
113113
return <h2 data-home>Home: {loaderData.message}</h2>;
114114
}
115115
`,
@@ -141,7 +141,7 @@ implementations.forEach((implementation) => {
141141
return { message: "Loader Data" };
142142
}
143143
144-
export function Component({ loaderData }) {
144+
export default function HomeRoute({ loaderData }) {
145145
return (
146146
<div>
147147
<h2 data-home>Home: {loaderData.message}</h2>
@@ -236,7 +236,7 @@ implementations.forEach((implementation) => {
236236
return { message: "Home Page Data" };
237237
}
238238
239-
export function Component({ loaderData }) {
239+
export default function HomeRoute({ loaderData }) {
240240
return (
241241
<div>
242242
<h1 data-page="home">Home Page</h1>
@@ -251,7 +251,7 @@ implementations.forEach((implementation) => {
251251
return { count: 1 };
252252
}
253253
254-
export { Component } from "./dashboard.client";
254+
export { default } from "./dashboard.client";
255255
`,
256256
"src/routes/dashboard.client.tsx": js`
257257
"use client";
@@ -260,7 +260,7 @@ implementations.forEach((implementation) => {
260260
import { Link } from "react-router";
261261
262262
// Export the entire route as a client component
263-
export function Component({ loaderData }) {
263+
export default function DashboardRoute({ loaderData }) {
264264
const [count, setCount] = useState(loaderData.count);
265265
266266
return (
@@ -367,7 +367,7 @@ implementations.forEach((implementation) => {
367367
return { message: "Home Page Data" };
368368
}
369369
370-
export function Component({ loaderData }) {
370+
export default function HomeRoute({ loaderData }) {
371371
return (
372372
<div>
373373
<h1 data-page="home">Home Page</h1>
@@ -477,7 +477,7 @@ implementations.forEach((implementation) => {
477477
}
478478
`,
479479
"src/routes/home.tsx": js`
480-
export { Component } from "./home.client";
480+
export { default } from "./home.client";
481481
`,
482482
"src/routes/home.client.tsx": js`
483483
"use client";
@@ -486,7 +486,7 @@ implementations.forEach((implementation) => {
486486
487487
import { incrementCounter } from "./home.actions";
488488
489-
export function Component() {
489+
export default function HomeRoute() {
490490
const [count, incrementCounterAction, incrementing] = useActionState(incrementCounter, 0);
491491
492492
return (
@@ -547,7 +547,7 @@ implementations.forEach((implementation) => {
547547
return { name, count };
548548
}
549549
550-
export function Component({ loaderData }) {
550+
export default function HomeRoute({ loaderData }) {
551551
const updateCounter = async (formData: FormData) => {
552552
"use server";
553553
name = formData.get("name");
@@ -624,7 +624,7 @@ implementations.forEach((implementation) => {
624624
import { redirectAction } from "./home.actions";
625625
import { Counter } from "./home.client";
626626
627-
export function Component(props) {
627+
export default function HomeRoute(props) {
628628
console.log({props});
629629
return (
630630
<div>
@@ -697,7 +697,7 @@ implementations.forEach((implementation) => {
697697
throw new Error("Intentional error from loader");
698698
}
699699
700-
export function Component() {
700+
export default function HomeRoute() {
701701
return <h2>This shouldn't render</h2>;
702702
}
703703

packages/react-router/lib/rsc/server.rsc.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type ServerRouteObjectBase = {
3333
action?: ActionFunction;
3434
clientAction?: ClientActionFunction;
3535
clientLoader?: ClientLoaderFunction;
36-
Component?: React.ComponentType<any>;
3736
ErrorBoundary?: React.ComponentType<any>;
3837
handle?: any;
3938
headers?: HeadersFunction;
@@ -48,7 +47,20 @@ type ServerRouteObjectBase = {
4847
export type ServerRouteObject = ServerRouteObjectBase & {
4948
id: string;
5049
path?: string;
51-
lazy?: () => Promise<ServerRouteObjectBase>;
50+
Component?: React.ComponentType<any>;
51+
lazy?: () => Promise<
52+
ServerRouteObjectBase &
53+
(
54+
| {
55+
default?: React.ComponentType<any>;
56+
Component?: never;
57+
}
58+
| {
59+
default?: never;
60+
Component?: React.ComponentType<any>;
61+
}
62+
)
63+
>;
5264
} & (
5365
| {
5466
index: true;
@@ -578,17 +590,8 @@ async function getServerRouteMatch(
578590
shouldRenderComponent: boolean,
579591
parentId: string | undefined
580592
) {
581-
if ("lazy" in match.route && match.route.lazy) {
582-
Object.assign(match.route, {
583-
// @ts-expect-error - FIXME: Fix the types here
584-
...((await match.route.lazy()) as any),
585-
path: match.route.path,
586-
index: (match.route as any).index,
587-
id: match.route.id,
588-
});
589-
match.route.lazy = undefined;
590-
}
591-
593+
// @ts-expect-error - FIXME: Fix the types here
594+
await explodeLazyRoute(match.route);
592595
const Layout = (match.route as any).Layout || React.Fragment;
593596
const Component = (match.route as any).Component;
594597
const ErrorBoundary = (match.route as any).ErrorBoundary;
@@ -712,9 +715,25 @@ async function getManifestRoute(
712715

713716
async function explodeLazyRoute(route: ServerRouteObject) {
714717
if ("lazy" in route && route.lazy) {
715-
let impl = (await route.lazy()) as any;
716-
for (let [k, v] of Object.entries(impl)) {
717-
route[k as keyof ServerRouteObject] = v;
718+
let {
719+
default: lazyDefaultExport,
720+
Component: lazyComponentExport,
721+
...lazyProperties
722+
} = (await route.lazy()) as any;
723+
let Component = lazyComponentExport || lazyDefaultExport;
724+
if (Component && !route.Component) {
725+
route.Component = Component;
726+
}
727+
for (let [k, v] of Object.entries(lazyProperties)) {
728+
if (
729+
k !== "id" &&
730+
k !== "path" &&
731+
k !== "index" &&
732+
k !== "children" &&
733+
route[k as keyof ServerRouteObject] == null
734+
) {
735+
route[k as keyof ServerRouteObject] = v;
736+
}
718737
}
719738
route.lazy = undefined;
720739
}

playground/rsc-parcel/src/routes/about/about.client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function clientLoader({ serverLoader }: ClientLoaderFunctionArgs) {
1515
};
1616
}
1717

18-
export function Component() {
18+
export default function AboutRoute() {
1919
const { client, message } = useLoaderData<typeof clientLoader>();
2020

2121
return (

playground/rsc-parcel/src/routes/about/about.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { clientLoader, Component } from "./about.client";
1+
export { clientLoader, default } from "./about.client";
22

33
export function loader() {
44
return {

playground/rsc-parcel/src/routes/fetcher/fetcher.client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useFetcher } from "react-router";
44
import type { loader } from "../resource/resource";
55

6-
export function Component() {
6+
export default function FetcherRoute() {
77
const fetcher = useFetcher<typeof loader>();
88

99
return (
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { Component } from "./fetcher.client";
1+
export { default } from "./fetcher.client";

playground/rsc-parcel/src/routes/home/home.client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function clientLoader({ serverLoader }: ClientLoaderFunctionArgs) {
1515
};
1616
}
1717

18-
export function Component() {
18+
export default function HomeRoute() {
1919
const { client, message } = useLoaderData<typeof clientLoader>();
2020

2121
return (

playground/rsc-parcel/src/routes/home/home.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { clientLoader, Component } from "./home.client";
1+
export { clientLoader, default } from "./home.client";
22

33
export function loader() {
44
return {

playground/rsc-parcel/src/routes/root/root.client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
2727
);
2828
}
2929

30-
export function Component() {
30+
export default function RootRoute() {
3131
const { counter, message } = useLoaderData<typeof loader>();
3232
return (
3333
<>

0 commit comments

Comments
 (0)