Skip to content

Commit 7d0d243

Browse files
authored
Restructure client route creation in preparation for client data (#8090)
1 parent 6a643ce commit 7d0d243

File tree

1 file changed

+93
-68
lines changed

1 file changed

+93
-68
lines changed

packages/remix-react/routes.tsx

+93-68
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import * as React from "react";
22
import { UNSAFE_ErrorResponseImpl as ErrorResponse } from "@remix-run/router";
33
import type {
4+
ActionFunctionArgs,
5+
LoaderFunctionArgs,
46
DataRouteObject,
57
ShouldRevalidateFunction,
68
} from "react-router-dom";
@@ -128,81 +130,104 @@ export function createClientRoutes(
128130
): DataRouteObject[] {
129131
return (routesByParentId[parentId] || []).map((route) => {
130132
let routeModule = routeModulesCache?.[route.id];
133+
134+
async function fetchServerLoader(request: Request) {
135+
if (!route.hasLoader) return null;
136+
return fetchServerHandler(request, route);
137+
}
138+
139+
async function fetchServerAction(request: Request) {
140+
if (!route.hasAction) {
141+
let msg =
142+
`Route "${route.id}" does not have an action, but you are trying ` +
143+
`to submit to it. To fix this, please add an \`action\` function to the route`;
144+
console.error(msg);
145+
throw new ErrorResponse(
146+
405,
147+
"Method Not Allowed",
148+
new Error(msg),
149+
true
150+
);
151+
}
152+
153+
return fetchServerHandler(request, route);
154+
}
155+
156+
async function callServerHandler(
157+
request: Request,
158+
handler: typeof fetchServerLoader | typeof fetchServerAction
159+
) {
160+
// Only prefetch links if we've been loaded into the cache, route.lazy
161+
// will handle initial loads
162+
let linkPrefetchPromise = routeModulesCache[route.id]
163+
? prefetchStyleLinks(route, routeModulesCache[route.id])
164+
: Promise.resolve();
165+
try {
166+
return handler(request);
167+
} finally {
168+
await linkPrefetchPromise;
169+
}
170+
}
171+
131172
let dataRoute: DataRouteObject = {
132173
id: route.id,
133174
index: route.index,
134175
path: route.path,
135-
async loader({ request }) {
136-
// Only prefetch links if we've been loaded into the cache, route.lazy
137-
// will handle initial loads
138-
let routeModulePromise = routeModulesCache[route.id]
139-
? prefetchStyleLinks(route, routeModulesCache[route.id])
140-
: Promise.resolve();
141-
try {
142-
if (!route.hasLoader) return null;
143-
return fetchServerHandler(request, route);
144-
} finally {
145-
await routeModulePromise;
146-
}
147-
},
148-
async action({ request }) {
149-
// Only prefetch links if we've been loaded into the cache, route.lazy
150-
// will handle initial loads
151-
let routeModulePromise = routeModulesCache[route.id]
152-
? prefetchStyleLinks(route, routeModulesCache[route.id])
153-
: Promise.resolve();
154-
try {
155-
if (!route.hasAction) {
156-
let msg =
157-
`Route "${route.id}" does not have an action, but you are trying ` +
158-
`to submit to it. To fix this, please add an \`action\` function to the route`;
159-
console.error(msg);
160-
return Promise.reject(
161-
new ErrorResponse(405, "Method Not Allowed", new Error(msg), true)
176+
loader: ({ request }: LoaderFunctionArgs) =>
177+
callServerHandler(request, () => fetchServerLoader(request)),
178+
action: ({ request }: ActionFunctionArgs) =>
179+
callServerHandler(request, () => fetchServerAction(request)),
180+
};
181+
182+
if (routeModule) {
183+
// Use critical path modules directly
184+
Object.assign(dataRoute, {
185+
...dataRoute,
186+
Component: getRouteModuleComponent(routeModule),
187+
ErrorBoundary: routeModule.ErrorBoundary
188+
? routeModule.ErrorBoundary
189+
: route.id === "root"
190+
? () => <RemixRootDefaultErrorBoundary error={useRouteError()} />
191+
: undefined,
192+
handle: routeModule.handle,
193+
shouldRevalidate: needsRevalidation
194+
? wrapShouldRevalidateForHdr(
195+
route.id,
196+
routeModule.shouldRevalidate,
197+
needsRevalidation
198+
)
199+
: routeModule.shouldRevalidate,
200+
});
201+
} else {
202+
// Load all other modules via route.lazy()
203+
Object.assign(dataRoute, {
204+
...dataRoute,
205+
lazy: async () => {
206+
let mod = await loadRouteModuleWithBlockingLinks(
207+
route,
208+
routeModulesCache
209+
);
210+
211+
let lazyRoute: Partial<DataRouteObject> = { ...mod };
212+
213+
if (needsRevalidation) {
214+
lazyRoute.shouldRevalidate = wrapShouldRevalidateForHdr(
215+
route.id,
216+
mod.shouldRevalidate,
217+
needsRevalidation
162218
);
163219
}
164220

165-
return fetchServerHandler(request, route);
166-
} finally {
167-
await routeModulePromise;
168-
}
169-
},
170-
...(routeModule
171-
? // Use critical path modules directly
172-
{
173-
Component: getRouteModuleComponent(routeModule),
174-
ErrorBoundary: routeModule.ErrorBoundary
175-
? routeModule.ErrorBoundary
176-
: route.id === "root"
177-
? () => <RemixRootDefaultErrorBoundary error={useRouteError()} />
178-
: undefined,
179-
handle: routeModule.handle,
180-
shouldRevalidate: needsRevalidation
181-
? wrapShouldRevalidateForHdr(
182-
route.id,
183-
routeModule.shouldRevalidate,
184-
needsRevalidation
185-
)
186-
: routeModule.shouldRevalidate,
187-
}
188-
: // Load all other modules via route.lazy()
189-
{
190-
lazy: async () => {
191-
let mod = await loadRouteModuleWithBlockingLinks(
192-
route,
193-
routeModulesCache
194-
);
195-
if (needsRevalidation) {
196-
mod.shouldRevalidate = wrapShouldRevalidateForHdr(
197-
route.id,
198-
mod.shouldRevalidate,
199-
needsRevalidation
200-
);
201-
}
202-
return mod;
203-
},
204-
}),
205-
};
221+
return {
222+
hasErrorBoundary: lazyRoute.hasErrorBoundary,
223+
shouldRevalidate: lazyRoute.shouldRevalidate,
224+
handle: lazyRoute.handle,
225+
Component: lazyRoute.Component,
226+
ErrorBoundary: lazyRoute.ErrorBoundary,
227+
};
228+
},
229+
});
230+
}
206231

207232
let children = createClientRoutes(
208233
manifest,

0 commit comments

Comments
 (0)