mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
In development the debug channel that streams React's Server Component debug information to the browser is buffered for the initial document and persisted, so that it can be replayed when the browser later serves the page from its HTTP cache — for example on back/forward navigation or tab duplication — instead of forcing a full reload. This changes where that buffer is persisted, moving it from `sessionStorage` to `IndexedDB`. The largest win comes from no longer having to serialize the data. `sessionStorage` can only hold strings, so the binary debug chunks had to be encoded into a string before being written and parsed back out again on restore, which becomes expensive once the payload grows to several megabytes. `IndexedDB` stores the chunks directly as the `Uint8Array`s they already are, so there is no encode and parse round trip on either side. Its asynchronous API helps a little on top of that, since the write itself no longer has to happen synchronously. The other improvement is that persistence no longer competes with hydration. The initial document's debug stream closes while hydration is still running, and the previous synchronous `sessionStorage` write happened at exactly that moment, taking main thread time away from hydration. The write is now deferred with `requestIdleCallback`, so it only runs once the main thread is genuinely idle, which is after hydration has drained, and it is skipped entirely if the page navigates away before that happens, in which case a later restore simply falls back to a reload. This is visible in the profiles below: with `sessionStorage` there is still hydration work running after the persistence task, whereas with the idle-scheduled `IndexedDB` write the persistence only runs once hydration is done. In a profile of a test page that deliberately transfers a large amount of debug information, the persistence work on the main thread dropped from more than 700 ms to roughly 25 to 45 ms. A real application with far less debug data will see a smaller difference, so the test page amplifies the effect, but the direction is the same. The number of persisted entries stays bounded to 10, with the oldest pruned on each write, and an end-to-end test covers the case where an entry is pushed out by newer page loads so that navigating back to it recovers through a page reload. **Before with `sessionStorage`**: <img width="973" height="627" alt="sessionStorage" src="https://github.com/user-attachments/assets/b8ff8464-9ccf-4363-b1fe-78db0fd3e1eb" /> **After with idle-scheduled `IndexedDB`:** <img width="973" height="627" alt="indexedDB" src="https://github.com/user-attachments/assets/94a557a3-c82d-4771-bd81-3b4dfd906f25" />
10 lines
204 B
TypeScript
10 lines
204 B
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
|
|
export function ClientComponent() {
|
|
const [count, setCount] = useState(0)
|
|
|
|
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>
|
|
}
|