`stateNode` is any-typed, so when reading from `stateNode` we should always cast
it to the specific type for that type of work. I noticed a place in the commit
phase where OffscreenInstance wasn't being cast. When I added the type
assertion, it exposed some type errors where nullable values were being accessed
without first being refined.
I added the required null checks without verifying the logic of the existing
code. If the existing logic was correct, then the extra null checks won't have
any affect on the behavior, because all they do is refine from a nullable type
to a non-nullable type in places where the type was assumed to already be
non-nullable. But the result looks a bit fishy to me, so I also left behind some
TODOs to follow up and verify it's correct.
This reverts commit 401296310f because it's
failing on main, likely due to conflict with something that landed before the
PR was merged. Need to rebase and fix.
This PR refactors the transition tracing root code by reusing the tracing marker code. Namely it:
* Refactors the tracing marker code so that it takes a tracing marker instance instead of a tracing marker fiber and rename the stack to `markerInstance` instead of `tracingMarker`
* Pushes the root code onto the stack
* Moves the instantiation of `root.incompleteTransitions` to the begin phase when we are pushing the root to the stack rather than in the commit phase
* [FORKED] Add HiddenContext to track if subtree is hidden
This adds a new stack cursor for tracking whether we're rendering inside
a subtree that's currently hidden.
This corresponds to the same place where we're already tracking the
"base lanes" needed to reveal a hidden subtree — that is, when going
from hidden -> visible, the base lanes are the ones that we skipped
over when we deferred the subtree. We must includes all the base lanes
and their updates in order to avoid an inconsistency with the
surrounding content that already committed.
I consolidated the base lanes logic and the hidden logic into the same
set of push/pop calls.
This is intended to replace the InvisibleParentContext that is currently
part of SuspenseContext, but I haven't done that part yet.
* Add previous commit to forked revisions
* [FORKED] Track nearest Suspense handler on stack
Instead of traversing the return path whenever something suspends to
find the nearest Suspense boundary, we can push the Suspense boundary
onto the stack before entering its subtree. This doesn't affect the
overall algorithm that much, but because we already do all the same
logic in the begin phase, we can save some redundant work by tracking
that information on the stack instead of recomputing it every time.
* Add previous commit to forked revisions
Offscreen is only enabled in the www and experimental channels. Instead
of listing these on every Offscreen test, I added a test gate alias
called `enableOffscreen`. Makes it easier to grep for these, and edit or
remove the channels later.
This applies forked changes from the "new" reconciler to the "old" one.
Includes:
- d410f0a [FORKED] Bugfix: Offscreen instance is null during setState
- 58bb117 [FORKED] Check for infinite update loops even if unmounted
- 31882b5 [FORKED] Bugfix: Revealing a hidden update
- 17691ac [FORKED] Don't update childLanes until after current render
This PR:
* Simplifies the code in `SidebarEventInfo` by passing it the actual clicked event rather than an index.
* Lightly refactored the `SidebarEventInfo` code so that it can be used for more than just `schedulingEvents`
* Fixes bug. Previously, whenever a state update event was clicked, we updated the `selectedCommitIndex` in the `ProfilerContext`. However, this index is used for the selected commit in the Flamegraph profiler, which caused a bug where if you would change the contents of the event sidebar, the commit sidebar in the Flamegraph profiler would change too. This PR replaces this with the actual event info instead
Add column number for `viewSourceLineFunction` and renamed the function to `viewUrlSourceFunction` to match the other source function naming conventions
This PR fixes a bug where we would add a transition to the lanes map every time an update occurs. However, we didn't factor in that there might be multiple updates in a transition, which would cause the transition to be added multiple times to the transitionLanes map.
This changes the transitionLanes object from an Array of Arrays to an Array of Sets so that we only add a transition if it hasn't been added before, avoiding duplicates
* [DevTools] front-end for profiling event stack
Adds a side-bar to the profiling tab. Users can now select an update event, and are
shown the callstack from the originating component. When a source path is available
there is now UI to jump to source.
Add FB enabled feature flag: enableProfilerComponentTree for the side-bar.
resolves#24170
This PR cleans up the DevTools codebase by:
* Consolidating `normalizeCodeLocInfo` into one place
* Remove unused source argument in the DevTools component stacks code
This PR adds a component stack field to the `schedule-state-update` event. The algorithm is as follows:
* During profiling, whenever a state update happens collect the parents of the fiber that caused the state update and store it in a map
* After profiling finishes, post process the `schedule-state-update` event and using the parent fibers, generate the component stack by using`describeFiber`, a function that uses error throwing to get the location of the component by calling the component without props.
---
Co-authored-by: Blake Friedman <blake.friedman@gmail.com>
Add aborting to the Flight Server. This encodes the reason as an "error"
row that gets thrown client side. These are still exposed in prod which
is a follow up we'll still have to do to encode them as digests instead.
The error is encoded once and then referenced by each row that needs to
be updated.
In Fizz this got split into Task and Segment. We don't have a concept of
Segment in Flight yet because we don't inline multiple segments into one
"Row". We just emit one "Row" for each Segment if something suspends.
This makes Flight non-deterministic atm but that's something we'll want to
address.
Regardless, right now, this is more like a Task than a Segment.
Before this change we weren't calling onError nor onFatalError if you abort
before completing the shell.
This means that the render never completes and hangs.
Aborting early can happen before even creating the stream for AbortSignal,
before rendering starts in Node since there's an setImmediate atm, or
during rendering.
We can think of transitions on the root as a bunch of tracing markers. Therefore, we can map each transition to a map of pending suspense boundaries. When a transition's pending suspense boundary map is empty, we know that it's complete. This PR:
* Combines the `pendingSuspenseBoundaries` and `transitions` into one `incompleteTransitions` object. This object is a map from a `transition` to a map of `pendingSuspenseBoundaries`
* Refactored code to make it so that every transition has its own `pendingSuspenseBoundaries` map rather than sharing just one.
* Moves the transition complete callback to the root. Alternatively, we can also keep a map of pendingSuspenseBoundaries to transitions on the Offscreen marker, but it's simpler to just call the transition complete callback on the root instead. We also only do this if there are transitions pending, so it shouldn't make too big of a difference
* [DevTools] fix useDeferredValue to match reconciler change
* fixup
* update test to catch original issue
* fix lint
* add safer tests for other composite hooks
This reverts commit 327e4a1f96.
Turns out we hadn't rolled this out internally yet — I mistook
enableClientRenderFallbackOnHydrationMismatch for
said enableClientRenderFallbackOnTextMismatch. Need to revert
until we finish rolling out the change.
* [FORKED] Bugfix: Offscreen instance is null during setState
During a setState, we traverse up the return path and check if any
parent Offscreen components are currently hidden. To do that, we must
access the Offscreen fiber's `stateNode` field.
On a mounted Offscreen fiber, the `stateNode` is never null, so usually
we don't need to refine the type. When a fiber is unmounted, though,
we null out its `stateNode` field to prevent memory cycles. However,
we also null out its `return` field, so I had assumed that an unmounted
Offscreen fiber would never be reachable.
What I didn't consider is that it's possible to call `setState` on a
fiber that never finished mounting. Because it never mounted, it was
never deleted. Because it was never deleted, its `return` field was
never disconnected.
This pattern is always accompanied by a warning but we still need to
account for it. There may also be other patterns where an unmounted
Offscreen instance is reachable, too.
The discovery also suggests it may be better for memory
usage if we don't attach the `return` pointer until the commit phase,
though in order to do that we'd need some other way to track the return
pointer during initial render, like on the stack.
The fix is to add a null check before reading the instance
during setState.
* Add previous commit to list of forked revisions
This PR pushes all of a suspense boundary's transitions onto the transition stack when it goes from hidden to visible so we can pass it to any child suspense boundaries or tracing markers.
Creating an Error captures a stack trace which can be somewhat expensive.
We shouldn't do tthat always for every render.
This also ensures that the stack trace is more useful because you can
follow through the Node.js code to see the cause.
ReactDOMFizzServer(Browser/Node)-test file is really meant to just be a
very shallow tests of the Browser/Node specific streaming APIs.
Most of the general streaming tests are in ReactDOMFizzServer-test instead
of testing all streaming related things in each environment.
The legacy renderToString APIs are mostly covered by ReactServerRendering-test
et al for historical reasons.
This PR adds code to add a marker complete callback to the queue. It also adds code to process marker complete callback.
Marker complete callbacks, in addition to the fields that transition complete callbacks need, also have a `markerName` field
When a suspense boundary suspends or commits, we need to notify the corresponding tracing markers so that they know when to log that they've completed. To do this, we add a stack of tracing markers. In the begin phase, we will push the tracing markers onto the stack, and during the complete/unwind phase we will pop the tracing markers off the stack
In a later PR, we will store the active tracing markers on the suspense boundary, and during the commit phase we will process the active tracing markers by adding/removing the boundary as appropriate.
* [FORKED] Check for infinite update loops even if unmounted
The infinite update loop check doesn't need to run if the component
already unmounted, because an update to an unmounted component can't
cause a re-render. But because we used to run the check in this case,
anyway, I found one test in www that happens to "rely on" this behavior
(accidentally). The test is a pretty messy snapshot thing that I have no
interest fixing so to unblock the sync I'm just going to switch this
back to how it was.
* Add previous commit to forked revisions