diff --git a/packages/next/src/server/app-render/encryption.ts b/packages/next/src/server/app-render/encryption.ts index 59ffb87369d35..70f864c8ba415 100644 --- a/packages/next/src/server/app-render/encryption.ts +++ b/packages/next/src/server/app-render/encryption.ts @@ -23,6 +23,8 @@ import { stringToUint8Array, } from './encryption-utils' +import type { ManifestNode } from '../../build/webpack/plugins/flight-manifest-plugin' + const textEncoder = new TextEncoder() const textDecoder = new TextDecoder() @@ -97,6 +99,13 @@ export async function decryptActionBoundArgs( // Decrypt the serialized string with the action id as the salt. const decryped = await decodeActionBoundArg(actionId, await encrypted) + // TODO: We can't use the client reference manifest to resolve the modules + // on the server side - instead they need to be recovered as the module + // references (proxies) again. + // For now, we'll just use an empty module map. + const ssrModuleMap: { + [moduleExport: string]: ManifestNode + } = {} // Using Flight to deserialize the args from the string. const deserialized = await createFromReadableStream( new ReadableStream({ @@ -107,12 +116,11 @@ export async function decryptActionBoundArgs( }), { ssrManifest: { - // TODO: We can't use the client reference manifest to resolve the modules - // on the server side - instead they need to be recovered as the module - // references (proxies) again. - // For now, we'll just use an empty module map. - moduleLoading: {}, - moduleMap: {}, + // moduleLoading must be null because we don't want to trigger preloads of ClientReferences + // to be added to the current execution. Instead, we'll wait for any ClientReference + // to be emitted which themselves will handle the preloading. + moduleLoading: null, + moduleMap: ssrModuleMap, }, } ) diff --git a/packages/next/src/server/use-cache/use-cache-wrapper.ts b/packages/next/src/server/use-cache/use-cache-wrapper.ts index ecfe5c7675cbf..5cec14e907507 100644 --- a/packages/next/src/server/use-cache/use-cache-wrapper.ts +++ b/packages/next/src/server/use-cache/use-cache-wrapper.ts @@ -15,6 +15,13 @@ import { import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external' import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' +import { + getClientReferenceManifestSingleton, + getServerModuleMap, +} from '../app-render/encryption-utils' + +import type { ManifestNode } from '../../build/webpack/plugins/flight-manifest-plugin' + type CacheEntry = { value: ReadableStream stale: boolean @@ -63,13 +70,6 @@ cacheHandlerMap.set('default', { shouldRevalidateStale: false, }) -const serverManifest: any = null // TODO -const clientManifest: any = null // TODO -const ssrManifest: any = { - moduleMap: {}, - moduleLoading: null, -} // TODO - // TODO: Consider moving this another module that is guaranteed to be required in a safe scope. const runInCleanSnapshot = createSnapshot() @@ -81,9 +81,14 @@ async function generateCacheEntry( fn: any ): Promise { const temporaryReferences = createServerTemporaryReferenceSet() - const [, args] = await decodeReply(encodedArguments, serverManifest, { - temporaryReferences, - }) + + const [, args] = await decodeReply( + encodedArguments, + getServerModuleMap(), + { + temporaryReferences, + } + ) // Invoke the inner function to load a new result. const result = fn.apply(null, args) @@ -91,18 +96,24 @@ async function generateCacheEntry( let didError = false let firstError: any = null - const stream = renderToReadableStream(result, clientManifest, { - environmentName: 'Cache', - temporaryReferences, - onError(error: any) { - // Report the error. - console.error(error) - if (!didError) { - didError = true - firstError = error - } - }, - }) + const clientReferenceManifestSingleton = getClientReferenceManifestSingleton() + + const stream = renderToReadableStream( + result, + clientReferenceManifestSingleton.clientModules, + { + environmentName: 'Cache', + temporaryReferences, + onError(error: any) { + // Report the error. + console.error(error) + if (!didError) { + didError = true + firstError = error + } + }, + } + ) const [returnStream, savedStream] = stream.tee() @@ -235,6 +246,22 @@ export function cache(kind: string, id: string, fn: any) { // server terminal. Once while generating the cache entry and once when replaying it on // the server, which is required to pick it up for replaying again on the client. const replayConsoleLogs = true + + // TODO: We can't use the client reference manifest to resolve the modules + // on the server side - instead they need to be recovered as the module + // references (proxies) again. + // For now, we'll just use an empty module map. + const ssrModuleMap: { + [moduleExport: string]: ManifestNode + } = {} + + const ssrManifest = { + // moduleLoading must be null because we don't want to trigger preloads of ClientReferences + // to be added to the consumer. Instead, we'll wait for any ClientReference to be emitted + // which themselves will handle the preloading. + moduleLoading: null, + moduleMap: ssrModuleMap, + } return createFromReadableStream(stream, { ssrManifest, temporaryReferences,