-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add future flag for Single Fetch #8773
Changes from 23 commits
29a1e30
78c011e
e837499
05ef1de
59758b3
1c5978b
195cd18
cc8a03f
918d340
18378f1
ce9b27d
a4631bd
dd0203b
77ac53e
a0fffd7
a2dc7a4
49b46be
bbc0728
c962cf7
3d7c4eb
36887bb
308b010
d5bed65
5cfdec3
509863d
45f07c8
b5fb702
1e6d13d
38ff342
3670378
729336c
7a80a6b
c6750a4
4f9ea7b
1d39835
522f9e4
98ebcd5
782af76
23ca0b8
47a2a3b
291bb3b
14de37c
903d483
dce624d
be316ac
6cce524
439a6cb
e72932b
3cd4512
9bc58ce
4123e1f
674ac4a
b81780a
2939707
395078d
faf262e
2d20749
00e414c
ac3133e
8e53388
f672242
8d4c012
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -196,7 +196,7 @@ export function createClientRoutesWithHMRRevalidationOptOut( | |
); | ||
} | ||
|
||
function preventInvalidServerHandlerCall( | ||
export function preventInvalidServerHandlerCall( | ||
type: "action" | "loader", | ||
route: Omit<EntryRoute, "children">, | ||
isSpaMode: boolean | ||
|
@@ -221,7 +221,7 @@ function preventInvalidServerHandlerCall( | |
} | ||
} | ||
|
||
function noActionDefinedError( | ||
export function noActionDefinedError( | ||
type: "action" | "clientAction", | ||
routeId: string | ||
) { | ||
|
@@ -249,16 +249,34 @@ export function createClientRoutes( | |
return (routesByParentId[parentId] || []).map((route) => { | ||
let routeModule = routeModulesCache[route.id]; | ||
|
||
async function fetchServerLoader(request: Request) { | ||
async function fetchServerLoader( | ||
request: Request, | ||
unwrap: boolean, | ||
singleFetch: unknown | ||
) { | ||
if (!route.hasLoader) return null; | ||
return fetchServerHandler(request, route); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of always hitting the server here, if single fetch is enabled we will have passed the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By proxying this all the way though and branching here as deep as possible - we avoid having to re-implement any of the logic around critical/lazy routes, revalidation, client data etc. in data |
||
if (typeof singleFetch === "function") { | ||
let result = await singleFetch(); | ||
return result; | ||
} | ||
let result = await fetchServerHandler(request, route); | ||
return unwrap ? unwrapServerResponse(result) : result; | ||
} | ||
|
||
async function fetchServerAction(request: Request) { | ||
async function fetchServerAction( | ||
request: Request, | ||
unwrap: boolean, | ||
singleFetch: unknown | ||
) { | ||
if (!route.hasAction) { | ||
throw noActionDefinedError("action", route.id); | ||
} | ||
return fetchServerHandler(request, route); | ||
if (typeof singleFetch === "function") { | ||
let result = await singleFetch(); | ||
return result; | ||
} | ||
let result = await fetchServerHandler(request, route); | ||
return unwrap ? unwrapServerResponse(result) : result; | ||
} | ||
|
||
async function prefetchStylesAndCallHandler( | ||
|
@@ -306,7 +324,10 @@ export function createClientRoutes( | |
needsRevalidation == null && | ||
(routeModule.clientLoader?.hydrate === true || !route.hasLoader); | ||
|
||
dataRoute.loader = async ({ request, params }: LoaderFunctionArgs) => { | ||
dataRoute.loader = async ( | ||
{ request, params }: LoaderFunctionArgs, | ||
singleFetch?: unknown | ||
) => { | ||
try { | ||
let result = await prefetchStylesAndCallHandler(async () => { | ||
invariant( | ||
|
@@ -316,7 +337,7 @@ export function createClientRoutes( | |
if (!routeModule.clientLoader) { | ||
if (isSpaMode) return null; | ||
// Call the server when no client loader exists | ||
return fetchServerLoader(request); | ||
return fetchServerLoader(request, false, singleFetch); | ||
} | ||
|
||
return routeModule.clientLoader({ | ||
|
@@ -334,9 +355,7 @@ export function createClientRoutes( | |
} | ||
|
||
// Call the server loader for client-side navigations | ||
let result = await fetchServerLoader(request); | ||
let unwrapped = await unwrapServerResponse(result); | ||
return unwrapped; | ||
return fetchServerLoader(request, true, singleFetch); | ||
}, | ||
}); | ||
}); | ||
|
@@ -355,7 +374,10 @@ export function createClientRoutes( | |
isSpaMode | ||
); | ||
|
||
dataRoute.action = ({ request, params }: ActionFunctionArgs) => { | ||
dataRoute.action = ( | ||
{ request, params }: ActionFunctionArgs, | ||
singleFetch?: unknown | ||
) => { | ||
return prefetchStylesAndCallHandler(async () => { | ||
invariant( | ||
routeModule, | ||
|
@@ -365,17 +387,15 @@ export function createClientRoutes( | |
if (isSpaMode) { | ||
throw noActionDefinedError("clientAction", route.id); | ||
} | ||
return fetchServerAction(request); | ||
return fetchServerAction(request, false, singleFetch); | ||
} | ||
|
||
return routeModule.clientAction({ | ||
request, | ||
params, | ||
async serverAction() { | ||
preventInvalidServerHandlerCall("action", route, isSpaMode); | ||
let result = await fetchServerAction(request); | ||
let unwrapped = await unwrapServerResponse(result); | ||
return unwrapped; | ||
return fetchServerAction(request, true, singleFetch); | ||
}, | ||
}); | ||
}); | ||
|
@@ -385,19 +405,25 @@ export function createClientRoutes( | |
// the server loader/action in parallel with the module load so we add | ||
// loader/action as static props on the route | ||
if (!route.hasClientLoader) { | ||
dataRoute.loader = ({ request }: LoaderFunctionArgs) => | ||
dataRoute.loader = ( | ||
{ request }: LoaderFunctionArgs, | ||
singleFetch?: unknown | ||
) => | ||
prefetchStylesAndCallHandler(() => { | ||
if (isSpaMode) return Promise.resolve(null); | ||
return fetchServerLoader(request); | ||
return fetchServerLoader(request, false, singleFetch); | ||
}); | ||
} | ||
if (!route.hasClientAction) { | ||
dataRoute.action = ({ request }: ActionFunctionArgs) => | ||
dataRoute.action = ( | ||
{ request }: ActionFunctionArgs, | ||
singleFetch?: unknown | ||
) => | ||
prefetchStylesAndCallHandler(() => { | ||
if (isSpaMode) { | ||
throw noActionDefinedError("clientAction", route.id); | ||
} | ||
return fetchServerAction(request); | ||
return fetchServerAction(request, false, singleFetch); | ||
}); | ||
} | ||
|
||
|
@@ -411,28 +437,30 @@ export function createClientRoutes( | |
let lazyRoute: Partial<DataRouteObject> = { ...mod }; | ||
if (mod.clientLoader) { | ||
let clientLoader = mod.clientLoader; | ||
lazyRoute.loader = (args) => | ||
lazyRoute.loader = ( | ||
args: LoaderFunctionArgs, | ||
singleFetch?: unknown | ||
) => | ||
clientLoader({ | ||
...args, | ||
async serverLoader() { | ||
preventInvalidServerHandlerCall("loader", route, isSpaMode); | ||
let response = await fetchServerLoader(args.request); | ||
let result = await unwrapServerResponse(response); | ||
return result; | ||
return fetchServerLoader(args.request, true, singleFetch); | ||
}, | ||
}); | ||
} | ||
|
||
if (mod.clientAction) { | ||
let clientAction = mod.clientAction; | ||
lazyRoute.action = (args) => | ||
lazyRoute.action = ( | ||
args: ActionFunctionArgs, | ||
singleFetch?: unknown | ||
) => | ||
clientAction({ | ||
...args, | ||
async serverAction() { | ||
preventInvalidServerHandlerCall("action", route, isSpaMode); | ||
let response = await fetchServerAction(args.request); | ||
let result = await unwrapServerResponse(response); | ||
return result; | ||
return fetchServerAction(args.request, true, singleFetch); | ||
}, | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Single fetch opts into this behavior automatically