Attempt static prefetch before resorting to runtime - #96095
Conversation
Stats from current PR🔴 1 regression
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (10 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsfailed to diffapp-page-exp..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page.runtime.dev.jsfailed to diffapp-page.runtime.prod.jsDiff too large to display pages-api.runtime.dev.jsDiff too large to display pages.runtime.dev.jsDiff too large to display 📎 Tarball URLCommit: 02d016d |
Tests PassedCommit: 02d016d |
415fe8a to
4ff9530
Compare
4ff9530 to
c6bb39f
Compare
544b1b3 to
060b848
Compare
060b848 to
810e43a
Compare
810e43a to
6956d9c
Compare
00333fa to
a8c842c
Compare
3de424e to
77143cd
Compare
f6f7a0f to
ce40d01
Compare
91c936b to
325ff7b
Compare
325ff7b to
11213ee
Compare
11213ee to
cdffd14
Compare
| // post-shell runtime-data access doesn't mark the shell variant itself as | ||
| // needing a runtime request. | ||
| // (An offset that somehow isn't visible in the decode reads as 0 — no | ||
| // shell — the conservative direction: it can waste a runtime request but |
There was a problem hiding this comment.
This comment is a bit contradictory with:
next.js/packages/next/src/client/components/segment-cache/cache.ts
Lines 2599 to 2600 in cdffd14
| // When this payload fully satisfied the segment — no runtime request | ||
| // needed — the content is as complete as a RUNTIME response of the same | ||
| // variant would have been, so it records that runtime tier. That's what | ||
| // lets the scheduler decide "would a runtime request return more?" by | ||
| // comparing tiers alone, with no separate signal to consult. | ||
| // | ||
| // Otherwise the content is only as complete as the static tier it was | ||
| // requested at, so a follow-up runtime request can still supersede it. | ||
| const recordedFetchStrategy = !needsRuntimeRequest | ||
| ? payloadFetchStrategy === FetchStrategy.StaticShell | ||
| ? FetchStrategy.RuntimeShell | ||
| : FetchStrategy.PPRRuntime | ||
| : fetchStrategy |
There was a problem hiding this comment.
hmm, this part feels a little weird. having to pretend that we used a different strategy makes me feel like there's some nicer way to model this. although i suppose it makes sense if we think about the strategies as "level of completeness"
There was a problem hiding this comment.
yeah my plan is to rename the field something like "completeness" but have it represent both sides
cdffd14 to
0cd482a
Compare
If we're reasonably confident that a segment can be prefetched statically without omitting data that would have been included during a runtime prefetch (e.g. cookies), the client should attempt prefetch the segment statically instead of going straight to a runtime request. The decision for whether to do this is based on the ShouldAttemptStaticPrefetch added in previous steps. If it turns out the static response is not sufficient, then it will fall back to a runtime request. This makes prefetching cheaper for pages that are fully statically renderable. We can make the optimization better in the future with more reliable per-segment computation of the ShouldAttemptStaticPrefetch, but the current approach should at least work for fully static pages, which is what's most important. This optimization applies during both the Shell phase and the Speculative phase of the prefetching algorithm.
0cd482a to
02d016d
Compare
…ching (#96302) ### What? Update the interactive apps guide's prefetching section for unified runtime prefetching. ### Why? #96106 removed the `allow-runtime` segment config, and the guide's section still described the old model after the mechanical rename: it told readers session data (cookies, headers) needs the link opt-in, when the App Shell already carries session-gated UI. Only URL data needs `prefetch={true}`. ### How? Rework the section around the per-link model: the shell carries static, cached, and session output, `prefetch={true}` resolves URL data ahead of the click, and the static prefetch attempt (#96095) makes the server cost an internal optimization. Includes a technical-writing pass on the section (full-noun subjects, split splices) and aligns the Next steps table row.
If we're reasonably confident that a segment can be prefetched statically without omitting data that would have been included during a runtime prefetch (e.g. cookies), the client should attempt prefetch the segment statically instead of going straight to a runtime request.
The decision for whether to do this is based on the ShouldAttemptStaticPrefetch added in previous steps.
If it turns out the static response is not sufficient, then it will fall back to a runtime request.
This makes prefetching cheaper for pages that are fully statically renderable. We can make the optimization better in the future with more reliable per-segment computation of the ShouldAttemptStaticPrefetch, but the current approach should at least work for fully static pages, which is what's most important.
This optimization applies during both the Shell phase and the Speculative phase of the prefetching algorithm.