next.js
f06d951d - [Cache Components] Dev - restart render on cache miss (#84088)

Commit
76 days ago
[Cache Components] Dev - restart render on cache miss (#84088) This PR replaces the previous approach to the dev-time cache warmup. On full-page requests, we 1. We attempt an initial RSC render. It uses a RequestStore, but includes a `cacheSignal` and a `prerenderResumeDataCache` to be filled 1. if there's no cache misses, we use the RSC render as is, and move onto SSR 2. If there's any cache misses in the static stage (i.e. during the first timeout), we treat the inital render as a prospective render, use it only for filling caches, and discard the result 3. Once caches are filled, we render RSC again (using a fresh RequestStore, with a filled `renderResumeDataCache`), and use this second stream for SSR instead. With this strategy, we minimize the amount of work we need to do for cache warming -- once caches for a page are filled, we can render it in one go, with no separate cache-filling render necessary. --- A lot of the effort here goes into trying to reflect the behavior of a static prerender into what we do during a dynamic render -- if something would be a dynamic hole (hanging promise) in a prerender, we shouldn't resolve it microtaskily (in the static stage). Instead, we have to delay it into a future timeout (the dynamic stage). In this PR, we're still using `makeDevtoolsIOAwarePromise` for this (i.e. just `new Promise((resolve) => setTimeout(resolve))`), though this will change to a more precise mechanism in #84644. The timing of when promises resolve is currently tested in `cache-components.dev-warmup.test.ts`, where we check the environment labels on the server logs replayed in the browser, and use that to verify which "phase" (Static/Dynamic) a given API resolves in. This will be the foundation for prefetch validation, where we'll need to snapshot what was rendered in each stage (Static/Runtime/Dynamic) and use that to validate whether a prefetch would result in an instant navigation. Note that there's currently a bug involving `params` and `searchParams` -- they can currently incorrectly resolve in the static phase (because those promises are created before we start the actual render). We're not (yet) relying on the timing of these promises for anything critical, so it's fine to leave it for now. This bug will be addressed in #84644, where I introduce a more precise mechanism for controlling the timing of promise resolution, which also lets us separate "runtime" APIs like `cookies` into a separate phase. --- I've also left the current `spawnDynamicValidationInDev` codepath as is, so after the we're done with all the render restarting, we'll still kick off a validation prerender. This will also change in the future (and could be optimized -- we've already ensured that all the caches are filled, so we could e.g. skip the prospective render there) but I'm trying not to do everything at once. --------- Co-authored-by: Josh Story <story@hey.com>
Author
Parents
Loading