Commit Graph
2213 Commits
Author SHA1 Message Date
Sam ZhouandGitHub 78cf315a48 [flow] Bump flow to v0.307.1 (#36199)
## Summary

Notable changes:
- Only $FlowFixMe, $FlowExpectedError suppression comments are supported
- All suppression comments need error code
- A lot of new invalid-compare and constant-condition errors suppressed.
These errors reveal potential logical bugs

## How did you test this change?

`yarn flow-ci`
2026-06-05 13:54:38 -04:00
Sebastian "Sebbie" SilbermannandGitHub 3f6785f59e [flags] Cleanup enableActivity (#36603) 2026-06-03 12:00:26 +02:00
Hendrik LiebauandGitHub b07aa4e27c [Flight] Fix stranded row content under Node stream backpressure (#36516)
The Flight Server emits Text and TypedArray rows as two chunks: a header
that gives the row's id, type, and content length, followed by the
content itself. These two chunks were pushed into
`completedRegularChunks` (and `completedDebugChunks` in DEV) as separate
items, so when the destination signaled backpressure between them, the
flush would write the header and then break out before reaching the
content. The content chunk was left stranded at the head of the queue.
Async work running while the destination was paused appended new rows to
`completedImportChunks` / `completedHintChunks`, and the next drain
flushed those queues first — splicing the newly-arrived bytes into the
position the Flight Client expects to read as the original row's
content. From there the Flight Client read rows from the wrong byte
offsets and the model failed to deserialize.

This only surfaced on the Node stream path.
`createFakeWritableFromReadableStreamController`, used by
`renderToReadableStream`, always returns `true` from `write()`, so the
flush loop never saw backpressure.

The fix pushes a `NEXT_TWO_CHUNKS_ARE_ATOMIC` sentinel ahead of each
`headerChunk` / `contentChunk` pair in `completedRegularChunks` and
`completedDebugChunks`. The flush loops detect the sentinel and write
the two chunks that follow it together before re-checking backpressure,
so backpressure can still break between rows but never within one.

### Alternatives considered

- **Pushing the pair as a `[headerChunk, contentChunk]` tuple.** Simpler
but allocates an array per row. The required `isArray` branch in the
flush hot path is likely comparable with the symbol check. This also
violates the opaque `Chunk` type boundary.
- **Concatenating header and content into one chunk.** Bad for memory —
typed-array content can be large.
- **Storing atomic groups in a separate queue.** Conceptually wrong and
risks breaking reference-ordering assumptions between rows.
- **Ignoring backpressure until the regulars queue is empty.** Defeats
the point of backpressure.
- **Wrapping the tuple behind a host-config API** (`writeAdjacentChunks`
/ `isAdjacentChunks` / `chunksToAdjacentChunks` /
`getAdjacentChunksLength`). Keeps the implementation opaque but adds
four exports per host config. Also has the tuple overhead.
- **Begin/end sentinels for variable-length atomic groups.** Not needed
— only Text and TypedArray rows use this pattern, and both are pairs.
2026-05-27 22:19:49 +02:00
Sebastian "Sebbie" SilbermannandGitHub b7cfd78d06 Throw special error if rejected Promises are incorrectly instrumented (#36328)
When a rejected `Promise` is instrumented in userspace while setting the
rejection reason in the wrong field (e.g. `error` instead of `reason`),
React will throw undefined (because `usable.reason` doesn't exist). This
makes it incredibly hard to find the actual rejection reason.

React is now throwing a generic error if we couldn't find the rejection
reason. That will produce a callstack pointing into the problematic
Promise from where you can hopefully extract the real rejection reason
(alongside fixing the bad instrumentation).

We're doing this in prod since this is unlikely to surface in dev. We're
only doing runtime type-checking for the rejected case. That should be
hit rarely and therefore hopefully have negligible runtime impact.
2026-05-27 12:00:17 +02:00
Sebastian "Sebbie" SilbermannandGitHub 7933c39a26 Stop transpiling computed property names (#36542) 2026-05-26 21:48:53 +02:00
Sebastian "Sebbie" SilbermannandGitHub 32abdbca5a Unified release process (#36456) 2026-05-26 17:23:27 +02:00
Ruslan LesiutinandGitHub e72dc6f733 fix[describeClassComponentFrame]: invoke constructor with new keyword (#36455)
For JavaScript runtimes that do not have
[`Reflect`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
supported, we had a fall back that was calling the constructor with
overridden `this` context via
```
fn.apply(Fake.prototype);
```

In ES6, it is required to call constructor only with the `new` keyword,
otherwise the runtime is expected to throw a corresponding TypeError:
```
TypeError: Class constructor <> cannot be invoked without 'new'
```

We've observed this error in Hermes runtime, but this is applicable to
V8 or any other runtime. The only reason why V8 wasn't affected is
because it implemented Reflect APIs.

Instead of the incorrect call, we will fall back to calling `new fn()`,
but with a temporary patched prototype of the class, which would make a
trap out of the setter for `props` object. We use the same approach when
`Reflect` APIs are available, but instead of modifying the prototype, we
pass the fake context:

https://github.com/facebook/react/blob/878b6fb60ce5a2347ec1bfa0741edf0b2d08f157/packages/shared/ReactComponentStackFrame.js#L129-L148


---

See tests implemented. Without the changes, the test would fail with the
`TypeError` mentioned above.
2026-05-13 22:05:14 +01:00
8844bdb164 [FlightReply] Type hardening and performance improvements (#36425)
Co-authored-by: Hendrik Liebau <[email protected]>
2026-05-06 19:39:45 +02:00
Ruslan LesiutinandGitHub 5f7d82e8cc [enableInfiniteRenderLoopDetection] Add a flag to force throwing (#36357)
Adds a `enableInfiniteRenderLoopDetectionForceThrow` flag, which changes
the detection mechanism behaviour to start throwing, when the loop is
observed. By default, the value is set to `false`, also made dynamic
from the start for `www`.
2026-04-29 21:12:57 +01:00
Xinzi ZhouandGitHub 4c56e37e58 Add react-flight-server-fb package for Meta's internal bundler (#36309)
<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->

- Adds a new react-flight-server-fb package providing RSC Flight
bindings for Meta's internal bundler stack
- Unlike webpack/turbopack integrations, this uses no manifest. Module
metadata is self-contained in ClientReference objects and sent over the
wire as-is
- Registers dom-browser-fb and dom-node-fb host configs for Rollup
builds targeting FB_WWW_DEV and FB_WWW_PROD

 Key design differences from other bundler

 - No build-time manifest
- Module IDs use Haste module names (e.g. `"MyComponent"`), with named
exports encoded as `"Module#export"`, rather than file paths resolved
through a manifest
- Client-side loading uses `Bootloader.handlePayload()` +
`JSResource().load()`
- `resolveClientReferenceMetadata` and `resolveClientReference` are
pass-throughs

## 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.
-->

E2E integration test is set up on Meta's internal system.
2026-04-27 09:48:37 -07:00
Sebastian "Sebbie" SilbermannandGitHub 15c64f7199 Minify prod error messages for all browser bundles (#36277) 2026-04-17 18:01:56 +02:00
Zeya PengandGitHub 4091c3f410 Wire up createViewTransitionInstance and suspendOnActiveViewTransition in Fabric (#36196)
## Summary
- Wires up the native `fabricCreateViewTransitionInstance` call in
`createViewTransitionInstance` which will create a ShadowNode for old
pseudo element
- Extracts tag allocation logic into a shared `allocateTag()` function
exported from `ReactFiberConfigFabric`
  - Imports `allocateTag` in `ReactFiberConfigFabricWithViewTransition`
- Reuses `allocateTag()` in `createInstance` and `createTextInstance`
instead of inline tag incrementing
- Wires up native `fabricSuspendOnActiveViewTransition` call in
`suspendOnActiveViewTransition` which suspends another view transition
when the previous one is not yet finished

## Test plan
- Existing Fabric renderer tests should continue to pass
- ViewTransition instance creation now properly allocates a tag and
calls the native module
2026-04-16 16:59:54 -04:00
Zeya PengandGitHub a63571a0fd Wire up startViewTransitionReadyFinished in Fabric (#36246)
## Summary
- Imports `startViewTransitionReadyFinished` from
`nativeFabricUIManager` in `ReactFiberConfigFabricWithViewTransition`
- Calls `fabricStartViewTransitionReadyFinished()` when the view
transition `ready` promise resolves

This is not a config function, but it's helpful to have it notify fabric
ViewTransition runtime when ready callback is done. Right now we're
testing animation kicked off from view transition event handlers, this
is signal to know when animations that belong to a transition have all
started.

## Test plan
- Existing Fabric renderer tests should continue to pass
- View transition ready callback now notifies the native module when
finished
2026-04-16 16:41:05 -04:00
Rubén NorteandGitHub 273365041c [react-native-renderer] Delete Paper (legacy) renderer (#36285)
## Summary

The Paper renderer is no longer used in React Native. This commit
removes all remaining Paper source code, tests, build system references,
and Paper backward-compatibility branches in shared code.

Deleted Paper-only source files:
- ReactNativeRenderer.js, ReactNativeInjection.js,
ReactFiberConfigNative.js
- ReactNativeComponentTree.js, ReactNativeEventEmitter.js
- ReactNativeFiberHostComponent.js, ReactNativeGlobalResponderHandler.js
- ReactNativeAttributePayload.js, NativeMethodsMixinUtils.js
- ReactFiberConfig.native.js (reconciler fork)
- index.js (Paper entry point)

Cleaned up shared files:
- ReactNativePublicCompat.js: removed _nativeTag checks, UIManager/
legacySendAccessibilityEvent Paper fallbacks
- ReactNativeFiberInspector.js: removed getInspectorDataForViewTag,
UIManager.measure fallback, Paper branch in
getInspectorDataForViewAtPoint
- ReactFiberConfigFabric.js: removed _nativeTag backward compat in
getPublicInstance, removed getInspectorDataForViewTag from devtools
config
- ReactNativeTypes.js: removed ReactNativeType (Paper API type)

Cleaned up build system:
- inlinedHostConfigs.js: removed shortName 'native' config
- forks.js: removed dead 'react-native-renderer' case
- Deleted ReactNative.js shim and Paper-only test mocks

## How did you test this change?

Manually synced the renderer to RN and passed all Fantom tests.

Manually verified the differences in the generated `ReactFabric-dev.js`
file. Only Paper compat logic has been removed.

<details>
<summary>diff</summary> 

```diff
--- /tmp/react-fabric-baseline/ReactFabric-dev.js	2026-04-16 16:42:42
+++ build/react-native/implementations/ReactFabric-dev.js	2026-04-16 18:08:43
@@ -30,43 +30,19 @@
         : emptyObject;
     }
     function createHierarchy(fiberHierarchy) {
-      return fiberHierarchy.map(function (fiber$jscomp$0) {
+      return fiberHierarchy.map(function (fiber) {
         return {
-          name: getComponentNameFromType(fiber$jscomp$0.type),
+          name: getComponentNameFromType(fiber.type),
           getInspectorData: function () {
             return {
-              props: getHostProps(fiber$jscomp$0),
+              props: getHostProps(fiber),
               measure: function (callback) {
-                var hostFiber = findCurrentHostFiber(fiber$jscomp$0);
-                if (
-                  (hostFiber =
-                    null != hostFiber &&
-                    null !== hostFiber.stateNode &&
-                    hostFiber.stateNode.node)
-                )
+                var hostFiber = findCurrentHostFiber(fiber);
+                (hostFiber =
+                  null != hostFiber &&
+                  null !== hostFiber.stateNode &&
+                  hostFiber.stateNode.node) &&
                   nativeFabricUIManager.measure(hostFiber, callback);
-                else {
-                  hostFiber = ReactNativePrivateInterface.UIManager;
-                  var JSCompiler_temp_const = hostFiber.measure,
-                    JSCompiler_inline_result;
-                  a: {
-                    for (var fiber = fiber$jscomp$0; fiber; ) {
-                      null !== fiber.stateNode &&
-                        5 === fiber.tag &&
-                        (JSCompiler_inline_result = findNodeHandle(
-                          fiber.stateNode
-                        ));
-                      if (JSCompiler_inline_result) break a;
-                      fiber = fiber.child;
-                    }
-                    JSCompiler_inline_result = null;
-                  }
-                  return JSCompiler_temp_const.call(
-                    hostFiber,
-                    JSCompiler_inline_result,
-                    callback
-                  );
-                }
               }
             };
           }
@@ -1805,18 +1781,6 @@
       }
       return null;
     }
-    function doesFiberContain(parentFiber, childFiber) {
-      for (
-        var parentFiberAlternate = parentFiber.alternate;
-        null !== childFiber;
-
-      ) {
-        if (childFiber === parentFiber || childFiber === parentFiberAlternate)
-          return !0;
-        childFiber = childFiber.return;
-      }
-      return !1;
-    }
     function traverseVisibleHostChildren(
       child,
       searchWithinHosts,
@@ -16986,44 +16950,6 @@
     function getCurrentFiberForDevTools() {
       return current;
     }
-    function findNodeHandle(componentOrHandle) {
-      var owner = current;
-      null !== owner &&
-        isRendering &&
-        null !== owner.stateNode &&
-        (owner.stateNode._warnedAboutRefsInRender ||
-          console.error(
-            "%s is accessing findNodeHandle inside its render(). render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead.",
-            getComponentNameFromType(owner.type) || "A component"
-          ),
-        (owner.stateNode._warnedAboutRefsInRender = !0));
-      if (null == componentOrHandle) return null;
-      if ("number" === typeof componentOrHandle) return componentOrHandle;
-      if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag;
-      if (
-        null != componentOrHandle.canonical &&
-        null != componentOrHandle.canonical.nativeTag
-      )
-        return componentOrHandle.canonical.nativeTag;
-      if (
-        (owner =
-          ReactNativePrivateInterface.getNativeTagFromPublicInstance(
-            componentOrHandle
-          ))
-      )
-        return owner;
-      componentOrHandle = findHostInstanceWithWarning(
-        componentOrHandle,
-        "findNodeHandle"
-      );
-      return null == componentOrHandle
-        ? componentOrHandle
-        : null != componentOrHandle._nativeTag
-          ? componentOrHandle._nativeTag
-          : ReactNativePrivateInterface.getNativeTagFromPublicInstance(
-              componentOrHandle
-            );
-    }
     function getNodeFromInternalInstanceHandle(internalInstanceHandle) {
       return (
         internalInstanceHandle &&
@@ -17134,12 +17060,9 @@
         }
         return instance.canonical.publicInstance;
       }
-      return null != instance.containerInfo &&
-        null != instance.containerInfo.publicInstance
+      return null != instance.containerInfo
         ? instance.containerInfo.publicInstance
-        : null != instance._nativeTag
-          ? instance
-          : null;
+        : null;
     }
     function getPublicInstanceFromHostFiber(fiber) {
       fiber = getPublicInstance(fiber.stateNode);
@@ -18017,7 +17940,6 @@
       DefaultEventPriority = 32,
       IdleEventPriority = 268435456,
       searchTarget = null,
-      instanceCache = new Map(),
       bind = Function.prototype.bind,
       valueStack = [];
     var fiberStack = [];
@@ -20041,24 +19963,19 @@
         _nativeFabricUIManage.unstable_getCurrentEventPriority,
       extraDevToolsConfig = {
         getInspectorDataForInstance: getInspectorDataForInstance,
-        getInspectorDataForViewTag: function (viewTag) {
-          viewTag = instanceCache.get(viewTag) || null;
-          return getInspectorDataForInstance(viewTag);
-        },
         getInspectorDataForViewAtPoint: function (
           inspectedView,
           locationX,
           locationY,
           callback
         ) {
-          var closestInstance = null,
-            fabricNode =
-              ReactNativePrivateInterface.getNodeFromPublicInstance(
-                inspectedView
-              );
-          fabricNode
+          var closestInstance = null;
+          (inspectedView =
+            ReactNativePrivateInterface.getNodeFromPublicInstance(
+              inspectedView
+            ))
             ? nativeFabricUIManager.findNodeAtPoint(
-                fabricNode,
+                inspectedView,
                 locationX,
                 locationY,
                 function (internalInstanceHandle) {
@@ -20109,32 +20026,9 @@
                   }
                 }
               )
-            : null != inspectedView._internalFiberInstanceHandleDEV
-              ? ReactNativePrivateInterface.UIManager.findSubviewIn(
-                  findNodeHandle(inspectedView),
-                  [locationX, locationY],
-                  function (nativeViewTag, left, top, width, height) {
-                    var inspectorData = getInspectorDataForInstance(
-                      instanceCache.get(nativeViewTag) || null
-                    );
-                    callback(
-                      assign({}, inspectorData, {
-                        pointerY: locationY,
-                        frame: {
-                          left: left,
-                          top: top,
-                          width: width,
-                          height: height
-                        },
-                        touchedViewTag: nativeViewTag,
-                        closestPublicInstance: nativeViewTag
-                      })
-                    );
-                  }
-                )
-              : console.error(
-                  "getInspectorDataForViewAtPoint expects to receive a host component"
-                );
+            : console.error(
+                "getInspectorDataForViewAtPoint expects to receive a host component"
+              );
         }
       },
       getViewConfigForType =
@@ -20368,23 +20262,12 @@
       );
     };
     exports.dispatchCommand = function (handle, command, args) {
-      var nativeTag =
-        null != handle._nativeTag
-          ? handle._nativeTag
-          : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle);
-      null == nativeTag
-        ? console.error(
+      handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle);
+      null != handle
+        ? nativeFabricUIManager.dispatchCommand(handle, command, args)
+        : console.error(
             "dispatchCommand was called with a ref that isn't a native component. Use React.forwardRef to get access to the underlying native component"
-          )
-        : ((handle =
-            ReactNativePrivateInterface.getNodeFromPublicInstance(handle)),
-          null != handle
-            ? nativeFabricUIManager.dispatchCommand(handle, command, args)
-            : ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand(
-                nativeTag,
-                command,
-                args
-              ));
+          );
     };
     exports.findHostInstance_DEPRECATED = function (componentOrHandle) {
       var owner = current;
@@ -20402,14 +20285,46 @@
         : componentOrHandle.canonical &&
             componentOrHandle.canonical.publicInstance
           ? componentOrHandle.canonical.publicInstance
-          : componentOrHandle._nativeTag
-            ? componentOrHandle
-            : findHostInstanceWithWarning(
-                componentOrHandle,
-                "findHostInstance_DEPRECATED"
-              );
+          : findHostInstanceWithWarning(
+              componentOrHandle,
+              "findHostInstance_DEPRECATED"
+            );
     };
-    exports.findNodeHandle = findNodeHandle;
+    exports.findNodeHandle = function (componentOrHandle) {
+      var owner = current;
+      null !== owner &&
+        isRendering &&
+        null !== owner.stateNode &&
+        (owner.stateNode._warnedAboutRefsInRender ||
+          console.error(
+            "%s is accessing findNodeHandle inside its render(). render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead.",
+            getComponentNameFromType(owner.type) || "A component"
+          ),
+        (owner.stateNode._warnedAboutRefsInRender = !0));
+      if (null == componentOrHandle) return null;
+      if ("number" === typeof componentOrHandle) return componentOrHandle;
+      if (
+        null != componentOrHandle.canonical &&
+        null != componentOrHandle.canonical.nativeTag
+      )
+        return componentOrHandle.canonical.nativeTag;
+      if (
+        (owner =
+          ReactNativePrivateInterface.getNativeTagFromPublicInstance(
+            componentOrHandle
+          ))
+      )
+        return owner;
+      componentOrHandle = findHostInstanceWithWarning(
+        componentOrHandle,
+        "findNodeHandle"
+      );
+      return null == componentOrHandle
+        ? componentOrHandle
+        : ReactNativePrivateInterface.getNativeTagFromPublicInstance(
+            componentOrHandle
+          );
+    };
     exports.getNodeFromInternalInstanceHandle =
       getNodeFromInternalInstanceHandle;
     exports.getPublicInstanceFromInternalInstanceHandle = function (
@@ -20433,14 +20348,6 @@
         : null;
     };
     exports.isChildPublicInstance = function (parentInstance, childInstance) {
-      if (
-        parentInstance._internalFiberInstanceHandleDEV &&
-        childInstance._internalFiberInstanceHandleDEV
-      )
-        return doesFiberContain(
-          parentInstance._internalFiberInstanceHandleDEV,
-          childInstance._internalFiberInstanceHandleDEV
-        );
       parentInstance =
         ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(
           parentInstance
@@ -20449,9 +20356,27 @@
         ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(
           childInstance
         );
-      return null != parentInstance && null != childInstance
-        ? doesFiberContain(parentInstance, childInstance)
-        : !1;
+      if (null != parentInstance && null != childInstance) {
+        a: {
+          for (
+            var parentFiberAlternate = parentInstance.alternate;
+            null !== childInstance;
+
+          ) {
+            if (
+              childInstance === parentInstance ||
+              childInstance === parentFiberAlternate
+            ) {
+              parentInstance = !0;
+              break a;
+            }
+            childInstance = childInstance.return;
+          }
+          parentInstance = !1;
+        }
+        return parentInstance;
+      }
+      return !1;
     };
     exports.render = function (
       element,
@@ -20521,22 +20446,12 @@
       return element;
     };
     exports.sendAccessibilityEvent = function (handle, eventType) {
-      var nativeTag =
-        null != handle._nativeTag
-          ? handle._nativeTag
-          : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle);
-      null == nativeTag
-        ? console.error(
+      handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle);
+      null != handle
+        ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType)
+        : console.error(
             "sendAccessibilityEvent was called with a ref that isn't a native component. Use React.forwardRef to get access to the underlying native component"
-          )
-        : ((handle =
-            ReactNativePrivateInterface.getNodeFromPublicInstance(handle)),
-          null != handle
-            ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType)
-            : ReactNativePrivateInterface.legacySendAccessibilityEvent(
-                nativeTag,
-                eventType
-              ));
+          );
     };
     exports.stopSurface = function (containerTag) {
       var root = roots.get(containerTag);
```

</details>
2026-04-16 18:34:03 +01:00
Rubén NorteandGitHub a26787e8c0 [RN] Move new event dispatching pipeline to RN (#36266)
## Summary

We found a bug in the logic in
https://github.com/facebook/react/pull/36253 and we realized it's very
inconvenient to iterate on the implementation when it's in this
repository, as we're forced to then synchronize it to RN to test
changes.

This moves the entire implementation to RN for simplicity and also to
simplify some clean ups in the future (like removing `top` prefixes from
native event types).

## How did you test this change?

The changes are gated. Will test e2e in RN.
2026-04-14 18:10:33 +01:00
Rubén NorteandGitHub 40093e71f7 [react-native-renderer] EventTarget-based event dispatching (#36253)
## Summary

Set up the experiment to migrate event dispatching in the React Native
renderer to be based on the native EventTarget API.

Behind the `enableNativeEventTargetEventDispatching` flag, events are
dispatched through `dispatchTrustedEvent` instead of the legacy plugin
system.

Regular event handler props are NOT registered via addEventListener at
commit time. Instead, a hook on EventTarget
(`EVENT_TARGET_GET_DECLARATIVE_LISTENER_KEY`) extracts handlers from
`canonical.currentProps` at dispatch time, shifting cost from every
render to only when events fire. The hook is overridden in
ReactNativeElement to look up the prop name via a reverse mapping from
event names (built lazily from the view config registry).

Responder events bypass EventTarget entirely. `negotiateResponder` walks
the fiber tree directly (capture then bubble phase), calling handlers
from `canonical.currentProps` and checking return values inline.
Lifecycle events (`responderGrant`, `responderMove`, etc.) call handlers
directly from props and inspect return values — `onResponderGrant`
returning `true` blocks native responder,
`onResponderTerminationRequest` returning `false` refuses termination.
This eliminates all commit-time cost for responder events (no wrappers,
no addEventListener, no `responderWrappers` on canonical).

## How did you test this change?

Flow
Tested e2e in RN using Fantom tests (that will land after this).
2026-04-14 12:43:41 +01:00
9f9f8ed2ed Fix require('ReactFeatureFlags') in eslint-plugin-react-hooks www build (#36243)
PR #35951 added FB_WWW_DEV builds for eslint-plugin-react-hooks to get
www-specific feature flag values. However, the FB_WWW build uses the
full ReactFeatureFlags.www.js fork, which contains:

  const dynamicFeatureFlags = require('ReactFeatureFlags');

This is a www Haste module that only exists in the www runtime. Rollup
can't tree-shake CJS require() calls (they're assumed side-effectful),
so the bare require('ReactFeatureFlags') survives in the build output
even though the eslint plugin only uses the static eprh_* exports.

When the built artifact is synced to www at
scripts/lint/eslint/rules/eslint-plugin-react-hooks/index.js, Node.js
fails with "Cannot find module 'ReactFeatureFlags'" because Haste
modules aren't available in the Node.js lint environment.

Create a dedicated fork (ReactFeatureFlags.eslint-plugin.www.js) that
exports only the static eprh_* flags with www values, without the
require('ReactFeatureFlags') dependency. Wire it up in forks.js for the
eslint-plugin-react-hooks entry point.

<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

Co-authored-by: Eugene Choi <[email protected]>
2026-04-09 12:14:54 -04:00
Jack PopeandGitHub 97b20b8453 Fix FB_WWW eprh bundle dev guard (#36238)
We use FB_WWW bundle to inject internal feature flag values, but need to
use NODE guard type because this is a node script -- __DEV__ is breaking
internal builds

Follow up to https://github.com/facebook/react/pull/35951
2026-04-08 16:12:35 -04:00
e2ed67eeee Add ReactFeatureFlags support to eprh (#35951)
We're currently hardcoding experimental options to
`eslint-plugin-react-hooks`. This blocks the release on features that
might not be ready.

This PR extends the ReactFeatureFlag infra to support flags for
`eslint-plugin-react-hooks`. An alternative would be to create a
separate flag system for build tools, but for now we have a small number
of these and reusing existing infra seems like the simplest approach.

I ran a full `yarn build` and checked the output resolved the flag
values as expected:


_build/oss-stable-semver/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js_
```js
var eprh_enableUseKeyedStateCompilerLint = false;
var eprh_enableVerboseNoSetStateInEffectCompilerLint = false;
var eprh_enableExhaustiveEffectDependenciesCompilerLint = 'off';
```


_build/facebook-www/ESLintPluginReactHooks-dev.classic.js_

```js
var eprh_enableUseKeyedStateCompilerLint = true;
var eprh_enableVerboseNoSetStateInEffectCompilerLint = true;
var eprh_enableExhaustiveEffectDependenciesCompilerLint = 'extra-only';
```

---------

Co-authored-by: lauren <[email protected]>
2026-03-24 23:13:27 -07:00
Zeya PengandGitHub 4e0280e3c7 Enables Basic View Transition support for React Native Fabric renderer (#35764)
## Summary

Enables Basic View Transition support for React Native Fabric renderer.

**Implemented:**
- Added FabricUIManager bindings for view transition methods:
`applyViewTransitionName`, `startViewTransition`
- Implemented `startViewTransition` with proper callback orchestration
(mutation → layout → afterMutation → spawnedWork → passive)
- Added fallback behavior that flushes work synchronously when Fabric's
`startViewTransition` returns null (e.g., when the ViewTransition
ReactNativeFeatureFlag is not enabled)
- Added Flow type declarations for new FabricUIManager methods
- Stubbed with `__DEV__` warnings for all the other view transition
config functions that are not yet implemented

This allows React Native apps using Fabric to leverage the View
Transition API for coordinated animations during state transitions, with
graceful degradation when the native side doesn't support it.

Below are diagrams of proposed architecture in fabric, and observation
of what/when config functions get called during a basic shared
transition example

<img width="2290" height="1529" alt="Untitled-2026-03-19-1240"
src="https://github.com/user-attachments/assets/192c9169-bc25-449c-a33b-dfec67179e7f"
/>

## How did you test this change?

- [x] `yarn flow fabric` - Flow type checks pass
- [x] `yarn lint` - Lint checks pass
- [x] Manually tested in Android catalyst app with
`enableViewTransition` and `enableViewTransitionForPersistenceMode `in
`ReactFeatureFlags.test-renderer.native-fb.js` and View Transition
enabled via ReactNativeFeatureFlag
- [x] Verified in the minified `ReactFabric-dev.fb.js` that the 'shim'
config functions are not included
- [x] Verified fallback behavior logs warning in `__DEV__` and flushes
work synchronously when ViewTransition flag isn't enabled in Fabric
2026-03-19 17:58:29 -04:00
e9d3110210 [Flight Reply] Early bailout if backing entry for Blob deserialization is not a Blob (#36055)
Co-authored-by: Hendrik Liebau <[email protected]>
2026-03-17 11:50:27 +01:00
Sebastian "Sebbie" SilbermannandGitHub 0caec283d6 [DevTools] Ignore new production renderers if we already use "worse" versions of React on a page (#35994) 2026-03-11 10:26:35 +01:00
RickyandGitHub 342225456f [errors] s/form state/action state (#35790)
Noticed `useActionState` error still refers to "form state" while
writing the docs.
2026-03-04 14:20:03 -05:00
Sebastian "Sebbie" SilbermannandGitHub a26b49a12e [noop] Typecheck react-noop-renderer against host config and renderer API (#35944) 2026-03-04 13:52:11 +01:00
Sebastian "Sebbie" SilbermannandGitHub b328795e1d [DevTools] Improve type coverage for extension runtime API (#35957) 2026-03-04 12:47:32 +01:00
Ruslan LesiutinandGitHub a3c56f2a29 [DevTools] Remove experimental __IS_INTERNAL_MCP_BUILD__ flag and related code (#35755)
This is unused.
2026-02-11 16:59:43 +00:00
930871872a [Flight] Add more DoS mitigations to Flight Reply, and harden Flight (#35632)
This fixes security vulnerabilities in Server Functions.

---------

Co-authored-by: Sebastian Markbåge <[email protected]>
Co-authored-by: Josh Story <[email protected]>
Co-authored-by: Janka Uryga <[email protected]>
Co-authored-by: Sebastian Sebbie Silbermann <[email protected]>
2026-01-26 20:24:58 +01:00
Joseph SavonaandGitHub 1481587019 worktree script improvements (#35603)
A few small improvements:
* Use `<root>/.worktrees` as the directory for worktrees so its hidden
by default in finder/ls
* Generate names with a timestamp, and allow auto-generating a name so
that you can just call eg `./scripts/worktree.sh --compiler --claude`
and get a random name
2026-01-23 10:41:17 -08:00
Joseph SavonaandGitHub da33fa5028 Add worktree script (#35593)
Intended to be used directly and/or from skills in an agent.

Usage is `./scripts/worktree.sh [--compiler] [--claude] <name>`. The
script:
* Checks that ./worktrees is in gitignore
* Checks the named worktree does not exist yet
* Creates the named worktree in ./worktrees/
* Installs deps
* cds into the worktree (optionally the compiler dir if `--compiler`)
* optionally runs claude in the worktree if `--claude`
2026-01-21 22:38:37 -08:00
RickyandGitHub 972321857d [tests] Fix flaky flight tests (#35513)
Flights tests are failing locally and in CI non-deterministically
because we're not disabling async hooks after tests, and GC can clear
WeakRefs non-deterministically.

This PR fixes the issue by adding an afterEach to disable installed
hooks, and normalizing the `value` to `value: {value: undefined}}` when
snapshotting.
2026-01-18 15:36:00 -05:00
RickyandGitHub 216e607086 [tests] add silent reporter (#35547)
Adds silent reporter so you can run tests and only see the failed tests

This helps reduce context agents use, if you're inclined to use agents:

<img width="630" height="292" alt="Screenshot 2026-01-17 at 12 39 58 PM"
src="https://github.com/user-attachments/assets/373b9803-59a6-4b9a-99f9-d74a7b41462e"
/>
2026-01-18 10:17:17 -05:00
laurenandGitHub cfdbdfb532 [ci] Add size-balanced test sequencer for better shard distribution (#35458)
Jest's default test sequencer sorts alphabetically, causing large test
files
(eg ReactDOMFloat-test.js at 9k lines,
ReactHooksWithNoopRenderer-test.js at 4k
lines) to cluster in shard 3/5. This made shard 3/5 average 117s vs 77s
for
other shards, a 52% slowdown. I'm using filesize as a rough proxy for
number of tests.

This custom sequencer sorts tests by file size and distributes large
files evenly across all shards
instead of clustering them together.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35458).
* __->__ #35458
* #35459
2026-01-06 21:29:22 -05:00
Sebastian "Sebbie" SilbermannandGitHub 7cea7830f0 [test] Exclude repository root from assertions (#35361) 2025-12-15 11:45:17 +01:00
Sebastian MarkbågeandGitHub 4b846c15bc [Flight] Patch Promise cycles and toString on Server Functions (#35345)
Server Functions can be stringified (sometimes implicitly) when passed
as data. This adds an override to hide the source code in that case -
just in case someone puts sensitive information in there.

Note that this still preserves the `name` field but this is also
available on the export but in practice is likely minified anyway.
There's nothing else on these referenes we'd consider unsafe unless you
explicitly expose expandos which are part of the `"use server"` export.

This adds a safety check to ensure you don't encode cyclic Promises.
This isn't a parser bug per se. Promises do have a safety mechanism that
avoids them infinite looping. However, since we use custom Thenables,
what can happen is that every time a native Promise awaits it, another
Promise wrapper is created around the Thenable which foils the
ECMAScript Promise cycle detection which can lead to an infinite loop.

This also ensures that embedded `ReadableStream` and `AsyncIterable`
streams are properly closed if the source stream closes early both on
the Server and Client. This doesn't cause an infinite loop but just to
make sure resource clean up can proceed properly.

We're also adding some more explicit clear errors for invalid payloads
since we no longer need to obfuscate the original issue.
2025-12-11 15:24:24 -05:00
Sebastian "Sebbie" SilbermannandGitHub 91733e8e50 [scripts] Remove perf-counters (#35308) 2025-12-06 12:33:42 +01:00
6d3abb1b28 [Flight] Move react-server-dom-webpack/*.unbundled to private react-server-dom-unbundled (#35290)
Co-authored-by: Hendrik Liebau <[email protected]>
2025-12-05 03:59:21 +01:00
Sebastian "Sebbie" SilbermannandGitHub 98bcb339bd [release] Allow building single release channel with processed versions (#35270) 2025-12-02 22:05:10 +01:00
Sebastian "Sebbie" SilbermannandGitHub c25e720cde [test] Fix Error Proxy in Node.js 21+ (#35227) 2025-11-29 16:52:39 +01:00
Sebastian MarkbågeandGitHub 753bace628 Escape View Transition Name Strings as base64 (#35060)
This is an alternative to #35059.

If the name needs escaping, then instead of escaping it, we just use a
base64 name. This wouldn't allow you to match on an escaped name in your
own CSS like you should be able to if browsers worked properly. But at
least it would provide matching name in current browsers which is
probably sufficient if you're using auto-generated names.

This also covers some cases where `CSS.escape()` isn't sufficient anyway
like when the name ends in a dot.
2025-11-06 16:02:06 -05:00
Michael HandGitHub b9caa76528 [react-dom] Include all Node.js APIs in Bun entrypoint for /server (#34193) 2025-10-27 23:06:45 +01:00
laurenandGitHub 7b31882c13 [generate-changelog] Refactor (#34993)
Just a light reorganization.
2025-10-27 18:04:48 -04:00
laurenandGitHub 74f3ea880e [generate-changelog] Add --format option (#34992)
Adds a new `--format` option which can be `text` (default), `csv`, or
`json`.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34992).
* #34993
* __->__ #34992
2025-10-27 17:54:09 -04:00
RickyandGitHub abe40e6763 [rn] delete the legacy renderers from the sync (#34946)
Now that RN is only on the New Architecture, we can stop stop syncing
the legacy React Native renderers.

In this diff, I just stop syncing them. In a follow up I'll delete the
code for them so only Fabric is left.

This will also allow us to remove the `enableLegacyMode` feature flag.
2025-10-27 17:38:56 -04:00
laurenandGitHub c442df842c [script] Add yarn generate-changelog (#34962)
(disclaimer: I used codex to write this script)

Adds a new `yarn generate-changelog` script to simplify the process of
writing changelogs. You can use it as follows:

```
$ yarn generate-changelog --help

Usage: yarn generate-changelog [--codex|--claude] [--debug] [<pkg@version> ...]

Options:
  --codex     Use Codex for commit summarization.                      [boolean]
  --claude    Use Claude for commit summarization.                     [boolean]
  --debug     Enable verbose debug logging.           [boolean] [default: false]
  -h, --help  Show help                                                [boolean]

Examples:
  generate-changelog --codex                Generate changelog for a single
  [email protected]           package using Codex.
  generate-changelog --claude [email protected]    Generate changelog entries for
  [email protected]                            multiple packages using Claude.
  generate-changelog --codex                Generate changelog for all stable
                                            packages using recorded versions.
```

For example, if no args are passed, the script will print find all the
relevant commits affecting packages (defaults to `stablePackages` in
`ReactVersions.js`) and format them as a simple markdown list.

```
$ yarn generate-changelog

## [email protected]
* [compiler] improve zod v3 backwards compat (#34877) ([#34877](https://github.com/facebook/react/pull/34877) by [@henryqdineen](https://github.com/henryqdineen))
* [ESLint] Disallow passing effect event down when inlined as a prop (#34820) ([#34820](https://github.com/facebook/react/pull/34820) by [@jf-eirinha](https://github.com/jf-eirinha))
* Switch to `export =` to fix eslint-plugin-react-hooks types (#34949) ([#34949](https://github.com/facebook/react/pull/34949) by [@karlhorky](https://github.com/karlhorky))
* [eprh] Type `configs.flat` more strictly (#34950) ([#34950](https://github.com/facebook/react/pull/34950) by [@poteto](https://github.com/poteto))
* Add hint for Node.js cjs-module-lexer for eslint-plugin-react-hook types (#34951) ([#34951](https://github.com/facebook/react/pull/34951) by [@karlhorky](https://github.com/karlhorky))
* Add hint for Node.js cjs-module-lexer for eslint-plugin-react-hook types (#34953) ([#34953](https://github.com/facebook/react/pull/34953) by [@karlhorky](https://github.com/karlhorky))

// etc etc...
```

If `--codex` or `--claude` is passed, the script will attempt to use
them to summarize the commit(s) in the same style as our existing
CHANGELOG.md.

And finally, for debugging the script you can add `--debug` to see
what's going on.
2025-10-27 15:48:36 -04:00
Sebastian MarkbågeandGitHub a48cd5ee84 [DevTools] Show the Suspense boundary name in the rect if there's no overlap (#34918)
This shows the title in the top corner of the rect if there's enough
space.

The complex bit here is that it can be noisy if too many boundaries
occupy the same space to overlap or partially overlap.

This uses an R-tree to store all the rects to find overlapping
boundaries to cut the available space to draw inside the rect. We use
this to compute the rectangle within the rect which doesn't have any
overlapping boundaries.

The roots don't count as overlapping. Similarly, a parent rect is not
consider overlapping a child. However, if two sibling boundaries occupy
the same space, no title will be drawn.

<img width="734" height="813" alt="Screenshot 2025-10-19 at 5 34 49 PM"
src="https://github.com/user-attachments/assets/2b848b9c-3b78-48e5-9476-dd59a7baf6bf"
/>

We might also consider drawing the "Initial Paint" title at the root but
that's less interesting. It's interesting in the beginning before you
know about the special case at the root but after that it's just always
the same value so just adds noise.
2025-10-19 22:17:45 -04:00
Damjan PetrovicandGitHub be8559bebc Add MIT license header to feature flag utility script (#34833)
Added the standard Meta Platforms, Inc. MIT license notice to the top of
the feature flag comparison script to ensure compliance with repository
licensing requirements and for code consistency.
**No functional or logic changes were made to the code.**
2025-10-16 14:20:21 -04:00
9625d04ce1 [compiler] improve zod v3 backwards compat (#34877)
## Summary

When upgrading to `[email protected]` in a project that
uses `zod@3` we are running into TypeScript errors like:

```
node_modules/babel-plugin-react-compiler/dist/index.d.ts:435:10 - error TS2694: Namespace '"/REDACTED/node_modules/zod/v3/external"' has no exported member 'core'.

435     }, z.core.$strip>>>;
             ~~~~
```

This problem seems to be related to
a76e065ec3, which introduced zod v3/v4
compatibility. Since `zod` is bundled into the compiler source this does
not cause runtime issues and only manifests as TypeScript errors. My
proposed solution is this PR is to use zod's [subpath versioning
strategy](https://zod.dev/v4/versioning?id=versioning-in-zod-4) which
allows you to support v3 and v4 APIs on both major versions.

Changes in this PR include:

- Updated `zod` import paths to `zod/v4`
- Bumped min `zod` version to `^3.25.0` for zod which guarantees the
`zod/v4` subpath is available.
- Updated `zod-validation-error` import paths to
`zod-validation-error/v4`
- Bumped min `zod-validation-error ` version to `^3.5.0` 
- Updated `externals` tsup configuration where appropriate. 

Once the compiler drops zod v3 support we could optionally remove the
`/v4` subpath from the imports.

## How did you test this change?

Not totally sure the best way to test. I ran `NODE_ENV=production yarn
workspace babel-plugin-react-compiler run build --dts` and diffed the
`dist/` folder between my change and `v1.0.0` and it looks correct. We
have a `patch-package` patch to workaround this for now and it works as
expected.

```diff
diff --git a/node_modules/babel-plugin-react-compiler/dist/index.d.ts b/node_modules/babel-plugin-react-compiler/dist/index.d.ts
index 81c3f3d..daafc2c 100644
--- a/node_modules/babel-plugin-react-compiler/dist/index.d.ts
+++ b/node_modules/babel-plugin-react-compiler/dist/index.d.ts
@@ -1,7 +1,7 @@
 import * as BabelCore from '@babel/core';
 import { NodePath as NodePath$1 } from '@babel/core';
 import * as t from '@babel/types';
-import { z } from 'zod';
+import { z } from 'zod/v4';
 import { NodePath, Scope } from '@babel/traverse';
 
 interface Result<T, E> {
```

Co-authored-by: Henry Q. Dineen <[email protected]>
2025-10-16 09:46:55 -07:00
Sebastian "Sebbie" SilbermannandGitHub d31f23f53f Release Fragment refs to Canary (#34720)
## Overview

This PR adds the `ref` prop to `<Fragment>` in `react@canary`.

This means this API is ready for final feedback and prepared for a
semver stable release.

## What this means

Shipping Fragment refs to canary means they have gone through extensive
testing in production, we are confident in the stability of the APIs,
and we are preparing to release it in a future semver stable version.

Libraries and frameworks following the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries) should begin
implementing and testing these features.

## Why we follow the Canary Workflow

To prepare for semver stable, libraries should test canary features like
Fragment refs with `react@canary` to confirm compatibility and prepare
for the next semver release in a myriad of environments and
configurations used throughout the React ecosystem. This provides
libraries with ample time to catch any issues we missed before slamming
them with problems in the wider semver release.

Since these features have already gone through extensive production
testing, and we are confident they are stable, frameworks following the
[Canary Workflow](https://react.dev/blog/2023/05/03/react-canaries) can
also begin adopting canary features like Fragment refs.

This adoption is similar to how different Browsers implement new
proposed browser features before they are added to the standard. If a
frameworks adopts a canary feature, they are committing to stability for
their users by ensuring any API changes before a semver stable release
are opaque and non-breaking to their users.

Apps not using a framework are also free to adopt canary features like
Fragment refs as long as they follow the [Canary
Workflow](https://react.dev/blog/2023/05/03/react-canaries), but we
generally recommend waiting for a semver stable release unless you have
the capacity to commit to following along with the canary changes and
debugging library compatibility issues.

Waiting for semver stable means you're able to benefit from libraries
testing and confirming support, and use semver as signal for which
version of a library you can use with support of the feature.

## Docs 

Check out the ["React Labs: View Transitions, Activity, and
more"](https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#fragment-refs)
blog post, and [the new docs for Fragment
refs`](https://react.dev/reference/react/Fragment#fragmentinstance) for
more info.
2025-10-06 21:24:24 -07:00
7921f2062c [compiler] Remove @babel/plugin-proposal-private-methods (#34715)
redo of #34458 but fixing up prettier

Co-authored-by: Arnaud Barré <[email protected]>
2025-10-03 09:13:55 -07:00
Sebastian "Sebbie" SilbermannandGitHub a48d95436f Allow running yarn lint on subset of paths (#34646) 2025-09-30 12:30:40 +02:00