next.js
523ae09b - [Cache Components] Faster partial hydration in PPR resumes (#82742)

Commit
207 days ago
[Cache Components] Faster partial hydration in PPR resumes (#82742) This PR fixes some HTML/RSC stream interleaving logic that, under some circumstances, resulted in hydration of a resumed page being delayed unnecessarily. Fixes NAR-284 --- When SSRing a page, we're mixing two streams -- the HTML stream, and the RSC stream (containing scripts with RSC data, used for hydration). In a regular (non-PPR) render, we need to wait for react to flush the first HTML chunk (containing `<html><body>...`) before we can send the first RSC script. This was implemented in `createMergedTransformStream`. The problem was that `createMergedTransformStream` was also re-used when rendering a PPR `resume()`. In that case, we're only outputting the dynamic portion of HTML, and the shell is sent separately (either by the next server, outside of `app-render`, or by infrastructure), meaning that is _not_ part of the stream that `createMergedTransformStream` receives. But the "wait for the first html chunk" logic was still there, and thus, we were accidentally delaying sending any RSC scripts until the first piece of dynamic HTML was rendered even if they had no connection to each other. In particular, this also prevented us from sending hydration data for the static shell. There's one edge case here -- if we didn't produce a static shell (e.g. for suspense-above-body), we should still apply the html-waiting logic, otherwise we'd end up sending scripts before the body is rendered. But if we have a shell, we shouldn't wait for the HTML at all. This is now solved as follows: 1. During the prerender, we track whether or not a shell (aka "prelude") was produced, and store that information in the postponed state object 2. When resuming, we check whether the prerender had a shell, and if it does, we don't wait for HTML (under the assumption that it was already sent separately, outside the dynamic render) To test this, I've had to extend our testing setup a bit -- with the default settings, playwright would wait until `load` is fired, which seems to fire after all the HTML finished streaming and thus doesn't let us inspect whether partial hydration is working correctly. We're also waiting for `load` in `elementByCss` (apparently, for compatibility with tests written before playwright) so i've had to work around that as well.
Author
Parents
Loading