@@ -91,20 +91,20 @@ type CacheKeyParts =
91
91
| [ buildId : string , id : string , args : unknown [ ] ]
92
92
| [ buildId : string , id : string , args : unknown [ ] , hmrRefreshHash : string ]
93
93
94
- interface UseCacheInnerPageComponentProps {
94
+ interface UseCachePageInnerProps {
95
95
params : Promise < Params >
96
96
searchParams ?: Promise < SearchParams >
97
97
}
98
98
99
- export interface UseCachePageComponentProps {
99
+ export interface UseCachePageProps {
100
100
params : Promise < Params >
101
101
searchParams : Promise < SearchParams >
102
- $$isPageComponent : true
102
+ $$isPage : true
103
103
}
104
104
105
- export type UseCacheLayoutComponentProps = {
105
+ export type UseCacheLayoutProps = {
106
106
params : Promise < Params >
107
- $$isLayoutComponent : true
107
+ $$isLayout : true
108
108
} & {
109
109
// The value type should be React.ReactNode. But such an index signature would
110
110
// be incompatible with the other two props.
@@ -995,25 +995,26 @@ export function cache(
995
995
}
996
996
}
997
997
998
- let isPageOrLayout = false
999
-
1000
- // For page and layout components, the cache function is overwritten,
1001
- // which allows us to apply special handling for params and searchParams.
1002
- // For pages and layouts we're using the outer params prop, and not the
1003
- // inner one that was serialized/deserialized. While it's not generally
1004
- // true for "use cache" args, in the case of `params` the inner and outer
1005
- // object are essentially equivalent, so this is safe to do (including
1006
- // fallback params that are hanging promises). It allows us to avoid
1007
- // waiting for the timeout, when prerendering a fallback shell of a cached
1008
- // page or layout that awaits params.
1009
- if ( isPageComponent ( args ) ) {
1010
- isPageOrLayout = true
998
+ let isPageOrLayoutSegmentFunction = false
999
+
1000
+ // For page and layout segment functions (i.e. the page/layout component,
1001
+ // or generateMetadata/generateViewport), the cache function is
1002
+ // overwritten, which allows us to apply special handling for params and
1003
+ // searchParams. For pages and layouts we're using the outer params prop,
1004
+ // and not the inner one that was serialized/deserialized. While it's not
1005
+ // generally true for "use cache" args, in the case of `params` the inner
1006
+ // and outer object are essentially equivalent, so this is safe to do
1007
+ // (including fallback params that are hanging promises). It allows us to
1008
+ // avoid waiting for the timeout, when prerendering a fallback shell of a
1009
+ // cached page or layout that awaits params.
1010
+ if ( isPageSegmentFunction ( args ) ) {
1011
+ isPageOrLayoutSegmentFunction = true
1011
1012
1012
1013
const [ { params : outerParams , searchParams : outerSearchParams } ] = args
1013
1014
1014
- const props : UseCacheInnerPageComponentProps = {
1015
+ const props : UseCachePageInnerProps = {
1015
1016
params : outerParams ,
1016
- // Omit searchParams and $$isPageComponent .
1017
+ // Omit searchParams and $$isPage .
1017
1018
}
1018
1019
1019
1020
if ( isPrivate ) {
@@ -1028,7 +1029,7 @@ export function cache(
1028
1029
[ name ] : async ( {
1029
1030
params : _innerParams ,
1030
1031
searchParams : innerSearchParams ,
1031
- } : UseCacheInnerPageComponentProps ) =>
1032
+ } : UseCachePageInnerProps ) =>
1032
1033
originalFn . apply ( null , [
1033
1034
{
1034
1035
params : outerParams ,
@@ -1045,19 +1046,22 @@ export function cache(
1045
1046
} ,
1046
1047
] ) ,
1047
1048
} [ name ] as ( ...args : unknown [ ] ) => Promise < unknown >
1048
- } else if ( isLayoutComponent ( args ) ) {
1049
- isPageOrLayout = true
1050
-
1051
- const [ { params : outerParams , $$isLayoutComponent, ...outerSlots } ] =
1052
- args
1053
- // Overwrite the props to omit $$isLayoutComponent.
1049
+ } else if ( isLayoutSegmentFunction ( args ) ) {
1050
+ isPageOrLayoutSegmentFunction = true
1051
+
1052
+ const [ { params : outerParams , $$isLayout, ...outerSlots } ] = args
1053
+ // Overwrite the props to omit $$isLayout. Note that slots are only
1054
+ // passed to the layout component (if any are defined), and not to
1055
+ // generateMetadata nor generateViewport. For those functions,
1056
+ // outerSlots/innerSlots is an empty object, which is fine because we're
1057
+ // just spreading it into the props.
1054
1058
args = [ { params : outerParams , ...outerSlots } ]
1055
1059
1056
1060
fn = {
1057
1061
[ name ] : async ( {
1058
1062
params : _innerParams ,
1059
1063
...innerSlots
1060
- } : Omit < UseCacheLayoutComponentProps , '$$isLayoutComponent ' > ) =>
1064
+ } : Omit < UseCacheLayoutProps , '$$isLayout ' > ) =>
1061
1065
originalFn . apply ( null , [ { params : outerParams , ...innerSlots } ] ) ,
1062
1066
} [ name ] as ( ...args : unknown [ ] ) => Promise < unknown >
1063
1067
}
@@ -1120,14 +1124,14 @@ export function cache(
1120
1124
//
1121
1125
// fallthrough
1122
1126
case 'prerender' :
1123
- if ( ! isPageOrLayout ) {
1124
- // If the "use cache" function is not a page or a layout, we need to
1125
- // track dynamic access already when encoding the arguments. If
1126
- // params are passed explicitly into a "use cache" function (as
1127
- // opposed to receiving them automatically in a page or layout), we
1128
- // assume that the params are also accessed. This allows us to abort
1129
- // early, and treat the function as dynamic, instead of waiting for
1130
- // the timeout to be reached.
1127
+ if ( ! isPageOrLayoutSegmentFunction ) {
1128
+ // If the "use cache" function is not a page or layout segment
1129
+ // function, we need to track dynamic access already when encoding
1130
+ // the arguments. If params are passed explicitly into a "use cache"
1131
+ // function (as opposed to receiving them automatically in a page or
1132
+ // layout), we assume that the params are also accessed. This allows
1133
+ // us to abort early, and treat the function as dynamic, instead of
1134
+ // waiting for the timeout to be reached.
1131
1135
const dynamicAccessAbortController = new AbortController ( )
1132
1136
1133
1137
encodedCacheKeyParts = await dynamicAccessAsyncStorage . run (
@@ -1600,37 +1604,31 @@ export function cache(
1600
1604
return React . cache ( cachedFn )
1601
1605
}
1602
1606
1603
- function isPageComponent (
1604
- args : any [ ]
1605
- ) : args is [ UseCachePageComponentProps , undefined ] {
1606
- if ( args . length !== 2 ) {
1607
- return false
1608
- }
1609
-
1610
- const [ props , ref ] = args
1607
+ /**
1608
+ * Returns `true` if the `'use cache'` function is the page component itself,
1609
+ * or `generateMetadata`/`generateViewport` in a page file.
1610
+ */
1611
+ function isPageSegmentFunction ( args : any [ ] ) : args is [ UseCachePageProps ] {
1612
+ const [ maybeProps ] = args
1611
1613
1612
1614
return (
1613
- ref === undefined && // server components receive an undefined ref arg
1614
- props !== null &&
1615
- typeof props === 'object' &&
1616
- ( props as UseCachePageComponentProps ) . $$isPageComponent
1615
+ maybeProps !== null &&
1616
+ typeof maybeProps === 'object' &&
1617
+ ( maybeProps as UseCachePageProps ) . $$isPage === true
1617
1618
)
1618
1619
}
1619
1620
1620
- function isLayoutComponent (
1621
- args : any [ ]
1622
- ) : args is [ UseCacheLayoutComponentProps , undefined ] {
1623
- if ( args . length !== 2 ) {
1624
- return false
1625
- }
1626
-
1627
- const [ props , ref ] = args
1621
+ /**
1622
+ * Returns `true` if the `'use cache'` function is the layout component itself,
1623
+ * or `generateMetadata`/`generateViewport` in a layout file.
1624
+ */
1625
+ function isLayoutSegmentFunction ( args : any [ ] ) : args is [ UseCacheLayoutProps ] {
1626
+ const [ maybeProps ] = args
1628
1627
1629
1628
return (
1630
- ref === undefined && // server components receive an undefined ref arg
1631
- props !== null &&
1632
- typeof props === 'object' &&
1633
- ( props as UseCacheLayoutComponentProps ) . $$isLayoutComponent
1629
+ maybeProps !== null &&
1630
+ typeof maybeProps === 'object' &&
1631
+ ( maybeProps as UseCacheLayoutProps ) . $$isLayout === true
1634
1632
)
1635
1633
}
1636
1634
0 commit comments