Commit Graph
1358 Commits
Author SHA1 Message Date
javache fc97c65ed0 [react-native] Consume ReactNativeAttributePayloadFabric from ReactNativePrivateInterface (#33616)
## Summary

ReactNativeAttributePayloadFabric was synced to react-native in
https://github.com/facebook/react-native/commit/0e42d33cbcfadcf5d787108da785d56a83d07a9f.
We should now consume these methods from the
ReactNativePrivateInterface.

Moving these methods to the React Native repo gives us more flexibility
to experiment with new techniques for bridging and diffing props
payloads.

I did have to leave some stub implementations for existing unit tests,
but moved all detailed tests to the React Native repo.

## How did you test this change?

* `yarn prettier`
* `yarn test ReactFabric-test`

DiffTrain build for [7a3ffef703](https://github.com/facebook/react/commit/7a3ffef70339c10f8d65a27b88cd73bfbe13eb8a)
2025-06-25 02:31:15 -07:00
sebmarkbageandHendrik Liebau 6db4aa0298 [Flight] Emit Partial Debug Info if we have any at the point of aborting a render (#33632)
When we abort a render we don't really have much information about the
task that was aborted. Because before a Promise resolves there's no
indication about would have resolved it. In particular we don't know
which I/O would've ultimately called resolve().

However, we can at least emit any information we do have at the point
where we emit it. At the least the stack of the top most Promise.

Currently we synchronously flush at the end of an `abort()` but we
should ideally schedule the flush in a macrotask and emit this debug
information right before that. That way we would give an opportunity for
any `cacheSignal()` abort to trigger rejections all the way up and those
rejections informs the awaited stack.

---------

Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>

DiffTrain build for [e67b4fe22e](https://github.com/facebook/react/commit/e67b4fe22e0c3c267303ee6737aec1db48055022)
2025-06-24 13:43:57 -07:00
josephsavona 99aa3a2717 [compiler] New inference repros/fixes (#33584)
Substantially improves the last major known issue with the new inference
model's implementation: inferring effects of function expressions. I
knowingly used a really simple (dumb) approach in
InferFunctionExpressionAliasingEffects but it worked surprisingly well
on a ton of code. However, investigating during the sync I saw that we
the algorithm was literally running out of memory, or crashing from
arrays that exceeded the maximum capacity. We were accumluating data
flow in a way that could lead to lists of data flow captures compounding
on themselves and growing very large very quickly. Plus, we were
incorrectly recording some data flow, leading to cases where we reported
false positive "can't mutate frozen value" for example.

So I went back to the drawing board. InferMutationAliasingRanges already
builds up a data flow graph which it uses to figure out what values
would be affected by mutations of other values, and update mutable
ranges. Well, the key question that we really want to answer for
inferring a function expression's aliasing effects is which values
alias/capture where. Per the docs I wrote up, we only have to record
such aliasing _if they are observable via mutations_. So, lightbulb:
simulate mutations of the params, free variables, and return of the
function expression and see which params/free-vars would be affected!
That's what we do now, giving us precise information about which such
values alias/capture where. When the "into" is a param/context-var we
use Capture, iwhen the destination is the return we use Alias to be
conservative.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33584).
* #33626
* #33625
* #33624
* __->__ #33584

DiffTrain build for [94cf60bede](https://github.com/facebook/react/commit/94cf60bede7cd6685e07a4374d1e3aa90445130b)
2025-06-24 10:09:13 -07:00
eps1lon 2939511af5 Fix CI (#33578)
DiffTrain build for [a947eba4f2](https://github.com/facebook/react/commit/a947eba4f2c8741d2c61a3b33fd79cf13bf9f39d)
2025-06-19 14:51:27 -07:00
sebmarkbage 3f8abf8acf Expose cacheSignal() alongside cache() (#33557)
This was really meant to be there from the beginning. A `cache()`:ed
entry has a life time. On the server this ends when the render finishes.
On the client this ends when the cache of that scope gets refreshed.

When a cache is no longer needed, it should be possible to abort any
outstanding network requests or other resources. That's what
`cacheSignal()` gives you. It returns an `AbortSignal` which aborts when
the cache lifetime is done based on the same execution scope as a
`cache()`ed function - i.e. `AsyncLocalStorage` on the server or the
render scope on the client.

```js
import {cacheSignal} from 'react';
async function Component() {
  await fetch(url, { signal: cacheSignal() });
}
```

For `fetch` in particular, a patch should really just do this
automatically for you. But it's useful for other resources like database
connections.

Another reason it's useful to have a `cacheSignal()` is to ignore any
errors that might have triggered from the act of being aborted. This is
just a general useful JavaScript pattern if you have access to a signal:

```js
async function getData(id, signal) {
  try {
     await queryDatabase(id, { signal });
  } catch (x) {
     if (!signal.aborted) {
       logError(x); // only log if it's a real error and not due to cancellation
     }
     return null;
  }
}
```

This just gets you a convenient way to get to it without drilling
through so a more idiomatic code in React might look something like.

```js
import {cacheSignal} from "react";

async function getData(id) {
  try {
     await queryDatabase(id);
  } catch (x) {
     if (!cacheSignal()?.aborted) {
       logError(x);
     }
     return null;
  }
}
```

If it's called outside of a React render, we normally treat any cached
functions as uncached. They're not an error call. They can still load
data. It's just not cached. This is not like an aborted signal because
then you couldn't issue any requests. It's also not like an infinite
abort signal because it's not actually cached forever. Therefore,
`cacheSignal()` returns `null` when called outside of a React render
scope.

Notably the `signal` option passed to `renderToReadableStream` in both
SSR (Fizz) and RSC (Flight Server) is not the same instance that comes
out of `cacheSignal()`. If you abort the `signal` passed in, then the
`cacheSignal()` is also aborted with the same reason. However, the
`cacheSignal()` can also get aborted if the render completes
successfully or fatally errors during render - allowing any outstanding
work that wasn't used to clean up. In the future we might also expand on
this to give different
[`TaskSignal`](https://developer.mozilla.org/en-US/docs/Web/API/TaskSignal)
to different scopes to pass different render or network priorities.

On the client version of `"react"` this exposes a noop (both for
Fiber/Fizz) due to `disableClientCache` flag but it's exposed so that
you can write shared code.

DiffTrain build for [e1dc03492e](https://github.com/facebook/react/commit/e1dc03492eedaec517e14a6e32b8fda571d00767)
2025-06-17 14:10:59 -07:00
jbrown215 15a6dc7dcf [compiler] Add repro for IIFE in ternary causing a bailout (#33546)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33546).
* #33548
* __->__ #33546

DiffTrain build for [75e78d243f](https://github.com/facebook/react/commit/75e78d243f749d009fa1c5c09c3464301b992718)
2025-06-16 19:06:07 -07:00
jbrown215 3b068f6553 [compiler] Do not inline IIFEs in value blocks (#33548)
As discussed in chat, this is a simple fix to stop introducing labels
inside expressions.

The useMemo-with-optional test was added in
https://github.com/facebook/react/commit/d70b2c2c4e85c2a7061214c15a8ff13167d10422
and crashes for the same reason- an unexpected label as a value block
terminal.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33548).
* __->__ #33548
* #33546

DiffTrain build for [90bee81902](https://github.com/facebook/react/commit/90bee819028bfecb724df298da798607b6a76abf)
2025-06-16 19:01:37 -07:00
kassens 126148e8ca Remove feature flag enableDO_NOT_USE_disableStrictPassiveEffect (#33524)
DiffTrain build for [5d24c64cc9](https://github.com/facebook/react/commit/5d24c64cc9c019fc644c4c6f0da640131b80ba18)
2025-06-16 09:32:35 -07:00
kassens 86066e82d0 Stringify context as SomeContext instead of SomeContext.Provider (#33507)
This matches the change in React 19 to use `<SomeContext>` as the
preferred way to provide a context.

DiffTrain build for [b7e2de632b](https://github.com/facebook/react/commit/b7e2de632b2a160bc09edda1fbb9b8f85a6914e8)
2025-06-11 09:14:54 -07:00
kassens 512c9fb930 Remove feature flag enableRenderableContext (#33505)
The flag is fully rolled out.

DiffTrain build for [6c86e56a0f](https://github.com/facebook/react/commit/6c86e56a0fa3c8f253da133330cd5b7d1d20e7e5)
2025-06-11 08:59:57 -07:00
07f9b02426 [Fiber] Fix hydration of useId in SuspenseList (#33491)
Includes #31412.

The issue is that `pushTreeFork` stores some global state when reconcile
children. This gets popped by `popTreeContext` in `completeWork`.
Normally `completeWork` returns its own `Fiber` again if it wants to do
a second pass which will call `pushTreeFork` again in the next pass.
However, `SuspenseList` doesn't return itself, it returns the next child
to work on.

The fix is to keep track of the count and push it again it when we
return the next child to attempt.

There are still some outstanding issues with hydration. Like the
backwards test still has the wrong behavior in it because it hydrates
backwards and so it picks up the DOM nodes in reverse order.
`tail="hidden"` also doesn't work correctly.

There's also another issue with `useId` and `AsyncIterable` in
SuspenseList when there's an unknown number of children. We don't
support those showing one at a time yet though so it's not an issue yet.
To fix it we need to add variable total count to the `useId` algorithm.
E.g. by falling back to varint encoding.

---------

Co-authored-by: Rick Hanlon <rickhanlonii@fb.com>
Co-authored-by: Ricky <rickhanlonii@gmail.com>

DiffTrain build for [c38e268978](https://github.com/facebook/react/commit/c38e26897848374c34ac6b651fce4a9088ed4dd0)
2025-06-09 16:47:18 -07:00
jbrown215 8b8eae7c2b [compiler] Don't include useEffectEvent values in autodeps (#33450)
Summary: useEffectEvent values are not meant to be added to the dep
array

DiffTrain build for [4df098c4c2](https://github.com/facebook/react/commit/4df098c4c2c51a033592ebc84abc47cc49a6bfb2)
2025-06-09 06:38:10 -07:00
javache a93b8dbee9 feat(ReactNative): prioritize attribute config process function to allow processing function props (#32119)
## Summary

In react-native props that are passed as function get converted to a
boolean (`true`). This is the default pattern for event handlers in
react-native.
However, there are reasons for why you might want to opt-out of this
behavior, and instead, pass along the actual function as the prop.
Right now, there is no way to do this, and props that are functions
always get set to `true`.
The `ViewConfig` attributes already have the API for a `process`
function. I simply moved the check for the process function up, so if a
ViewConfig's prop attribute configured a process function this is always
called first.
This provides an API to opt out of the default behavior.

This is the accompanied PR for react-native:

- https://github.com/facebook/react-native/pull/48777

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->

I modified the code manually in a template react-native app and
confirmed its working. This is a code path you only need in very special
cases, thus it's a bit hard to provide a test for this. I recorded a
video where you can see that the changes are active and the prop is
being passed as native value.

For this I created a custom native component with a view config that
looked like this:

```js
const viewConfig = {
  uiViewClassName: 'CustomView',
  bubblingEventTypes: {},
  directEventTypes: {},
  validAttributes: {
    nativeProp: {
      process: (nativeProp) => {
		// Identity function that simply returns the prop function callback
        // to opt out of this prop being set to `true` as its a function
        return nativeProp
      },
    },
  },
}
```

https://github.com/user-attachments/assets/493534b2-a508-4142-a760-0b1b24419e19

Additionally I made sure that this doesn't conflict with any existing
view configs in react native. In general, this shouldn't be a breaking
change, as for existing view configs it didn't made a difference if you
simply set `myProp: true` or `myProp: { process: () => {...} }` because
as soon as it was detected that the prop is a function the config
wouldn't be used (which is what this PR fixes).
Probably everyone, including the react-native core components use
`myProp: true` for callback props, so this change should be fine.

DiffTrain build for [911dbd9e34](https://github.com/facebook/react/commit/911dbd9e34048b21e96f24acb837b926687aa939)
2025-06-09 03:03:13 -07:00
sebmarkbage fa02f0ef85 Replace Implicit Options on SuspenseList with Explicit Options (#33424)
We want to change the defaults for `revealOrder` and `tail` on
SuspenseList. This is an intermediate step to allow experimental users
to upgrade.

To explicitly specify these options I added `revealOrder="independent"`
and `tail="visible"`.

I then added warnings if `undefined` or `null` is passed. You must now
always explicitly specify them. However, semantics are still preserved
for now until the next step.

We also want to change the rendering order of the `children` prop for
`revealOrder="backwards"`. As an intermediate step I first added
`revealOrder="unstable_legacy-backwards"` option. This will only be
temporary until all users can switch to the new `"backwards"` semantics
once we flip it in the next step.

I also clarified the types that the directional props requires iterable
children but not iterable inside of those. Rows with multiple items can
be modeled as explicit fragments.

DiffTrain build for [d742611ce4](https://github.com/facebook/react/commit/d742611ce40545127032f4e221c78bf9f70eb437)
2025-06-03 14:48:24 -07:00
sebmarkbage 2bb1f667a3 Use underscore instead of « » for useId algorithm (#33422)
Alternative to #33421. The difference is that this also adds an
underscore between the "R" and the ID.

The reason we wanted to use special characters is because we use the
full spectrum of A-Z 0-9 in our ID generation so we can basically
collide with any common word (or anyone using a similar algorithm,
base64 or even base16). It's a little less likely that someone would put
`_R_` specifically unless you generate like two IDs separated by
underscore.

![9w2ogt](https://github.com/user-attachments/assets/21b2d2ac-1a3a-4657-ba0b-1616e49dfdee)

DiffTrain build for [1ae0a845bd](https://github.com/facebook/react/commit/1ae0a845bde5b95dfc319cadf366cb7b3fb1ca92)
2025-06-03 08:38:09 -07:00
mofeiZ bd2cf53c3b [compiler][patch] Emit unary expressions instead of negative numbers (#33383)
This is a babel bug + edge case.

Babel compact mode produces invalid JavaScript (i.e. parse error) when
given a `NumericLiteral` with a negative value.

See https://codesandbox.io/p/devbox/5d47fr for repro.

DiffTrain build for [526dd340b3](https://github.com/facebook/react/commit/526dd340b3e77193846fe5eed02b9bb89d7c2d15)
2025-06-02 08:53:55 -07:00
javache 57bfa90fe3 Cleanup props diffing experiments (#33381)
## Summary

We completed testing on these internally, so can cleanup the separate
fast and slow paths and remove the `enableShallowPropDiffing` flag which
we're not pursuing.

## How did you test this change?

```
yarn test ReactNativeAttributePayloadFabric
```

DiffTrain build for [8b55eb4e72](https://github.com/facebook/react/commit/8b55eb4e724271206bd5dec7dba0a35aedc74493)
2025-05-30 09:27:12 -07:00
eps1lon 919208f846 [react-dom] Enforce small gap between completed navigation and default Transition indicator (#33354)
DiffTrain build for [5717f1933f](https://github.com/facebook/react/commit/5717f1933f2e8b10406fde1043c3047cbfbddc82)
2025-05-28 10:53:14 -07:00
mofeiZ e35cb5e59e [compiler][gating] Custom opt out directives (experimental option) (#33328)
Adding an experimental / unstable compiler config to enable custom
opt-out directives

DiffTrain build for [f9ae0a4c2e](https://github.com/facebook/react/commit/f9ae0a4c2edc9ad93507b550f2aeb60119955336)
2025-05-27 09:09:23 -07:00
jbrown215 9b5001edaf [eslint] Add an option to require dependencies on effect hooks (#33344)
Summary:

To prepare for automatic effect dependencies, some codebases may want to
codemod
existing useEffect calls with no deps to include an explicit undefined
second argument
in order to preserve the "run on every render" behavior. In sufficiently
large codebases,
this may require a temporary enforcement period where all effects
provide an explicit
dependencies argument.

Outside of migration, relying on a component to render can lead to real
bugs,
especially when working with memoization.

DiffTrain build for [99efc627a5](https://github.com/facebook/react/commit/99efc627a5a8cb56f50cfffee544c86c49572b6f)
2025-05-23 07:16:54 -07:00
sophiebits 556b910114 Fix incorrect use of NoLanes in executionContext check (#33170)
## Summary

This PR fixes a likely incorrect condition in the
`scheduleUpdateOnFiber` function inside `ReactFiberWorkLoop.js`.

Previously, the code checked:

```js
(executionContext & RenderContext) !== NoLanes
````

However, `NoLanes` is part of the lane priority system, not the
execution context flags. The intent here seems to be to detect whether
the current execution context includes `RenderContext`, which should be
compared against `NoContext`, not `NoLanes`.

This fix replaces `NoLanes` with `NoContext` for semantic correctness
and consistency with other checks throughout the codebase.

**Fixes
[[#33169](https://github.com/facebook/react/issues/33169)](https://github.com/facebook/react/issues/33169)**

---

## How did you test this change?

I ran the following commands to validate correctness and ensure nothing
was broken:

* `yarn lint`
* `yarn linc`
* `yarn test`
* `yarn test --prod`
* `yarn flow`
* `yarn prettier`

All checks passed. Since this is a minor internal logic fix and doesn't
change public behavior or APIs, no additional tests are necessary at
this time.

DiffTrain build for [bfaeb4a461](https://github.com/facebook/react/commit/bfaeb4a46175fa0f4edf2eba58349d5029e5e86e)
2025-05-22 19:10:04 -07:00
kassens 509acba3d9 Fix typo in error message. (#33313)
## Summary

I am writing code that isn't so good, so I saw this error message many
times. It appears to have a typo. This PR fixes the typo.

## How did you test this change?

Ran the tests

DiffTrain build for [3e9db65fc3](https://github.com/facebook/react/commit/3e9db65fc3341148a5248b3ffc6bc68c0640fd3f)
2025-05-22 13:25:12 -07:00
mofeiZ eed66bfa2c [compiler] Prepare HIRBuilder to be used by later passes (#32286)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32286).
* #33326
* #33325
* __->__ #32286

DiffTrain build for [13f20044f3](https://github.com/facebook/react/commit/13f20044f3a5a9433eb4c6ef4c6577b8f0d13350)
2025-05-22 13:20:39 -07:00
mofeiZ 27e38b43c9 [compiler][gating] Experimental directive based gating (#33149)
Adds `dynamicGating` as an experimental option for testing rollout DX at
Meta. If specified, this enables dynamic gating which matches `use memo
if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33149).
* __->__ #33149
* #33148

DiffTrain build for [459a2c4298](https://github.com/facebook/react/commit/459a2c4298187cb0ee45605e2575ff35f4a81183)
2025-05-21 14:30:02 -07:00
jackpope b850e17e7b New children notify fragment instances in Fabric (#33093)
When a new child of a fragment instance is inserted, we need to notify
the instance to keep any relevant tracking up to date. For example, we
automatically observe the new child with any active
IntersectionObserver.

For mutable renderers (DOM), we reuse the existing traversal in
`commitPlacement` that does the insertions for HostComponents. Immutable
renderers (Fabric) exit this path before the traversal though, so
currently we can't notify the fragment instances.

Here I've created a separate traversal in `commitPlacement`,
specifically for immutable renders when `enableFragmentRefs` is on.

DiffTrain build for [1835b3f7d9](https://github.com/facebook/react/commit/1835b3f7d9c0541259a8812c5dfaf3d77f0721eb)
2025-05-21 12:54:11 -07:00
sebmarkbage e76c45254e [Fiber] Support AsyncIterable children in SuspenseList (#33299)
We support AsyncIterable (more so when it's a cached form like in coming
from Flight) as children.

This fixes some warnings and bugs when passed to SuspenseList.

Ideally SuspenseList with `tail="hidden"` should support unblocking
before the full result has resolved but that's an optimization on top.
We also might want to change semantics for this for
`revealOrder="backwards"` so it becomes possible to stream items in
reverse order.

DiffTrain build for [4c6967be29](https://github.com/facebook/react/commit/4c6967be290fc31182c61cfdac19915fdb16aa60)
2025-05-20 06:46:21 -07:00
josephsavona d4ef296f8a [compiler] Fix error message for custom hooks (#33310)
We were printing "Custom" instead of "hook".

DiffTrain build for [c6c2a52ad8](https://github.com/facebook/react/commit/c6c2a52ad8fb1894b03a3bb618eb57e5deca5aa0)
2025-05-19 15:36:47 -07:00
kassens bbd4a494c7 [eslint-plugin-react-hooks] add experimental_autoDependenciesHooks option (#33294)
DiffTrain build for [a3abf5f2f8](https://github.com/facebook/react/commit/a3abf5f2f835ad0c61e2325f5cbac2d1d9045517)
2025-05-19 12:19:59 -07:00
kassens 129579cd4e [eslint-plugin-react-hooks] fix exhaustive deps lint rule with component syntax (#33182)
DiffTrain build for [4448b18760](https://github.com/facebook/react/commit/4448b18760d867f9e009e810571e7a3b8930bb19)
2025-05-15 09:57:33 -07:00
poteto 512e02997e [ci] Log author_association (#33213)
For debugging purposes, log author_association

DiffTrain build for [08cb2d7ee7](https://github.com/facebook/react/commit/08cb2d7ee732f35ef1935c75c081754bd81d60b9)
2025-05-15 08:57:12 -07:00
poteto 086827942b [compiler] Update changelog for 19.1.0-rc.2 (#33207)
Update the changelog.

DiffTrain build for [203df2c940](https://github.com/facebook/react/commit/203df2c9409f580fd63eeacd4f80d70c2741bd4f)
2025-05-15 07:40:34 -07:00
sebmarkbage 4ca6bfb8e7 [Fizz] Add vt- prefix attributes to annotate <ViewTransition> in HTML (#33206)
Stacked on #33194 and #33200.

When Suspense boundaries reveal during streaming, the Fizz runtime will
be responsible for animating the reveal if necessary (not in this PR).
However, for the future runtime to know what to do it needs to know
about the `<ViewTransition>` configuration to apply.

Ofc, these are virtual nodes that disappear from the HTML. We could
model them as comments like we do with other virtual nodes like Suspense
and Activity. However, that doesn't let us target them with
querySelector and CSS (for no-JS transitions). We also don't have to
model every ViewTransition since not every combination can happen using
only the server runtime. So instead this collapses `<ViewTransition>`
and applies the configuration to the inner DOM nodes.

```js
<ViewTransition name="hi">
  <div />
  <div />
</ViewTransition>
```

Becomes:

```html
<div vt-name="hi" vt-update="auto"></div>
<div vt-name="hi_1" vt-update="auto"></div>
```

I use `vt-` prefix as opposed to `data-` to keep these virtual
attributes away from user specific ones but we're effectively claiming
this namespace.

There are four triggers `vt-update`, `vt-enter`, `vt-exit` and
`vt-share`. The server resolves which ones might apply to this DOM node.
The value represents the class name (after resolving
view-transition-type mappings) or `"auto"` if no specific class name is
needed but this is still a trigger.

The value can also be `"none"`. This is different from missing because
for example an `vt-update="none"` will block mutations inside it from
triggering the boundary where as a missing `vt-update` would bubble up
to be handled by a parent.

`vt-name` is technically only necessary when `vt-share` is specified to
find a pair. However, since an explicit name can also be used to target
specific CSS selectors, we include it even for other cases.

We want to exclude as many of these annotations as possible.

`vt-enter` can only affect the first DOM node inside a Suspense
boundary's content since the reveal would cause it to enter but nothing
deeper inside. Similarly `vt-exit` can only affect the first DOM node
inside a fallback. So for every other case we can exclude them. (For
future MPA ViewTransitions of the whole document it might also be
something we annotate to children inside the `<body>` as well.) Ideally
we'd only include `vt-enter` for Suspense boundaries that actually
flushed a fallback but since we prepare all that content earlier it's
hard to know.

`vt-share` can be anywhere inside an fallback or content. Technically we
don't have to include it outside the root most Suspense boundary or for
boundaries that are inlined into the root shell. However, this is tricky
to detect. It would also not be correct for future MPA ViewTransitions
because in that case the shared scenario can affect anything in the two
documents so it needs to be in every node everywhere which is
effectively what we do. If a `share` class is specified but it has no
explicit name, we can exclude it since it can't match anything.

`vt-update` is only necessary if something below or a sibling might
update like a Suspense boundary. However, since we don't know when
rendering a segment if it'll later asynchronously add a Suspense
boundary later we have to assume that anywhere might have a child. So
these are always included. We collapse to use the inner most one when
directly nested though since that's the one that ends up winning.

There are some weird edge cases that can't be fully modeled by the lack
of virtual nodes.

DiffTrain build for [65b5aae010](https://github.com/facebook/react/commit/65b5aae010002ef88221cc4998711eaef6068006)
2025-05-14 22:11:47 -07:00
sebmarkbage 07b3f038b6 [Fizz] Track whether we're in a fallback on FormatContext (#33194)
Removes the `isFallback` flag on Tasks and tracks it on the
formatContext instead.

Less memory and avoids passing and tracking extra arguments to all the
pushStartInstance branches that doesn't need it.

We'll need to be able to track more Suspense related contexts on this
for View Transitions anyway.

DiffTrain build for [3f67d0857e](https://github.com/facebook/react/commit/3f67d0857efc3ab21b9d30851f5a8451471166ab)
2025-05-14 22:08:30 -07:00
sebmarkbage 0f43f35f84 Claim the useId name space for every auto named ViewTransition (#33200)
This is a partial revert of #33094. It's true that we don't need the
server and client ViewTransition names to line up. However the server
does need to be able to generate deterministic names for itself. The
cheapest way to do that is using the useId algorithm. When it's used by
the server, the client needs to also materialize an ID even if it
doesn't use it.

DiffTrain build for [96eb84e493](https://github.com/facebook/react/commit/96eb84e493c4ff2c280990659057164c0f16bbb8)
2025-05-14 15:41:12 -07:00
sebmarkbage ba5b805801 Don't consider Portals animating unless they're wrapped in a ViewTransition (#33191)
And that doesn't disable with `update="none"`.

The principle here is that we want the content of a Portal to animate if
other things are animating with it but if other things aren't animating
then we don't.

DiffTrain build for [63d664b220](https://github.com/facebook/react/commit/63d664b220b1587da0f3b4ced895456f3d8320da)
2025-05-14 15:29:31 -07:00
kassens f948e0357f Delete stray file (#33199)
Not sure where this was coming from.

DiffTrain build for [d85f86cf01](https://github.com/facebook/react/commit/d85f86cf017151bcf5908d593c3899d876656a01)
2025-05-14 08:34:07 -07:00
sebmarkbage 533b5a9967 [Fiber] Trigger default indicator for isomorphic async actions with no root associated (#33190)
Stacked on #33160, #33162, #33186 and #33188.

We have a special case that's awkward for default indicators. When you
start a new async Transition from `React.startTransition` then there's
not yet any associated root with the Transition because you haven't
necessarily `setState` on anything yet until the promise resolves.
That's what `entangleAsyncAction` handles by creating a lane that
everything entangles with until all async actions are done.

If there are no sync updates before the end of the event, we should
trigger a default indicator until either the async action completes
without update or if it gets entangled with some roots we should keep it
going until those roots are done.

DiffTrain build for [3a5b326d81](https://github.com/facebook/react/commit/3a5b326d8180f005a10e34a07ded6d5632efe337)
2025-05-13 13:18:04 -07:00
sebmarkbage 9c65b7e39a Implement Navigation API backed default indicator for DOM renderer (#33162)
Stacked on #33160.

By default, if `onDefaultTransitionIndicator` is not overridden, this
will trigger a fake Navigation event using the Navigation API. This is
intercepted to create an on-going navigation until we complete the
Transition. Basically each default Transition is simulated as a
Navigation.

This triggers the native browser loading state (in Chrome at least). So
now by default the browser spinner spins during a Transition if no other
loading state is provided. Firefox and Safari hasn't shipped Navigation
API yet and even in the flag Safari has, it doesn't actually trigger the
native loading state.

To ensures that you can still use other Navigations concurrently, we
don't start our fake Navigation if there's one on-going already.
Similarly if our fake Navigation gets interrupted by another. We wait
for on-going ones to finish and then start a new fake one if we're
supposed to be still pending.

There might be other routers on the page that might listen to intercept
Navigation Events. Typically you'd expect them not to trigger a refetch
when navigating to the same state. However, if they want to detect this
we provide the `"react-transition"` string in the `info` field for this
purpose.

DiffTrain build for [59440424d0](https://github.com/facebook/react/commit/59440424d05360cca32ca6f46ae33661f70d43e2)
2025-05-13 13:07:35 -07:00
sebmarkbage ffe6305552 [Fiber] Always flush Default priority in the microtask if a Transition was scheduled (#33186)
Stacked on #33160.

The purpose of this is to avoid calling `onDefaultTransitionIndicator`
when a Default priority update acts as the loading indicator, but still
call it when unrelated Default updates happens nearby.

When we schedule Default priority work that gets batched with other
events in the same frame more or less. This helps optimize by doing less
work. However, that batching means that we can't separate work from one
setState from another. If we would consider all Default priority work in
a frame when determining whether to show the default we might never show
it in cases like when you have a recurring timer updating something.

This instead flushes the Default priority work eagerly along with the
sync work at the end of the event, if this event scheduled any
Transition work. This is then used to determine if the default indicator
needs to be shown.

DiffTrain build for [b480865db0](https://github.com/facebook/react/commit/b480865db0babfcad602a1a1909775069b5779f9)
2025-05-13 12:59:50 -07:00
sebmarkbage 863c41cd67 [Fiber] Trigger default transition indicator if needed (#33160)
Stacked on #33159.

This implements `onDefaultTransitionIndicator`.

The sequence is:

1) In `markRootUpdated` we schedule Transition updates as needing
`indicatorLanes` on the root. This tracks the lanes that currently need
an indicator to either start or remain going until this lane commits.
2) Track mutations during any commit. We use the same hook that view
transitions use here but instead of tracking it just per view transition
scope, we also track a global boolean for the whole root.
3) If a sync/default commit had any mutations, then we clear the
indicator lane for the `currentEventTransitionLane`. This requires that
the lane is still active while we do these commits. See #33159. In other
words, a sync update gets associated with the current transition and it
is assumed to be rendering the loading state for that corresponding
transition so we don't need a default indicator for this lane.
4) At the end of `processRootScheduleInMicrotask`, right before we're
about to enter a new "event transition lane" scope, it is no longer
possible to render any more loading states for the current transition
lane. That's when we invoke `onDefaultTransitionIndicator` for any roots
that have new indicator lanes.
5) When we commit, we remove the finished lanes from `indicatorLanes`
and once that reaches zero again, then we can clean up the default
indicator. This approach means that you can start multiple different
transitions while an indicator is still going but it won't stop/restart
each time. Instead, it'll wait until all are done before stopping.

Follow ups:

- [x] Default updates are currently not enough to cancel because those
aren't flush in the same microtask. That's unfortunate. #33186
- [x] Handle async actions before the setState. Since these don't
necessarily have a root this is tricky. #33190
- [x] Disable for `useDeferredValue`. ~Since it also goes through
`markRootUpdated` and schedules a Transition lane it'll get a default
indicator even though it probably shouldn't have one.~ EDIT: Turns out
this just works because it doesn't go through `markRootUpdated` when
work is left behind.
- [x] Implement built-in DOM version by default. #33162

DiffTrain build for [62d3f36ea7](https://github.com/facebook/react/commit/62d3f36ea79fc0a10b514d4bbcc4ba3f21b3206e)
2025-05-13 12:52:35 -07:00
sebmarkbage bb4b9e402e Reset currentEventTransitionLane after flushing sync work (#33159)
This keeps track of the transition lane allocated for this event. I want
to be able to use the current one within sync work flushing to know
which lane needs its loading indicator cleared.

It's also a bit weird that transition work scheduled inside sync updates
in the same event aren't entangled with other transitions in that event
when `flushSync` is.

Therefore this moves it to reset after flushing.

It should have no impact. Just splitting it out into a separate PR for
an abundance of caution.

The only thing this might affect would be if the React internals throws
and it doesn't reset after. But really it doesn't really have to reset
and they're all entangled anyway.

DiffTrain build for [676f0879f3](https://github.com/facebook/react/commit/676f0879f315130309262ff3532707029f0288bb)
2025-05-13 12:28:58 -07:00
sebmarkbage 4a0575d571 [Fiber] Stash the entangled async action lane on currentEventTransitionLane (#33188)
When we're entangled with an async action lane we use that lane instead
of the currentEventTransitionLane. Conversely, if we start a new async
action lane we reuse the currentEventTransitionLane.

So they're basically supposed to be in sync but they're not if you
resolve the async action and then schedule new stuff in the same event.
Then you end up with two transitions in the same event with different
lanes.

By stashing it like this we fix that but it also gives us an opportunity
to check just the currentEventTransitionLane to see if this event
scheduled any regular Transition updates or Async Transitions.

DiffTrain build for [0cac32d60d](https://github.com/facebook/react/commit/0cac32d60dd4482b27fe8a54dffbabceb22c6272)
2025-05-13 12:27:45 -07:00
sebmarkbage 282bf23bad [DevTools] Get source location from structured callsites in prepareStackTrace (#33143)
When we get the source location for "View source for this element" we
should be using the enclosing function of the callsite of the child. So
that we don't just point to some random line within the component.

This is similar to the technique in #33136.

This technique is now really better than the fake throw technique, when
available. So I now favor the owner technique. The only problem it's
only available in DEV and only if it has a child that's owned (and not
filtered).

We could implement this same technique for the error that's thrown in
the fake throwing solution. However, we really shouldn't need that at
all because for client components we should be able to call
`inspect(fn)` at least in Chrome which is even better.

DiffTrain build for [997c7bc930](https://github.com/facebook/react/commit/997c7bc930304142b3af37bcb21599181124aeb4)
2025-05-13 09:46:46 -07:00
sebmarkbage d5a02f564b [Fizz] Gate rel="expect" behind enableFizzBlockingRender (#33183)
Enabled in experimental channel.

We know this is critical semantics to enforce at the HTML level since if
you don't then you can't add explicit boundaries after the fact.
However, this might have to go in a major release to allow for
upgrading.

DiffTrain build for [b94603b955](https://github.com/facebook/react/commit/b94603b95504130aec72f61e02d7b66d48f33653)
2025-05-13 07:24:17 -07:00
sebmarkbage f090b69fca [ReactFlightWebpackPlugin] Add support for .mjs file extension (#33028)
## Summary
Our builds generate files with a `.mjs` file extension. These are
currently filtered out by `ReactFlightWebpackPlugin` so I am updating it
to support this file extension.

This fixes https://github.com/facebook/react/issues/33155

## How did you test this change?
I built the plugin with this change and used `yalc` to test it in my
project. I confirmed the expected files now show up in
`react-client-manifest.json`

DiffTrain build for [2bcf06b692](https://github.com/facebook/react/commit/2bcf06b69254cad6f7e702bf7d65c4f30478668c)
2025-05-12 18:23:26 -07:00
sammy-SC 79b68866d3 Add eager alternate.stateNode cleanup (#33161)
This is a fix for a problem where React retains shadow nodes longer than
it needs to. The behaviour is shown in React Native test:
https://github.com/facebook/react-native/blob/main/packages/react-native/src/private/__tests__/utilities/__tests__/ShadowNodeReferenceCounter-itest.js#L169

# Problem
When React commits a new shadow tree, old shadow nodes are stored inside
`fiber.alternate.stateNode`. This is not cleared up until React clones
the node again. This may be problematic if mutation deletes a subtree,
in that case `fiber.alternate.stateNode` will retain entire subtree
until next update. In case of image nodes, this means retaining entire
images.

So when React goes from revision A: `<View><View /></View>` to revision
B: `<View />`, `fiber.alternate.stateNode` will be pointing to Shadow
Node that represents revision A..

![image](https://github.com/user-attachments/assets/076b677e-d152-4763-8c9d-4f923212b424)

# Fix
To fix this, this PR adds a new feature flag
`enableEagerAlternateStateNodeCleanup`. When enabled,
`alternate.stateNode` is proactively pointed towards finishedWork's
stateNode, releasing resources sooner.

I have verified this fixes the issue [demonstrated by React Native
tests](https://github.com/facebook/react-native/blob/main/packages/react-native/src/private/__tests__/utilities/__tests__/ShadowNodeReferenceCounter-itest.js#L169).
All existing React tests pass when the flag is enabled.

DiffTrain build for [5d04d73274](https://github.com/facebook/react/commit/5d04d73274a884ed53106677d56dd837ae668c45)
2025-05-12 09:45:35 -07:00
mofeiZ 865800150c [compiler][entrypoint] Fix edgecases for noEmit and opt-outs (#33148)
Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* #33149
* __->__ #33148

DiffTrain build for [3820740a7f](https://github.com/facebook/react/commit/3820740a7fbfc3b27a5127b43bdad44382ff3ce0)
2025-05-09 10:44:40 -07:00
mofeiZ 3f8a69cee6 [compiler][be] Make program traversal more readable (#33147)
React Compiler's program traversal logic is pretty lengthy and complex
as we've added a lot of features piecemeal. `compileProgram` is 300+
lines long and has confusing control flow (defining helpers inline,
invoking visitors, mutating-asts-while-iterating, mutating global
`ALREADY_COMPILED` state).

- Moved more stuff to `ProgramContext`
- Separated `compileProgram` into a bunch of helpers

Tested by syncing this stack to a Meta codebase and observing no
compilation output changes (D74487851, P1806855669, P1806855379)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33147).
* #33149
* #33148
* __->__ #33147

DiffTrain build for [5069e18060](https://github.com/facebook/react/commit/5069e18060e00d7c07b2b04ebc8a3fa21e2d810a)
2025-05-09 10:29:54 -07:00
huntie 038fe5aafd Root import types from react-native in ReactNativeTypes (#33063)
DiffTrain build for [9518f11856](https://github.com/facebook/react/commit/9518f1185621aecb99fd72385cdb137c6e8bd8fe)
2025-05-09 04:18:34 -07:00
sebmarkbage e9cd841727 Use a shared noop function from shared/noop (#33154)
Stacked on #33150.

We use `noop` functions in a lot of places as place holders. I don't
think there's any real optimizations we get from having separate
instances. This moves them to use a common instance in `shared/noop`.

DiffTrain build for [21fdf308a1](https://github.com/facebook/react/commit/21fdf308a1a01af69c28c00a70086aa1bd4c2411)
2025-05-08 18:40:16 -07:00