Skip to content

Commit

Permalink
fix: remove eager buffering with stream pumping and deferred cache si…
Browse files Browse the repository at this point in the history
…gnaling
  • Loading branch information
wyattjoh committed Nov 5, 2024
1 parent cacbfd2 commit f933447
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 224 deletions.
7 changes: 4 additions & 3 deletions packages/next/src/export/routes/app-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { WorkStore } from '../../server/app-render/work-async-storage.exter
import type { FallbackRouteParams } from '../../server/request/fallback-params'
import { AfterRunner } from '../../server/after/run-with-after'
import type { RequestLifecycleOpts } from '../../server/base-server'
import { stringifyResumeDataCache } from '../../server/resume-data-cache/serialization'

export const enum ExportedAppPageFiles {
HTML = 'HTML',
Expand Down Expand Up @@ -149,7 +150,7 @@ export async function exportAppPage(
fetchTags,
fetchMetrics,
segmentFlightData,
resumeDataCache,
immutableResumeDataCache,
} = metadata

// Ensure we don't postpone without having PPR enabled.
Expand Down Expand Up @@ -256,11 +257,11 @@ export async function exportAppPage(
'utf8'
)

if (resumeDataCache) {
if (immutableResumeDataCache) {
await fileWriter(
ExportedAppPageFiles.RESUME_CACHE,
htmlFilepath.replace(/\.html$/, NEXT_STATIC_DATA_CACHE_SUFFIX),
await resumeDataCache.stringify()
await stringifyResumeDataCache(immutableResumeDataCache)
)
}

Expand Down
61 changes: 35 additions & 26 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ import './clean-async-snapshot.external'
import { INFINITE_CACHE } from '../../lib/constants'
import { createComponentStylesAndScripts } from './create-component-styles-and-scripts'
import { parseLoaderTree } from './parse-loader-tree'
import { ResumeDataCache } from '../use-cache/resume-data-cache'
import {
createMutableResumeDataCache,
sealResumeDataCache,
} from '../resume-data-cache/resume-data-cache'

export type GetDynamicParamFromSegment = (
// [slug] / [[slug]] / [...slug]
Expand Down Expand Up @@ -612,12 +615,12 @@ async function warmupDevRender(

// We're doing a dev warmup, so we should create a new resume data cache so
// we can fill it.
const resumeDataCache = new ResumeDataCache()
const mutableResumeDataCache = createMutableResumeDataCache()

// Attach this to the request store so that it can be used during the
// render.
const { requestStore } = ctx
requestStore.resumeDataCache = resumeDataCache
requestStore.mutableResumeDataCache = mutableResumeDataCache

const rscPayload = await workUnitAsyncStorage.run(
requestStore,
Expand Down Expand Up @@ -652,7 +655,7 @@ async function warmupDevRender(
// lift the warmup pathway outside of renderToHTML... but for now this suffices
return new FlightRenderResult('', {
fetchMetrics: ctx.workStore.fetchMetrics,
resumeDataCache,
immutableResumeDataCache: sealResumeDataCache(mutableResumeDataCache),
})
}

Expand Down Expand Up @@ -1443,7 +1446,7 @@ export const renderToHTMLOrFlight: AppPageRender = (
url,
implicitTags,
renderOpts.onUpdateCookies,
renderOpts.resumeDataCache,
renderOpts.immutableResumeDataCache,
renderOpts.previewProps,
isHmrRefresh,
serverComponentsHmrCache
Expand Down Expand Up @@ -1966,7 +1969,7 @@ async function spawnDynamicValidationInDev(
const initialServerRenderController = new AbortController()

const cacheSignal = new CacheSignal()
const resumeDataCache = new ResumeDataCache()
const mutableResumeDataCache = createMutableResumeDataCache()
const initialServerPrerenderStore: PrerenderStore = {
type: 'prerender',
phase: 'render',
Expand All @@ -1979,7 +1982,7 @@ async function spawnDynamicValidationInDev(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

const initialClientController = new AbortController()
Expand All @@ -1995,7 +1998,7 @@ async function spawnDynamicValidationInDev(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

// We're not going to use the result of this render because the only time it could be used
Expand Down Expand Up @@ -2127,7 +2130,7 @@ async function spawnDynamicValidationInDev(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

const finalClientController = new AbortController()
Expand All @@ -2147,7 +2150,7 @@ async function spawnDynamicValidationInDev(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

const finalServerPayload = await workUnitAsyncStorage.run(
Expand Down Expand Up @@ -2419,7 +2422,7 @@ async function prerenderToStream(
// performing a fresh prerender. If we get to implementing the
// prerendering of an already prerendered page, we should use the passed
// resume data cache instead.
const resumeDataCache = new ResumeDataCache()
const mutableResumeDataCache = createMutableResumeDataCache()

const initialServerPrerenderStore: PrerenderStore = (prerenderStore = {
type: 'prerender',
Expand All @@ -2433,7 +2436,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

// We're not going to use the result of this render because the only time it could be used
Expand Down Expand Up @@ -2520,7 +2523,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

const prerender = require('react-dom/static.edge')
Expand Down Expand Up @@ -2600,7 +2603,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

const finalAttemptRSCPayload = await workUnitAsyncStorage.run(
Expand Down Expand Up @@ -2657,7 +2660,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}

let clientIsDynamic = false
Expand Down Expand Up @@ -2738,7 +2741,9 @@ async function prerenderToStream(

const flightData = await streamToBuffer(reactServerResult.asStream())
metadata.flightData = flightData
metadata.resumeDataCache = resumeDataCache
metadata.immutableResumeDataCache = sealResumeDataCache(
mutableResumeDataCache
)
metadata.segmentFlightData = await collectSegmentData(
finalAttemptRSCPayload,
flightData,
Expand Down Expand Up @@ -2873,7 +2878,7 @@ async function prerenderToStream(
const initialServerRenderController = new AbortController()

const cacheSignal = new CacheSignal()
const resumeDataCache = new ResumeDataCache()
const mutableResumeDataCache = createMutableResumeDataCache()

const initialServerPrerenderStore: PrerenderStore = (prerenderStore = {
type: 'prerender',
Expand All @@ -2887,7 +2892,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

const initialClientController = new AbortController()
Expand All @@ -2903,7 +2908,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

// We're not going to use the result of this render because the only time it could be used
Expand Down Expand Up @@ -3046,7 +3051,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

let clientIsDynamic = false
Expand All @@ -3069,7 +3074,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})

const finalServerPayload = await workUnitAsyncStorage.run(
Expand Down Expand Up @@ -3198,10 +3203,12 @@ async function prerenderToStream(
}
}

metadata.immutableResumeDataCache = sealResumeDataCache(
mutableResumeDataCache
)
const flightData = await streamToBuffer(
serverPrerenderStreamResult.asStream()
)
metadata.resumeDataCache = resumeDataCache
metadata.flightData = flightData
metadata.segmentFlightData = await collectSegmentData(
finalServerPayload,
Expand Down Expand Up @@ -3249,7 +3256,7 @@ async function prerenderToStream(
renderOpts.isDebugDynamicAccesses
)

const resumeDataCache = new ResumeDataCache()
const mutableResumeDataCache = createMutableResumeDataCache()
const reactServerPrerenderStore: PrerenderStore = (prerenderStore = {
type: 'prerender-ppr',
phase: 'render',
Expand All @@ -3259,7 +3266,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
})
const RSCPayload = await workUnitAsyncStorage.run(
reactServerPrerenderStore,
Expand Down Expand Up @@ -3291,7 +3298,7 @@ async function prerenderToStream(
expire: INFINITE_CACHE,
stale: INFINITE_CACHE,
tags: [...ctx.requestStore.implicitTags],
resumeDataCache,
mutableResumeDataCache,
}
const prerender = require('react-dom/static.edge')
.prerender as (typeof import('react-dom/static.edge'))['prerender']
Expand Down Expand Up @@ -3342,7 +3349,9 @@ async function prerenderToStream(
renderOpts
)
}
metadata.resumeDataCache = resumeDataCache
metadata.immutableResumeDataCache = sealResumeDataCache(
mutableResumeDataCache
)

/**
* When prerendering there are three outcomes to consider
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/server/app-render/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { InstrumentationOnRequestError } from '../instrumentation/types'
import type { NextRequestHint } from '../web/adapter'
import type { BaseNextRequest } from '../base-http'
import type { IncomingMessage } from 'http'
import type { ResumeDataCache } from '../use-cache/resume-data-cache'
import type { ImmutableResumeDataCache } from '../resume-data-cache/resume-data-cache'

export type DynamicParamTypes =
| 'catchall'
Expand Down Expand Up @@ -189,7 +189,7 @@ export interface RenderOptsPartial {
* The resume data cache that was generated for this partially prerendered
* page or during rendering.
*/
resumeDataCache?: ResumeDataCache
immutableResumeDataCache?: ImmutableResumeDataCache

/**
* When true, only the static shell of the page will be rendered. This will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { ServerComponentsHmrCache } from '../response-cache'
import type {
ImmutableResumeDataCache,
MutableResumeDataCache,
} from '../use-cache/resume-data-cache'
} from '../resume-data-cache/resume-data-cache'

type WorkUnitPhase = 'action' | 'render' | 'after'

Expand Down Expand Up @@ -56,7 +56,12 @@ export type RequestStore = {
/**
* The resume data cache for this request. This will be a immutable cache.
*/
resumeDataCache: ImmutableResumeDataCache | null
immutableResumeDataCache: ImmutableResumeDataCache | null

/**
* The resume data cache for this request. This will be a mutable cache.
*/
mutableResumeDataCache: MutableResumeDataCache | null

// DEV-only
usedDynamic?: boolean
Expand Down Expand Up @@ -109,7 +114,7 @@ export type PrerenderStoreModern = {
/**
* The resume data cache for this prerender.
*/
resumeDataCache: MutableResumeDataCache | null
mutableResumeDataCache: MutableResumeDataCache | null

// DEV ONLY
// When used this flag informs certain APIs to skip logging because we're
Expand All @@ -131,7 +136,7 @@ export type PrerenderStorePPR = {
/**
* The resume data cache for this prerender.
*/
resumeDataCache: MutableResumeDataCache
mutableResumeDataCache: MutableResumeDataCache
} & PhasePartial

export type PrerenderStoreLegacy = {
Expand Down Expand Up @@ -211,30 +216,35 @@ export function getExpectedRequestStore(
)
}

export function getImmutableResumeDataCache(
export function getMutableResumeDataCache(
workUnitStore: WorkUnitStore
): ImmutableResumeDataCache | null {
): MutableResumeDataCache | null {
if (
workUnitStore.type !== 'prerender-legacy' &&
workUnitStore.type !== 'cache' &&
workUnitStore.type !== 'unstable-cache'
) {
return workUnitStore.resumeDataCache
return workUnitStore.mutableResumeDataCache
}

return null
}

export function getMutableResumeDataCache(
export function getImmutableResumeDataCache(
workUnitStore: WorkUnitStore
): MutableResumeDataCache | null {
): ImmutableResumeDataCache | null {
if (
workUnitStore.type !== 'prerender-legacy' &&
workUnitStore.type !== 'cache' &&
workUnitStore.type !== 'unstable-cache' &&
workUnitStore.type !== 'request'
workUnitStore.type !== 'unstable-cache'
) {
return workUnitStore.resumeDataCache
if (workUnitStore.type === 'request') {
return workUnitStore.immutableResumeDataCache
}

// We return the mutable resume data cache here as an immutable version of
// the cache as it can also be used for reading.
return workUnitStore.mutableResumeDataCache
}

return null
Expand Down
Loading

0 comments on commit f933447

Please sign in to comment.