[pull] main from react:main#509
Merged
Merged
Conversation
`getPostponedState` snapshots `request.nextSegmentId` at `onAllReady`, before the Fizz stream is flowing. At this point we have visited all Suspense boundaries and know which ones suspended by user code or not. However, only when the stream is flowing are we counting the size of each boundary. When we detect large boundaries, we suspend them i.e. we outline them instead of keeping them inline. This results in more segments being written while the postponed state holds a stale count. We now keep a reference to the returned postponed state and mutate the segment IDs when we outline. That way serializing `postponed` after the `prelude` has flushed writes the latest postponed state. The current API design means that you can potentially serialize stale postponed state. We're considering a redesign to make these issues impossible (e.g. #36815). For now, the postponed state should only be serialized or passed onto a `resume` once the `prelude` has flushed e.g.: ```js const { createWriteStream, writeFileSync } = require('node:fs'); const { createWriteStream } = require('node:stream'); const { prelude, postponed } = prenderToNodeStream(...) // serializing `postponed` now would write a stale state. // serialize prelude const destination = createWriteStream('prelude.html') prelude.pipe(destination) await finished(prelude) // now we can serialize postponed writeFileSync('postponed.json', JSON.stringify(postponed)) ``` --------- Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>
Adds the component-tree building blocks and the `createTools(facade)`
assembler — the first tools layered on top of the `installFacade` hook
from commit 1.
### `createTools(facade): Tools`
Reads the facade's tracked state (fiber roots + per-renderer internals)
and returns a plain `Tools` object — no globals; the integrator decides
what to do with it. Tools return **typed, plain JavaScript values** (or
`{error}`); serialization (to an integration package's wire format) is
left to the caller.
### Tools
- **`getComponentTree(depth?, rootUid?)`** — the component tree as a
flat array of `{uid, type, name, key, firstChild, nextSibling}` nodes
(an adjacency list referencing other nodes by label).
- **`getComponentByUid(uid)`** — one component's `{type, name, key?,
props?, hooks?}`. For function components, `hooks` is the inspected
hooks tree (nested `subHooks`), obtained via `react-debug-tools'`
`inspectHooksOfFiberWithoutDefaultDispatcher` with the renderer's
injected dispatcher (normalized by `getDispatcherRef`) — so hooks
introspection never falls back to, or bundles, React's shared internals.
- **`findComponents(name, rootUid?, page?, pageSize?)`** — paginated,
case-insensitive name search.
- **`getComponentSource(uid)`** — the component's definition location
`{name, fileName, line, column}` (or `null`).
- **`getOwnersStack(uid)`** — the raw JSX owner-stack string (DEV only).
- **`getOwnersBranch(uid)`** — the structured owner chain `[{uid, name,
type}]`, ordered immediate owner → root (DEV only).
### UIDs
Components are addressed by stable `rN` uids, assigned lazily and
memoized per fiber (and its alternate), so a component keeps the same
uid across re-renders and across every tool. These uids don't survive
page reloads.
Adds the profiler building blocks to `createTools` — per-commit render
timing on top of the component-tree tools from commit 2.
### Tools
- **`startProfiling(traceName?)`** → `{status: 'started', trace}`.
Begins a session that records timing on every commit. Errors if a
session is already active.
- **`stopProfiling()`** → `{status: 'stopped', traceName, commits}`
(commit count). Errors if no session is active.
- **`getTraceOverview(traceName)`** → one row per commit: `{commit,
committedAt, renderDuration, layoutDuration, passiveDuration,
componentsChanged}`.
- **`getCommitReport(traceName, commitIndex)`** → one commit's detail:
`{committedAt, priority, renderDuration, layoutDuration,
passiveDuration,
components}`, where `components` is `{label, name, type, actualDuration,
selfDuration}` sorted by `actualDuration` descending.
Durations are in milliseconds, or `null` when the build does not collect
profiler
timing. `passiveDuration` is attributed per root via the hook's
post-commit pass.
This PR just adds more tests that validate Facade's implementation against setups with multiple React roots or Renderers.
…#36682) Makes `installFacade` usable on pages that already have a DevTools backend — most importantly the **React DevTools browser extension** — by attaching to the existing `__REACT_DEVTOOLS_GLOBAL_HOOK__` instead of refusing to install. This is important, because otherwise if the page had Facade installed, the user won't be able to use React DevTools browser extension.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )