Removes the "allow-runtime" prefetch config, and turns its behavior on
implicitly wherever Partial Prefetching is enabled.
The original motivation for "allow-runtime" was to give apps more
control over server costs triggered by prefetches. Until a route
explicitly opts in, prefetches would only be served from the CDN, not
from the server. The problem, though, was it was very confusing to know
when to add or remove this configuration. The incentive for many apps
was to add it everywhere, with no clear signal for when to remove it.
Our updated thinking is that Partial Prefetching itself already provides
sufficient protection against runaway prefetching costs: per-link
prefetches only happen on Link components that explicitly opt in with
the prefetch prop.
The optimizations landed earlier in this stack also make allow-runtime
less necessary: on pages where all the content is statically renderable,
prefetches are served from the static cache and no runtime request is
ever issued; only a page that accesses non-static data is prefetched at
runtime.
The upshot of this decision is that runtime versus static becomes an
internal optimization; the same content gets prefetched regardless of
whether or how Next.js is able to optimize it.
When `partialPrefetching` is on, the shell that we usually care about
displaying is the App Shell, which is represented by the ShellRuntime
stage. We should only show the cold cache indicator for caches that
happen up until then, and release the client-side promise appropriately.
This PR extends the existing `revealAfterStage` mechanics to account for
this.
> Note that this is incomplete: if we're navigating via `<Link
prefetch={true}>` (or have `partialPrefetching: "unstable_eager"), we
might want to use the Runtime stage instead. I'm leaving those for a
follow up -- representing the common case (a shell prefetch) seems like
the most useful thing.
I've re-worked the `revealAfterStage/holdStreamUntilRevealed` setup into
an object (`DevNavigationKind`) that represents the navigation that
we're trying to simulate -- either an initial load or a client nav. This
gets rid of the invalid `holdStreamUntilRevealed = true` +
`revealAfterStage = RenderStage.Runtime/ShellRuntime` combination and
lets us bring the logic closer to where the stream blocking tricks
actually happen.
I've also done some drive-by refactoring of `streamStagedRenderInDev` to
dedupe some repetitive code, because every task was basically doing the
same thing. I've also moved all `revealAfter.resolve()` calls into
separate tasks -- we were inconsistent about this, and the `Static`
`revealAfter.resolve()` was done together with the next stage, but the
`RenderStage.Runtime` was done in a separate task.
---
Strangely, despite the changes working as expected for the Cold Cache
indicator, I can't actually get link data (`await searchParams`) to
trigger a fallback when navigating, so there's a failing test for that
in `cache-components-dev-streaming.test.ts`. I'm not sure why what's
causing this, but I'm leaving that investigation for a follow-up as
well.