-
Notifications
You must be signed in to change notification settings - Fork 27.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Segment Cache] Support <Link prefetch={true}> #74172
base: canary
Are you sure you want to change the base?
Conversation
This implements background revalidation of partial segment entries in client Segment Cache. Until this PR, entries were never replaced in the Segment Cache, they were only evicted upon becoming stale, or if the LRU overflowed. But there are cases where we'll want to replace an existing entry with a new one; for example, if the current segment has more dynamic holes than the new one. Most commonly this happens when multiple fetching strategies are mixed within the same app. For example: when a shared layout belongs to both a PPR-enabled route and a non-PPR enabled route, the layout data might be omitted when prefetching the non-PPR enabled route, if it's wrapped in a loading boundary. But that shouldn't prevent it from being included when prefetching the route that has PPR enabled. (Another example is when a shared layout is prefetched both on viewport entry and also via <Link prefetch={true}>. A viewport prefetch will only include the static data, but prefetch={true} includes both the static and the dynamic. <Link prefetch={true}> is not yet implemented by the Segment Cache but it will use a similar background revalidation strategy as the one implemented in this PR.)
Stats from current PRDefault Build (Increase detected
|
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
buildDuration | 18.6s | 19.1s | |
buildDurationCached | 15.1s | 13s | N/A |
nodeModulesSize | 416 MB | 417 MB | |
nextStartRea..uration (ms) | 475ms | 471ms | N/A |
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
1187-HASH.js gzip | 52.4 kB | 53.2 kB | |
8276.HASH.js gzip | 169 B | 168 B | N/A |
8377-HASH.js gzip | 5.36 kB | 5.36 kB | N/A |
bccd1874-HASH.js gzip | 52.8 kB | 53 kB | |
framework-HASH.js gzip | 57.5 kB | 57.5 kB | N/A |
main-app-HASH.js gzip | 232 B | 235 B | N/A |
main-HASH.js gzip | 34.1 kB | 34.1 kB | N/A |
webpack-HASH.js gzip | 1.71 kB | 1.71 kB | N/A |
Overall change | 105 kB | 106 kB |
Legacy Client Bundles (polyfills)
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 39.4 kB | 39.4 kB | ✓ |
Overall change | 39.4 kB | 39.4 kB | ✓ |
Client Pages
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
_app-HASH.js gzip | 193 B | 193 B | ✓ |
_error-HASH.js gzip | 193 B | 193 B | ✓ |
amp-HASH.js gzip | 512 B | 510 B | N/A |
css-HASH.js gzip | 343 B | 342 B | N/A |
dynamic-HASH.js gzip | 1.84 kB | 1.84 kB | ✓ |
edge-ssr-HASH.js gzip | 265 B | 265 B | ✓ |
head-HASH.js gzip | 363 B | 362 B | N/A |
hooks-HASH.js gzip | 393 B | 392 B | N/A |
image-HASH.js gzip | 4.49 kB | 4.49 kB | N/A |
index-HASH.js gzip | 268 B | 268 B | ✓ |
link-HASH.js gzip | 2.35 kB | 2.34 kB | N/A |
routerDirect..HASH.js gzip | 328 B | 328 B | ✓ |
script-HASH.js gzip | 397 B | 397 B | ✓ |
withRouter-HASH.js gzip | 323 B | 326 B | N/A |
1afbb74e6ecf..834.css gzip | 106 B | 106 B | ✓ |
Overall change | 3.59 kB | 3.59 kB | ✓ |
Client Build Manifests
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
_buildManifest.js gzip | 749 B | 746 B | N/A |
Overall change | 0 B | 0 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
index.html gzip | 524 B | 523 B | N/A |
link.html gzip | 539 B | 537 B | N/A |
withRouter.html gzip | 520 B | 520 B | ✓ |
Overall change | 520 B | 520 B | ✓ |
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
edge-ssr.js gzip | 128 kB | 129 kB | N/A |
page.js gzip | 206 kB | 206 kB | |
Overall change | 206 kB | 206 kB |
Middleware size
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
middleware-b..fest.js gzip | 671 B | 669 B | N/A |
middleware-r..fest.js gzip | 155 B | 156 B | N/A |
middleware.js gzip | 31.2 kB | 31.3 kB | N/A |
edge-runtime..pack.js gzip | 844 B | 844 B | ✓ |
Overall change | 844 B | 844 B | ✓ |
Next Runtimes Overall increase ⚠️
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
274-experime...dev.js gzip | 322 B | 322 B | ✓ |
274.runtime.dev.js gzip | 314 B | 314 B | ✓ |
app-page-exp...dev.js gzip | 359 kB | 357 kB | N/A |
app-page-exp..prod.js gzip | 129 kB | 129 kB | |
app-page-tur..prod.js gzip | 142 kB | 142 kB | |
app-page-tur..prod.js gzip | 137 kB | 137 kB | N/A |
app-page.run...dev.js gzip | 347 kB | 347 kB | N/A |
app-page.run..prod.js gzip | 125 kB | 125 kB | |
app-route-ex...dev.js gzip | 37.5 kB | 37.5 kB | N/A |
app-route-ex..prod.js gzip | 25.5 kB | 25.5 kB | N/A |
app-route-tu..prod.js gzip | 25.5 kB | 25.5 kB | N/A |
app-route-tu..prod.js gzip | 25.4 kB | 25.3 kB | N/A |
app-route.ru...dev.js gzip | 39.2 kB | 39.1 kB | N/A |
app-route.ru..prod.js gzip | 25.4 kB | 25.3 kB | N/A |
pages-api-tu..prod.js gzip | 9.69 kB | 9.69 kB | ✓ |
pages-api.ru...dev.js gzip | 11.6 kB | 11.6 kB | ✓ |
pages-api.ru..prod.js gzip | 9.68 kB | 9.68 kB | ✓ |
pages-turbo...prod.js gzip | 21.7 kB | 21.7 kB | N/A |
pages.runtim...dev.js gzip | 27.5 kB | 27.5 kB | N/A |
pages.runtim..prod.js gzip | 21.7 kB | 21.7 kB | N/A |
server.runti..prod.js gzip | 916 kB | 916 kB | N/A |
Overall change | 427 kB | 429 kB |
build cache
vercel/next.js canary | acdlite/next.js segment-cache-full-prefetch | Change | |
---|---|---|---|
0.pack gzip | 2.08 MB | 2.08 MB | N/A |
index.pack gzip | 75.3 kB | 74.2 kB | N/A |
Overall change | 0 B | 0 B | ✓ |
Diff details
Diff for middleware.js
Diff too large to display
Diff for edge-ssr.js
Diff too large to display
Diff for 1187-HASH.js
Diff too large to display
Diff for bccd1874-HASH.js
Diff too large to display
Diff for main-HASH.js
Diff too large to display
Diff for app-page-exp..ntime.dev.js
failed to diff
Diff for app-page-exp..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page.runtime.dev.js
failed to diff
Diff for app-page.runtime.prod.js
Diff too large to display
Diff for app-route-ex..ntime.dev.js
Diff too large to display
Diff for app-route-ex..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route.runtime.dev.js
Diff too large to display
Diff for app-route.ru..time.prod.js
Diff too large to display
Diff for pages-turbo...time.prod.js
Diff too large to display
Diff for pages.runtime.dev.js
Diff too large to display
Diff for pages.runtime.prod.js
Diff too large to display
Diff for server.runtime.prod.js
failed to diff
This implements support in the Segment Cache for "full" link prefetches, typically initiated by passing `prefetch={true}` to a `<Link>`. The goal of a full prefetch is to request all the data needed for a navigation, both static and dynamic, so that once the navigation occurs, the router does not need to fetch any additional data. So, a full prefetch implicitly instructs the client cache to treat the response as static, even the dynamic data. The implementation is largely the same as what we do to support non-PPR -enabled routes — a request tree is sent to the server describing which segments are already cached and which ones need to be rendered. While constructing the request tree, if all the segments are already in the client cache, the request can be skipped entirely. The main difference is that a full prefetch will only reuse a cached segment entry if it does not contain any dynamic holes.
1574af6
to
62077fc
Compare
Based on:
This implements support in the Segment Cache for "full" link prefetches, typically initiated by passing
prefetch={true}
to a<Link>
.The goal of a full prefetch is to request all the data needed for a navigation, both static and dynamic, so that once the navigation occurs, the router does not need to fetch any additional data. So, a full prefetch implicitly instructs the client cache to treat the response as static, even the dynamic data.
The implementation is largely the same as what we do to support non-PPR-enabled routes — a request tree is sent to the server describing which segments are already cached and which ones need to be rendered. While constructing the request tree, if all the segments are already in the client cache, the request can be skipped entirely. The main difference is that a full prefetch will only reuse a cached segment entry if it does not contain any dynamic holes.