Commit Graph

6130 Commits

Author SHA1 Message Date
Ricky 03e4ec2d0f [assert helpers] react-dom (pt3) (#31983)
moar assert helpers

this finishes all of react-dom except the server integration tests which
are tricky to convert
2025-01-05 17:10:29 -05:00
Ricky bf883bebbc [fizz] fix empty string href double warning (#31783)
I think this is the suggested change from
https://github.com/facebook/react/pull/31765#discussion_r1884541447

But no tests fail and I'm not sure how to test it? Seems sus. 

Also seems like the `removeAttribute` here should be changed?


https://github.com/facebook/react/blob/9d9f12f2699a049777fa88914306ad4de9e2b74d/packages/react-dom-bindings/src/client/ReactDOMComponent.js#L400-L427
2025-01-03 12:53:28 -05:00
Ricky f42f8c0635 [flags] Remove enableServerComponentLogs (#31772)
This has landed everywhere.
2025-01-03 12:53:19 -05:00
Sebastian Markbåge 3b009b4cd5 Make RefStatic and LayoutStatic the same bit (#31965)
Refs are basically just fancy Layout Effects. These are conceptually the
same thing and are always visited together so they don't need to be
different flags.

Whenever we disappear/reappear Offscreen content we need to do both Refs
and Layout Effects.

This is just indicating which phase needs to be visited and these are
always the same phase.
2025-01-02 21:23:09 -05:00
Ricky dc7578290f [assert helpers] ReactDOMFloat-test (#31901)
Splitting out ReactDOMFloat to it's own PR because it's huge.
2025-01-02 15:53:19 -05:00
Ricky 7c11aad374 [assert helpers] react-dom (pt2) (#31902)
Converts more react-dom tests
2025-01-02 15:53:06 -05:00
Ricky d8a08f8e39 [assert helpers] ReactDOMComponent-test (#31898)
Splitting out ReactDOMComponent to it's own PR because it's huge.
2025-01-02 15:28:15 -05:00
Ricky a7c898d83a [assert helpers] react-dom (pt 1) (#31897)
Converts ~half of react-dom tests
2025-01-02 15:28:06 -05:00
Sebastian Markbåge c81312e3a7 [Fiber] Refactor Commit Phase into Separate Functions for Before Mutation/Mutation/Layout (#31930)
This is doing some general clean up to be able to split the commit root three phases into three separate async steps.
2025-01-02 14:55:34 -05:00
Sebastian Markbåge d8b903f49e [Fiber] Avoid return value from commitBeforeMutationEffects (#31922)
This is behind an unusual flag (enableCreateEventHandleAPI) that doesn't
serve a special return value. I'll be collecting other flags from this
phase too.

We can just use the global flag and reset it before the next mutation
phase. Unlike focusedInstanceHandle this doesn't leak any memory in the
meantime.
2025-01-02 14:34:26 -05:00
Sebastian Markbåge 6ca7fbe884 [Fiber] Gate Update flag on BeforeMutationMask on flags (#31921)
We're currently visiting the snapshot phase for every `Update` flag even
though we rarely have to do anything in the Snapshot phase.

The only flags that seem to use these wider visits is
`enableCreateEventHandleAPI` and `enableUseEffectEventHook` but really
neither of those should do that neither. They should schedule explicit
Snapshot phases if needed.
2025-01-02 14:34:10 -05:00
Sebastian Markbåge 0de1233fd1 [Fiber] Mark error boundaries and commit phases when an error is thrown (#31876)
This tracks commit phase errors and marks the component that errored as
red. These also get the errors attached to the entry.

<img width="1505" alt="Screenshot 2024-12-20 at 2 40 14 PM"
src="https://github.com/user-attachments/assets/cac3ead7-a024-4e33-ab27-2e95293c4299"
/>

In the render phase I just mark the Error Boundary that caught the
error. We don't have access to the actual error since it's locked behind
closures in the update queue. We could probably expose that someway.

<img width="949" alt="Screenshot 2024-12-20 at 1 49 05 PM"
src="https://github.com/user-attachments/assets/3032455d-d9f2-462b-9c07-7be23663ecd3"
/>

Follow ups:

Since the Error Boundary doesn't commit its attempted render, we don't
log those. If we did then maybe we should just mark the errored
component like I do for the commit phase. We could potentially walk the
list of errors and log the captured fibers and just log their entries as
children.

We could also potentially walk the uncommitted Fiber tree by stashing it
somewhere or even getting it from the alternate. This could be done on
Suspense boundaries too to track failed hydrations.

---------

Co-authored-by: Ricky <rickhanlonii@gmail.com>
2025-01-02 13:28:24 -05:00
Sebastian Markbåge 1e9eb95db5 [Fiber] Mark cascading updates (#31866)
A common source of performance problems is due to cascading renders from
calling `setState` in `useLayoutEffect` or `useEffect`. This marks the
entry from the update to when we start the render as red and `"Cascade"`
to highlight this.

<img width="964" alt="Screenshot 2024-12-19 at 10 54 59 PM"
src="https://github.com/user-attachments/assets/2bfa91e6-1dc1-4b7f-a659-50aaf2a97e83"
/>

In addition to this case, there's another case where you call `setState`
multiple times in the same event causing multiple renders. This might be
due to multiple `flushSync`, or spawned a microtasks from a
`useLayoutEffect`. In theory it could also be from a microtask scheduled
after the first `setState`. This one we can only detect if it's from an
event that has a `window.event` since otherwise it's hard to know if
we're still in the same event.

<img width="1210" alt="Screenshot 2024-12-19 at 11 38 44 PM"
src="https://github.com/user-attachments/assets/ee188bc4-8ebb-4e95-b5a5-4d724856c27d"
/>

I decided against making a ping in a microtask considered a cascade.
Because that should ideally be using the Suspense Optimization and so
wouldn't be considered multi-pass.

<img width="1284" alt="Screenshot 2024-12-19 at 11 07 30 PM"
src="https://github.com/user-attachments/assets/2d173750-a475-41a0-b6cf-679d15c4ca97"
/>

We might consider making the whole render phase and maybe commit phase
red but that should maybe reserved for actual errors. The "Blocked"
phase really represents the `setState` and so will have the stack trace
of the first update.
2025-01-02 13:04:09 -05:00
Sebastian Markbåge fe21c947c8 [Fiber] Yield every other frame for Transition/Retry work (#31828)
This flag first moves the `shouldYield()` logic into React itself. We
need this for `postTask` compatibility anyway since this logic is no
longer a concern of the scheduler. This means that there can also be no
global `requestPaint()` that asks for painting earlier. So this is best
rolled out with `enableAlwaysYieldScheduler` (and ideally
`enableYieldingBeforePassive`) instead of `enableRequestPaint`.

Once in React we can change the yield timing heuristics. This uses the
previous 5ms for Idle work to keep everything responsive while doing
background work. However, for Transitions and Retries we have seen that
same thread animations (like loading states animating, or constant
animations like cool Three.js stuff) can take CPU time away from the
Transition that causes moving into new content to slow down. Therefore
we only yield every 25ms.

The purpose of this yield is not to avoid the overhead of yielding,
which is very low, but rather to intentionally block any frequently
occurring other main thread work like animations from starving our work.
If we could we could just tell everyone else to throttle their stuff for
ideal scheduling but that's not quite realistic. In other words, the
purpose of this is to reduce the frame rate of animations to 30 fps and
we achieve this by not yielding. We still do yield to allow the
animations to not just stall. This seems like a good balance.

The 5ms of Idle is because we don't really need to yield less often
since the overhead is low. We keep it low to allow 120 fps animations to
run if necessary and our work may not be the only work within a frame so
we need to yield early enough to leave enough time left.

Similarly we choose 25ms rather than say 35ms to ensure that we push
long enough to guarantee to half the frame rate but low enough that
there's plenty of time left for a rAF to power each animation every
other frame. It's also low enough that if something else interrupts the
work like a new interaction, we can still be responsive to that within
50ms or so. We also need to yield in case there's I/O work that needs to
get bounced through the main thread.

This flag is currently off everywhere since we have so many other
scheduling flags but that means there's some urgency to roll those out
fully so we can test this one. There's also some tests to update since
this doesn't go through the Mock scheduler anymore for yields.
2025-01-02 13:02:22 -05:00
Ruslan Lesiutin 62208bee5a DevTools: fork FastRefresh test for <18 versions of React (#31893)
We currently have a failing test for React DevTools against React 17.
This started failing in https://github.com/facebook/react/pull/30899,
where we changed logic for error tracking and started relying on
`onPostCommitFiberRoot` hook.

Looking at https://github.com/facebook/react/pull/21183,
`onPostCommitFiberRoot` was shipped in 18, which means that any console
errors / warnings emitted in passive effects won't be recorded by React
DevTools for React < 18.
2025-01-02 14:07:21 +00:00
Devon Govett 694d3e1aae [Flight Parcel] Implement prepareDestinationForModule (#31799)
Followup to #31725

This implements `prepareDestinationForModule` in the Parcel Flight
client. On the Parcel side, the `<Resources>` component now only inserts
`<link>` elements for stylesheets (along with a bootstrap script when
needed), and React is responsible for inserting scripts. This ensures
that components that are conditionally dynamic imported during render
are also preloaded.

CSS must be added to the RSC tree using `<Resources>` to avoid FOUC.
This must be manually rendered in both the top-level page, and in any
component that is dynamic imported. It would be nice if there was a way
for React to automatically insert CSS as well, but unfortunately
`prepareDestinationForModule` only knows about client components and not
CSS for server components. Perhaps there could be a way we could
annotate components at code splitting boundaries with the resources they
need? More thoughts in this thread:
https://github.com/facebook/react/pull/31725#discussion_r1884867607
2024-12-31 13:13:43 -05:00
Sebastian Markbåge 50f00fd876 [Flight] Mark Errored Server Components (#31879)
This is similar to #31876 but for Server Components.

It marks them as errored and puts the error message in the Summary
properties.

<img width="1511" alt="Screenshot 2024-12-20 at 5 05 35 PM"
src="https://github.com/user-attachments/assets/92f11e42-0e23-41c7-bfd4-09effb25e024"
/>

This only looks at the current chunk for rejections. That means that
there might still be promises deeper that rejected but it's only the
immediate return value of the Server Component that's considered a
rejection of the component itself.
2024-12-28 02:02:16 -05:00
Ricky 94867f33be [asserts helpers] react package (#31853)
Based off https://github.com/facebook/react/pull/31844

Commit to review:
https://github.com/facebook/react/commit/11aa104e3e70c0accc21f785060b812beb145089

Converts the rest of the `react` package.
2024-12-23 14:58:20 -05:00
Ricky 99471c02dd [assert helpers] ReactFlight (#31860) 2024-12-20 12:41:30 -05:00
Ricky 26297f5383 [assert helpers] not dom or reconciler (#31862)
converts everything left outside react-dom and react-reconciler
2024-12-20 12:41:13 -05:00
Jack Pope de82912e62 Turn off enableYieldingBeforePassive in internal test renderers (#31863)
https://github.com/facebook/react/pull/31785 turned on
`enableYieldingBeforePassive` for the internal test renderer builds. We
have some failing tests on the RN side blocking the sync so lets turn
these off for now.
2024-12-20 09:48:50 -05:00
Sebastian "Sebbie" Silbermann 518d06d26a Turn off enableYieldingBeforePassive (#31857) 2024-12-19 20:43:01 +01:00
Ricky 36d15d5862 [assert helpers] ReactChildren-test (#31844)
Based off https://github.com/facebook/react/pull/31843

Commit to review:
https://github.com/facebook/react/pull/31844/commits/2c653b81a73e155f1548c0362e5334629a45351e

Moar tests
2024-12-19 13:05:23 -05:00
Sebastian Markbåge 9f540fcc51 [Flight] Support streaming of decodeReply in Edge environments (#31852)
We support streaming `multipart/form-data` in Node.js using Busboy since
that's kind of the idiomatic ecosystem way for handling these stream
there. There's not really anything idiomatic like that for Edge that's
universal yet.

This adds a version that's basically just
`AsyncIterable.from(formData)`. It could also be a `ReadableStream` of
those entries since those are also `AsyncIterable`.

I imagine that in the future we might add one from a binary
`ReadableStream` that does the parsing built-in.
2024-12-19 12:54:59 -05:00
Ricky 8f92ea467e [assert helpers] forwardRef-test (#31843)
Starting to convert the rest of tests to the `assertConsoleTypeDev`
helpers.
2024-12-19 11:50:05 -05:00
Jack Pope bd76ce54d9 Fork Scheduler feature flags for native-fb (#31859)
#31787 introduces an experimental scheduler flag:
`enableAlwaysYieldScheduler`, which is turned off for www. There wasn't
a SchedulerFeatureFlags fork for native-fb, so the experimental change
was enabled in the Scheduler-dev build there which causes test failures
and is blocking the sync.

#31805 introduces another scheduler flag `enableRequestPaint`, which is
set as a `__VARIANT__` on www. I've set this to `true` here to preserve
the existing behavior. We can follow up with dynamic flags for native-fb
after unblocking the sync.
2024-12-19 11:49:14 -05:00
Sebastian Markbåge a9bbe34622 [Flight] Reject any new Chunks not yet discovered at the time of reportGlobalError (#31851)
Same as #31840 but for the Flight Client.
2024-12-19 00:03:40 -05:00
Sebastian Markbåge 17520b6381 [Fiber] Mark hydrated components in tertiary color (green) (#31829)
This is a follow up to #31752.

This keeps track in the commit phase whether this subtree was hydrated.
If it was, then we mark those components in the Components track as
green. Just like the phase itself is marked as green.

If the boundary client rendered we instead mark it as "errored" and its
children given the plain primary render color (blue). I also collect the
hydration error for this case so we can include its message in the
details view. (Unfortunately this doesn't support newlines atm.)

Most of the time this happens in separate commits for each boundary but
it is possible to force a client render in the same pass as a hydration.
Such as if an update flows into a boundary that has been put into
fallback state after it was initially attempted.

<img width="1487" alt="Screenshot 2024-12-18 at 12 06 54 AM"
src="https://github.com/user-attachments/assets/74c57291-4d11-414c-9751-3dac3285a89a"
/>
2024-12-18 23:53:54 -05:00
Ricky faf6c4dfdc [flags] Remove debugRenderPhaseSideEffectsForStrictMode (#31839)
This is enabled everywhere, we can just use the inline `__DEV__` checks.
2024-12-18 17:51:12 -05:00
Sebastian Markbåge ef979d4703 [Flight Reply] Reject any new Chunks not yet discovered at the time of reportGlobalError (#31840)
We might have already resolved models that are not pending and so are
not rejected by aborting the stream. When those later get parsed they
might discover new chunks which end up as pending. These should be
errored since they will never be able to resolve later.

This avoids infinitely hanging the stream.

This same fix needs to be ported to ReactFlightClient that has the same
issue.
2024-12-18 12:56:57 -08:00
Jonathan Hefner 95465dc491 Allow <script> and <template> tags in <select> tag (#31837) 2024-12-18 21:29:16 +01:00
Ricky 74dd2da9ac [flags] Remove enableModernStrictMode (#31838)
This is enabled everywhere.
2024-12-18 14:45:37 -05:00
Ricky e1d843f4d8 [tests] <StrictMode /> nested in tree is broken (#31825)
Adds a test that shows using <StrictMode /> anywhere outside of the root
node will not fire strict effects.

This works:

```js
root.render(
  <StrictMode>
    <App>
      <Children />
    </App>
  </StrictMode>
);
  ```
  
  This does not fire strict effects on mount:
```js
root.render(
  <App>
    <StrictMode>
      <Children />
    </StrictMode>
  </App>
);
```
2024-12-18 13:29:41 -05:00
Ricky 1e9ef39a87 [flags] Delete enableSchedulerDebugger (#31826)
The tool for this isn't used so I killed it internally and we can clean
up the code to make it easier to reduce the scheduler code.
2024-12-18 13:29:22 -05:00
Hendrik Liebau 7eb8234f7c [Flight] Fix double-incremented pending chunks counter (#31833)
Before calling `emitTimingChunk` inside of `forwardDebugInfo`, we must
not increment `request.pendingChunks`, as this is already done inside of
the `emitTimingChunk` function.

I don't have a unit test for this, but manually verified that this fixes
the hanging responses in https://github.com/vercel/next.js/pull/73804.
2024-12-18 16:35:02 +01:00
David Sancho 2bd1c756c6 Ensure function arity is preserved after build (#31808)
Co-authored-by: eps1lon <sebastian.silbermann@vercel.com>
2024-12-18 14:08:56 +01:00
Sebastian Markbåge 6a4b46cd70 [Fiber] Log Effect and Render Times in Offscreen Commit Phase (#31788)
In https://github.com/facebook/react/pull/30967 and
https://github.com/facebook/react/pull/30983 I added logging of the just
rendered components and the effects. However this didn't consider the
special Offscreen passes. So this adds the same thing to those passes.

Log component effect timings for disconnected/reconnected offscreen
subtrees. This includes initial mount of a Suspense boundary.

Log component render timings for reconnected and already offscreen
offscreen subtrees.
2024-12-17 19:46:03 -05:00
Sebastian Markbåge facec3ee71 [Fiber] Schedule passive effects using the regular ensureRootIsScheduled flow (#31785)
This treats workInProgressRoot work and rootWithPendingPassiveEffects
the same way. Basically as long as there's some work on the root, yield
the current task. Including passive effects. This means that passive
effects are now a continuation instead of a separate callback. This can
mean they're earlier or later than before. Later for Idle in case
there's other non-React work. Earlier for same Default if there's other
Default priority work.

This makes sense since increasing priority of the passive effects beyond
Idle doesn't really make sense for an Idle render.

However, for any given render at same priority it's more important to
complete this work than start something new.

Since we special case continuations to always yield to the browser, this
has the same effect as #31784 without implementing `requestPaint`. At
least assuming nothing else calls `requestPaint`.

<img width="587" alt="Screenshot 2024-12-14 at 5 37 37 PM"
src="https://github.com/user-attachments/assets/8641b172-8842-4191-8bf0-50cbe263a30c"
/>
2024-12-17 17:01:31 -05:00
Sebastian Markbåge f5077bcc92 [Scheduler] Always yield to native macro tasks when a virtual task completes (#31787)
As an alternative to #31784.

We should really just always yield each virtual task to a native task.
So that it's 1:1 with native tasks. This affects when microtasks within
each task happens. This brings us closer to native `postTask` semantics
which makes it more seamless to just use that when available.

This still doesn't yield when a task expires to protect against
starvation.
2024-12-17 16:49:01 -05:00
Jack Pope 34ee3919c3 Clean up enableLazyContextPropagation (#31810)
This flag has shipped everywhere, let's clean it up.
2024-12-17 11:56:00 -05:00
Ricky d428725882 [flags] Clean up scheduler flags (#31814)
These flags are hardcoded now, we can make them static.
2024-12-17 10:27:46 -05:00
Ricky 975cea2d3d Enable debugRenderPhaseSideEffectsForStrictMode in test renderers (#31761)
This flag controls the strict mode double invoke render/lifecycles/etc
behavior in Strict Mode.

The only place this flag is off is the test renderers, which it should
be on for.

If we can land this, we can follow up to remove the flag.
2024-12-16 22:52:18 -05:00
Ricky 49b1a956a9 Enable disableDefaultPropsExceptForClasses (#31804)
TODO: test this PR to see what internal tests fail
2024-12-16 22:51:15 -05:00
Ricky 8dab5920e0 Turn on useModernStrictMode in test renderers (#31769)
It's on everywhere else, let's turn this on so we can remove it. 

Probably should have been turned on in the test renderer for 19.
2024-12-16 22:43:51 -05:00
Sebastian Markbåge 54e86bd0d0 [Flight] Color and badge non-primary environments (#31738)
Stacked on #31737.

<img width="987" alt="Screenshot 2024-12-11 at 8 41 15 PM"
src="https://github.com/user-attachments/assets/438379a9-0138-4d02-a53a-419402839558"
/>

When mixing environments (like "use cache" or third party RSC) it's
useful to color and badge those components differently to differentiate.

I'm not putting them in separate tracks because when they do actually
execute, like cache misses or third party RSCs, they behave like they're
part of the same tree.
2024-12-16 13:39:19 -05:00
Sebastian Markbåge bdf187174d [Flight] Emit Deduped Server Components Marker (#31737)
Stacked on #31736.

<img width="1223" alt="Screenshot 2024-12-11 at 8 21 12 PM"
src="https://github.com/user-attachments/assets/a7cbc04b-c831-476b-aa2f-baddec9461c9"
/>

This emits a placeholder when we're deduping a component. This starts
when the parent's self time ends, where we would've started rendering
this component if it wasn't already started. The end time is when the
actual render ends since the parent is also blocked by it.
2024-12-16 13:16:53 -05:00
Sebastian Markbåge 07facb52d3 [Flight] Sort Server Components Track Group ahead of Client Scheduler/Components Tracks (#31736)
Stacked on #31735.

This ensures that Server Components Track comes first. Since it's
typically rendered first on the server for initial load and then flows
into scheduler and client components work. Also puts it closer to the
Network and further away from "Main" JS.

<img width="769" alt="Screenshot 2024-12-11 at 5 31 41 PM"
src="https://github.com/user-attachments/assets/7198db0f-075e-4a78-8ea4-3bfbf06727cb"
/>

Same trick as in #31615.
2024-12-16 12:39:15 -05:00
Jack Pope 909ed63e0a Clean up context access profiling experiment (#31806)
We introduced the `unstable_useContextWithBailout` API to run compiler
based experiments. This API was designed to be an experiment proxy for
alternative approaches which would be heavier to implement. The
experiment turned out to be inconclusive. Since most of our performance
critical usage is already optimized, we weren't able to find a clear win
with this approach.

Since we don't have further plans for this API, let's clean it up.
2024-12-16 12:32:07 -05:00
Sebastian Markbåge 031230d2e0 [Flight] Stack Parallel Components in Separate Tracks (#31735)
Stacked on https://github.com/facebook/react/pull/31729

<img width="1436" alt="Screenshot 2024-12-11 at 3 36 41 PM"
src="https://github.com/user-attachments/assets/0a201913-0076-4bbf-be18-8f1df6c58313"
/>

The Server Components visualization is currently a tree flame graph
where parent spans the child. This makes it equivalent to the Client
Components visualization.

However, since Server Components can be async and therefore parallel, we
need to do something when two children are executed in parallel. This PR
bumps parallel children into a separate track and then within that track
if that child has more children it can grow within that track.

I currently just cut off more than 10 parallel tracks.

Synchronous Server Components are still in sequence but it's unlikely
because even a simple microtasky Async Component is still parallel.

<img width="959" alt="Screenshot 2024-12-11 at 4 31 17 PM"
src="https://github.com/user-attachments/assets/5ad6a7f8-7fa0-46dc-af51-78caf9849176"
/>

I think this is probably not a very useful visualization for Server
Components but we can try it out.

I'm also going to try a different visualization where parent-child
relationship is horizontal and parallel vertical instead, but it might
not be possible to make that line up in this tool. It makes it a little
harder to see how much different components (including their children)
impact the overall tree. If that's the only visualization it's also
confusing why it's different dimensions than the Client Component
version.
2024-12-16 11:58:25 -05:00
Ricky f7b1273da2 Flag for requestPaint (#31805)
Will run a quick experiment for this.
2024-12-16 11:18:03 -05:00