Skip to content

Commit

Permalink
Basic implementation of cache-wrapper with RSC serialization (vercel#…
Browse files Browse the repository at this point in the history
…70435)

Co-authored-by: JJ Kasper <[email protected]>
  • Loading branch information
2 people authored and abhi12299 committed Sep 29, 2024
1 parent 5521bb5 commit a23ee7f
Show file tree
Hide file tree
Showing 12 changed files with 375 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
export function cache(_kind: string, _id: string, fn: any) {
return fn
}
export { cache } from '../../../../server/use-cache/use-cache-wrapper'
12 changes: 12 additions & 0 deletions packages/next/src/client/components/async-local-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,15 @@ export function createAsyncLocalStorage<
}
return new FakeAsyncLocalStorage()
}

export function createSnapshot(): <R, TArgs extends any[]>(
fn: (...args: TArgs) => R,
...args: TArgs
) => R {
if (maybeGlobalAsyncLocalStorage) {
return maybeGlobalAsyncLocalStorage.snapshot()
}
return function (fn: any, ...args: any[]) {
return fn(...args)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface StaticGenerationStore {
forceStatic?: boolean
dynamicShouldError?: boolean
pendingRevalidates?: Record<string, Promise<any>>
pendingRevalidateWrites?: Array<Promise<void>> // This is like pendingRevalidates but isn't used for deduping.

dynamicUsageDescription?: string
dynamicUsageStack?: string
Expand Down
3 changes: 3 additions & 0 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ async function addRevalidationHeader(
staticGenerationStore.revalidatedTags || []
),
...Object.values(staticGenerationStore.pendingRevalidates || {}),
...(staticGenerationStore.pendingRevalidateWrites || []),
])

// If a tag was revalidated, the client router needs to invalidate all the
Expand Down Expand Up @@ -533,6 +534,7 @@ export async function handleAction({
staticGenerationStore.revalidatedTags || []
),
...Object.values(staticGenerationStore.pendingRevalidates || {}),
...(staticGenerationStore.pendingRevalidateWrites || []),
])

const promise = Promise.reject(error)
Expand Down Expand Up @@ -924,6 +926,7 @@ export async function handleAction({
staticGenerationStore.revalidatedTags || []
),
...Object.values(staticGenerationStore.pendingRevalidates || {}),
...(staticGenerationStore.pendingRevalidateWrites || []),
])
const promise = Promise.reject(err)
try {
Expand Down
60 changes: 32 additions & 28 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ function parseRequestHeaders(

const flightRouterState = shouldProvideFlightRouterState
? parseAndValidateFlightRouterState(
headers[NEXT_ROUTER_STATE_TREE_HEADER.toLowerCase()]
)
headers[NEXT_ROUTER_STATE_TREE_HEADER.toLowerCase()]
)
: undefined

const csp =
Expand Down Expand Up @@ -930,7 +930,7 @@ async function renderToHTMLOrFlightImpl(
})
.end(
metrics.clientComponentLoadStart +
metrics.clientComponentLoadTimes
metrics.clientComponentLoadTimes
)
}
}
Expand Down Expand Up @@ -1086,13 +1086,15 @@ async function renderToHTMLOrFlightImpl(
// If we have pending revalidates, wait until they are all resolved.
if (
staticGenerationStore.pendingRevalidates ||
staticGenerationStore.revalidatedTags
staticGenerationStore.revalidatedTags ||
staticGenerationStore.pendingRevalidateWrites
) {
options.waitUntil = Promise.all([
staticGenerationStore.incrementalCache?.revalidateTag(
staticGenerationStore.revalidatedTags || []
),
...Object.values(staticGenerationStore.pendingRevalidates || {}),
...(staticGenerationStore.pendingRevalidateWrites || []),
])
}

Expand Down Expand Up @@ -1194,13 +1196,15 @@ async function renderToHTMLOrFlightImpl(
// If we have pending revalidates, wait until they are all resolved.
if (
staticGenerationStore.pendingRevalidates ||
staticGenerationStore.revalidatedTags
staticGenerationStore.revalidatedTags ||
staticGenerationStore.pendingRevalidateWrites
) {
options.waitUntil = Promise.all([
staticGenerationStore.incrementalCache?.revalidateTag(
staticGenerationStore.revalidatedTags || []
),
...Object.values(staticGenerationStore.pendingRevalidates || {}),
...(staticGenerationStore.pendingRevalidateWrites || []),
])
}

Expand Down Expand Up @@ -1849,8 +1853,8 @@ async function prerenderToStream(
ctx,
res.statusCode === 404
)
function voidOnError() {}
;(
function voidOnError() { }
; (
prerenderAsyncStorage.run(
// The store to scope
prospectiveRenderPrerenderStore,
Expand All @@ -1869,7 +1873,7 @@ async function prerenderToStream(
signal: flightController.signal,
}
) as Promise<ReactServerPrerenderResolveToType>
).catch(() => {})
).catch(() => { })

// When this resolves the cache has no inflight reads and we can ascertain the dynamic outcome
await cacheSignal.cacheReady()
Expand Down Expand Up @@ -2064,7 +2068,7 @@ async function prerenderToStream(
const resumeStream = await resume(
<App
reactServerStream={foreverStream}
preinitScripts={() => {}}
preinitScripts={() => { }}
clientReferenceManifest={clientReferenceManifest}
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
nonce={ctx.nonce}
Expand Down Expand Up @@ -2157,24 +2161,24 @@ async function prerenderToStream(
ctx,
res.statusCode === 404
)
// We're not going to use the result of this render because the only time it could be used
// is if it completes in a microtask and that's likely very rare for any non-trivial app
;(
prerenderAsyncStorage.run(
// The store to scope
prospectiveRenderPrerenderStore,
// The function to run
ComponentMod.prerender,
// ... the arguments for the function to run
firstAttemptRSCPayload,
clientReferenceManifest.clientModules,
{
nonce: ctx.nonce,
onError,
signal: flightController.signal,
}
) as Promise<ReactServerPrerenderResolveToType>
).catch(() => {})
// We're not going to use the result of this render because the only time it could be used
// is if it completes in a microtask and that's likely very rare for any non-trivial app
; (
prerenderAsyncStorage.run(
// The store to scope
prospectiveRenderPrerenderStore,
// The function to run
ComponentMod.prerender,
// ... the arguments for the function to run
firstAttemptRSCPayload,
clientReferenceManifest.clientModules,
{
nonce: ctx.nonce,
onError,
signal: flightController.signal,
}
) as Promise<ReactServerPrerenderResolveToType>
).catch(() => { })

// When this resolves the cache has no inflight reads and we can ascertain the dynamic outcome
await cacheSignal.cacheReady()
Expand Down Expand Up @@ -2513,7 +2517,7 @@ async function prerenderToStream(
const resumeStream = await resume(
<App
reactServerStream={foreverStream}
preinitScripts={() => {}}
preinitScripts={() => { }}
clientReferenceManifest={clientReferenceManifest}
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
nonce={ctx.nonce}
Expand Down
Loading

0 comments on commit a23ee7f

Please sign in to comment.