Commit Graph

3 Commits

Author SHA1 Message Date
Zack Tanner 4be2ee7443 Preserve per-segment prefetching after dynamic navigation (#96583)
## Summary

Cache Components routes support per-segment prefetching, but dynamic
Flight responses only advertised this capability during static
generation. This could cause a subsequent `router.prefetch()` call to
fall back to loading-boundary prefetching and issue an unnecessary
request.

In other words, this logic was correctly determined
[here](https://github.com/vercel/next.js/blob/0db9e5f994ddf144bef72640d5be9bb17d77fe30/packages/next/src/server/app-render/app-render.tsx#L2204)
but not in the initial payload.

## Verification

- `pnpm test-start-turbo
test/e2e/app-dir/segment-cache/basic/segment-cache-basic.test.ts`
- `pnpm test-start-webpack
test/e2e/app-dir/segment-cache/basic/segment-cache-basic.test.ts`
2026-08-04 02:02:32 +00:00
Andrew Clark bcb94e3222 [Segment Cache] Refresh on same-page navigation (#76223)
It's a common UI pattern for apps to refresh when you click a link to
the current page. So when this happens, we refresh the dynamic data in
the page segments.

Note that this does not apply if the any part of the hash or search
query has changed. This might feel a bit weird but it makes more sense
when you consider that the way to trigger this behavior is to click the
same link multiple times.

We should probably refresh the *entire* route when this case occurs, not
just the page segments. Essentially treating it the same as a refresh()
triggered by an action, which is the more explicit way of modeling the
UI pattern described above.

Also note that this only refreshes the dynamic data, not static/cached
data. If the page segment is fully static and prefetched, the request is
skipped. (This is also how refresh() works.)
2025-02-28 12:50:11 -05:00
Andrew Clark 7b61470177 [Segment Cache] Add act-inspired internal router testing helper (#74668)
Adds an internal test utility for e2e testing of requests initiated by
the Next.js Router, such as prefetches and navigations. Calls the given
async function then intercepts any router requests that are initiated as
a result. It will then wait for all the requests to complete before
exiting. Inspired by the React `act` API.

I generally dislike early testing abstractions, but getting all the
details right for intercepting the requests with Playwright ended up
being non-trivial enough that I relented and extracted it to a separate
module, in the `e2e/app-dir/segment-cache` folder. I'll hold off moving
it to somewhere even more generic until it's proven to be useful.

Example:

```js
// Asserts that rendering a link results in a prefetch response that
// contains some expected substring
await act(async () => {
  await revealLink()
}, {
  includes: 'subset of linked page content'
})
```

A few goals here:

- As much as possible, avoid coupling to internal implementation
details. For example, it will check for the presence of the "rsc" header
to determine if a request was initiated by the router, but that's about
it.
- No timers, no race conditions. It works by intercepting the requests
at the Playwright network layer. There should be no long pauses when
running the tests, and if an assertion fails, it should fail quickly.
- Account for Next.js's internal bandwidth throttling. The router does
not initiate more than a fixed number of requests at a time, so every
time a request is fulfilled, it has the potential to unblock more
prefetches. So we must wait a task to check for additional requests.
This is similar to what React's `act` implementation does to account for
asynchronous rendering tasks.
2025-01-09 10:26:59 -05:00