From 014138df87869b174956f90a33fd6cf66e160114 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Tue, 10 Mar 2026 18:05:48 +0100 Subject: [PATCH 01/10] [DevTools] Fix a crash when rendering a new class Component when simulating errored state (#35985) --- .../src/__tests__/storeForceError-test.js | 106 ++++++++++++++++++ .../src/backend/fiber/renderer.js | 4 +- .../src/ReactFiberBeginWork.js | 3 + 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 packages/react-devtools-shared/src/__tests__/storeForceError-test.js diff --git a/packages/react-devtools-shared/src/__tests__/storeForceError-test.js b/packages/react-devtools-shared/src/__tests__/storeForceError-test.js new file mode 100644 index 000000000000..16ae50d6f028 --- /dev/null +++ b/packages/react-devtools-shared/src/__tests__/storeForceError-test.js @@ -0,0 +1,106 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type Store from 'react-devtools-shared/src/devtools/store'; + +import {getVersionedRenderImplementation} from './utils'; + +describe('Store forcing errors', () => { + let React; + let agent; + let store: Store; + let utils; + let actAsync; + + beforeEach(() => { + agent = global.agent; + store = global.store; + store.collapseNodesByDefault = false; + store.componentFilters = []; + store.recordChangeDescriptions = true; + + React = require('react'); + utils = require('./utils'); + + actAsync = utils.actAsync; + }); + + const {render} = getVersionedRenderImplementation(); + + // @reactVersion >= 18.0 + it('resets forced error and fallback states when filters are changed', async () => { + class AnyClassComponent extends React.Component { + render() { + return this.props.children; + } + } + + class ErrorBoundary extends React.Component { + state = {hasError: false}; + + static getDerivedStateFromError() { + return {hasError: true}; + } + + render() { + if (this.state.hasError) { + return ( + +
+ + ); + } + return this.props.children; + } + } + + function App() { + return ( + +
+ + ); + } + + await actAsync(async () => { + render(); + }); + const rendererID = utils.getRendererID(); + await actAsync(() => { + agent.overrideError({ + id: store.getElementIDAtIndex(2), + rendererID, + forceError: true, + }); + }); + + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + ▾ + ▾ +
+ `); + + await actAsync(() => { + agent.overrideError({ + id: store.getElementIDAtIndex(2), + rendererID, + forceError: false, + }); + }); + + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + ▾ +
+ `); + }); +}); diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 49e6192b467e..aa7fe9d6ee84 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -7898,7 +7898,7 @@ export function attach( // Map of Fiber and its force error status: true (error), false (toggled off) const forceErrorForFibers = new Map(); - function shouldErrorFiberAccordingToMap(fiber: any): boolean { + function shouldErrorFiberAccordingToMap(fiber: any): boolean | null { if (typeof setErrorHandler !== 'function') { throw new Error( 'Expected overrideError() to not get called for earlier React versions.', @@ -7934,7 +7934,7 @@ export function attach( } } if (status === undefined) { - return false; + return null; } return status; } diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 49a4c53c8941..cf2c08236733 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1584,6 +1584,9 @@ function updateClassComponent( // This is used by DevTools to force a boundary to error. switch (shouldError(workInProgress)) { case false: { + // We previously simulated an error on this boundary + // so the instance must have been constructed in a previous + // commit. const instance = workInProgress.stateNode; const ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack. From 7b5b561bd2dda205ed8f397864379003b707d4ae Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Wed, 11 Mar 2026 10:26:35 +0100 Subject: [PATCH 02/10] [DevTools] Ignore new production renderers if we already use "worse" versions of React on a page (#35994) --- .../background/setExtensionIconAndPopup.js | 14 +++++- .../src/contentScripts/installHook.js | 14 +----- .../src/contentScripts/reactBuildType.js | 50 +++++++++++++++++++ .../src/backend/types.js | 7 +++ packages/react-devtools-shared/src/hook.js | 5 +- scripts/flow/react-devtools.js | 14 ++++++ 6 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 packages/react-devtools-extensions/src/contentScripts/reactBuildType.js diff --git a/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js b/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js index 51f233e284f0..7f92114c87e1 100644 --- a/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js +++ b/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js @@ -1,8 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ /* global chrome */ 'use strict'; +import type {ReactBuildType} from 'react-devtools-shared/src/backend/types'; -function setExtensionIconAndPopup(reactBuildType, tabId) { +function setExtensionIconAndPopup( + reactBuildType: ReactBuildType, + tabId: number, +) { chrome.action.setIcon({ tabId, path: { diff --git a/packages/react-devtools-extensions/src/contentScripts/installHook.js b/packages/react-devtools-extensions/src/contentScripts/installHook.js index 490232baf869..4a7cb44eaa31 100644 --- a/packages/react-devtools-extensions/src/contentScripts/installHook.js +++ b/packages/react-devtools-extensions/src/contentScripts/installHook.js @@ -10,6 +10,7 @@ import { getProfilingSettings, } from 'react-devtools-shared/src/utils'; import {postMessage} from './messages'; +import {createReactRendererListener} from './reactBuildType'; let resolveHookSettingsInjection: (settings: DevToolsHookSettings) => void; let resolveComponentFiltersInjection: (filters: Array) => void; @@ -67,17 +68,6 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { // Detect React window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on( 'renderer', - function ({reactBuildType}) { - window.postMessage( - { - source: 'react-devtools-hook', - payload: { - type: 'react-renderer-attached', - reactBuildType, - }, - }, - '*', - ); - }, + createReactRendererListener(window), ); } diff --git a/packages/react-devtools-extensions/src/contentScripts/reactBuildType.js b/packages/react-devtools-extensions/src/contentScripts/reactBuildType.js new file mode 100644 index 000000000000..f1d5326ea96a --- /dev/null +++ b/packages/react-devtools-extensions/src/contentScripts/reactBuildType.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +import type {ReactBuildType} from 'react-devtools-shared/src/backend/types'; + +function reduceReactBuild( + currentReactBuildType: null | ReactBuildType, + nextReactBuildType: ReactBuildType, +): ReactBuildType { + if ( + currentReactBuildType === null || + currentReactBuildType === 'production' + ) { + return nextReactBuildType; + } + + // We only display the "worst" build type, so if we've already detected a non-production build, + // we ignore any future production builds. This way if a page has multiple renderers, + // and at least one of them is a non-production build, we'll display that instead of "production". + return nextReactBuildType === 'production' + ? currentReactBuildType + : nextReactBuildType; +} + +export function createReactRendererListener(target: { + postMessage: Function, + ... +}): ({reactBuildType: ReactBuildType}) => void { + let displayedReactBuild: null | ReactBuildType = null; + + return function ({reactBuildType}) { + displayedReactBuild = reduceReactBuild(displayedReactBuild, reactBuildType); + + target.postMessage( + { + source: 'react-devtools-hook', + payload: { + type: 'react-renderer-attached', + reactBuildType: displayedReactBuild, + }, + }, + '*', + ); + }; +} diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index c68601f9b633..70ef8e4befef 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -603,3 +603,10 @@ export type DevToolsHookSettings = { export type DevToolsSettings = DevToolsHookSettings & { componentFilters: Array, }; + +export type ReactBuildType = + | 'deadcode' + | 'development' + | 'outdated' + | 'production' + | 'unminified'; diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 5764a8bee4bf..f24ae48c3601 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -17,6 +17,7 @@ import type { DevToolsBackend, DevToolsHookSettings, ProfilingSettings, + ReactBuildType, } from './backend/types'; import type {ComponentFilter} from './frontend/types'; @@ -71,7 +72,7 @@ export function installHook( return null; } - function detectReactBuildType(renderer: ReactRenderer) { + function detectReactBuildType(renderer: ReactRenderer): ReactBuildType { try { if (typeof renderer.version === 'string') { // React DOM Fiber (16+) @@ -211,7 +212,7 @@ export function installHook( const id = ++uidCounter; renderers.set(id, renderer); - const reactBuildType = hasDetectedBadDCE + const reactBuildType: ReactBuildType = hasDetectedBadDCE ? 'deadcode' : detectReactBuildType(renderer); diff --git a/scripts/flow/react-devtools.js b/scripts/flow/react-devtools.js index 21f9e441ada6..ddd925c2443d 100644 --- a/scripts/flow/react-devtools.js +++ b/scripts/flow/react-devtools.js @@ -17,6 +17,16 @@ declare const __IS_CHROME__: boolean; declare const __IS_EDGE__: boolean; declare const __IS_NATIVE__: boolean; +interface ExtensionAction { + /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/action/setIcon} */ + setIcon(details: { + tabId: number, + path?: string | {[iconSize: string]: string}, + }): void; + /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/action/setPopup} */ + setPopup(details: {tabId: number, popup: string}): void; +} + interface ExtensionDevtools { /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/devtools/inspectedWindow} */ inspectedWindow: $FlowFixMe; @@ -73,6 +83,8 @@ interface ExtensionRuntime { extensionId: string, connectInfo?: {name?: string, includeTlsChannelId?: boolean}, ): ExtensionRuntimePort; + /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getURL} */ + getURL(path: string): string; /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage} */ onMessage: ExtensionEvent< ( @@ -108,6 +120,8 @@ interface ExtensionTabs { } interface ExtensionAPI { + /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/action} */ + action: ExtensionAction; devtools: ExtensionDevtools; /** @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/permissions} */ permissions: $FlowFixMe; From b5f01787949b3619ef178a2574b54e2c1043910d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 08:38:01 -0700 Subject: [PATCH 03/10] Bump jws from 3.2.2 to 3.2.3 (#35373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [jws](https://github.com/brianloveswords/node-jws) from 3.2.2 to 3.2.3.
Release notes

Sourced from jws's releases.

v3.2.3

Changed

  • Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key) when using HMAC algorithms.
  • Upgrading JWA version to 1.4.2, addressing a compatibility issue for Node >= 25.
Changelog

Sourced from jws's changelog.

[3.2.3]

Changed

  • Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key) when using HMAC algorithms.
  • Upgrading JWA version to 1.4.2, adressing a compatibility issue for Node >= 25.

[3.0.0]

Changed

2.0.0 - 2015-01-30

Changed

  • BREAKING: Default payload encoding changed from binary to utf8. utf8 is a is a more sensible default than binary because many payloads, as far as I can tell, will contain user-facing strings that could be in any language. (6b6de48)

  • Code reorganization, thanks @​fearphage! (7880050)

Added

  • Option in all relevant methods for encoding. For those few users that might be depending on a binary encoding of the messages, this is for them. (6b6de48)
Commits
  • 4f6e73f Merge commit from fork
  • bd0fea5 version 3.2.3
  • 7c3b4b4 Enhance tests for HMAC streaming sign and verify
  • a9b8ed9 Improve secretOrKey initialization in VerifyStream
  • 6707fde Improve secret handling in SignStream
  • See full diff in compare view
Maintainer changes

This version was pushed to npm by julien.wollscheid, a new releaser for jws since your current version.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jws&package-manager=npm_and_yarn&previous-version=3.2.2&new-version=3.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index c7f9e8501453..303fed599cdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6015,10 +6015,10 @@ buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer-equal-constant-time@1.0.1: +buffer-equal-constant-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== buffer-fill@^1.0.0: version "1.0.0" @@ -8167,7 +8167,6 @@ eslint-plugin-no-unsanitized@4.0.2: "eslint-plugin-react-internal@link:./scripts/eslint-rules": version "0.0.0" - uid "" eslint-plugin-react@^6.7.1: version "6.10.3" @@ -11986,21 +11985,21 @@ junk@^3.1.0: resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== +jwa@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.2.tgz#16011ac6db48de7b102777e57897901520eec7b9" + integrity sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw== dependencies: - buffer-equal-constant-time "1.0.1" + buffer-equal-constant-time "^1.0.1" ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + version "3.2.3" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.3.tgz#5ac0690b460900a27265de24520526853c0b8ca1" + integrity sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g== dependencies: - jwa "^1.4.1" + jwa "^1.4.2" safe-buffer "^5.0.1" keyv@3.0.0: From 96005e445c4c6df5f222cc62d0327d4a389c339f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 08:38:41 -0700 Subject: [PATCH 04/10] Bump qs from 6.4.0 to 6.4.1 in /fixtures/packaging/webpack/prod (#35432) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [qs](https://github.com/ljharb/qs) from 6.4.0 to 6.4.1.
Changelog

Sourced from qs's changelog.

6.4.1

  • [Fix] parse: ignore __proto__ keys (#428)
  • [Fix] fix for an impossible situation: when the formatter is called with a non-string value
  • [Fix] use safer-buffer instead of Buffer constructor
  • [Fix] utils.merge: avoid a crash with a null target and an array source
  • [Fix] utils.merge: avoid a crash with a null target and a truthy non-array source
  • [Fix] stringify: fix a crash with strictNullHandling and a custom filter/serializeDate (#279)
  • [Fix] utils: merge: fix crash when source is a truthy primitive & no options are provided
  • [Fix] when parseArrays is false, properly handle keys ending in []
  • [Robustness] stringify: avoid relying on a global undefined (#427)
  • [Refactor] use cached Array.isArray
  • [Refactor] stringify: Avoid arr = arr.concat(...), push to the existing instance (#269)
  • [readme] remove travis badge; add github actions/codecov badges; update URLs
  • [Docs] Clarify the need for "arrayLimit" option
  • [meta] fix README.md (#399)
  • [meta] Clean up license text so it’s properly detected as BSD-3-Clause
  • [meta] add FUNDING.yml
  • [actions] backport actions from main
  • [Tests] remove nonexistent tape option
  • [Dev Deps] backport from main
Commits
  • 486aa46 v6.4.1
  • 727ef5d [Fix] parse: ignore __proto__ keys (#428)
  • cd1874e [Robustness] stringify: avoid relying on a global undefined (#427)
  • 45e987c [readme] remove travis badge; add github actions/codecov badges; update URLs
  • 90a3bce [meta] fix README.md (#399)
  • 9566d25 [Fix] fix for an impossible situation: when the formatter is called with a no...
  • 74227ef Clean up license text so it’s properly detected as BSD-3-Clause
  • 35dfb22 [actions] backport actions from main
  • 7d4670f [Dev Deps] backport from main
  • 0485440 [Fix] use safer-buffer instead of Buffer constructor
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qs&package-manager=npm_and_yarn&previous-version=6.4.0&new-version=6.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fixtures/packaging/webpack/prod/yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fixtures/packaging/webpack/prod/yarn.lock b/fixtures/packaging/webpack/prod/yarn.lock index 961a3a8208a0..2da73debceea 100644 --- a/fixtures/packaging/webpack/prod/yarn.lock +++ b/fixtures/packaging/webpack/prod/yarn.lock @@ -936,8 +936,8 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + version "6.4.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.1.tgz#2bad97710a5b661c366b378b1e3a44a592ff45e6" querystring-es3@^0.2.0: version "0.2.1" From bae6dd09fb9b08fc4387a9f649d9d1ef9ad1a9e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 08:40:22 -0700 Subject: [PATCH 05/10] Bump qs from 6.4.0 to 6.4.1 in /fixtures/packaging/webpack-alias/dev (#35505) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [qs](https://github.com/ljharb/qs) from 6.4.0 to 6.4.1.
Changelog

Sourced from qs's changelog.

6.4.1

  • [Fix] parse: ignore __proto__ keys (#428)
  • [Fix] fix for an impossible situation: when the formatter is called with a non-string value
  • [Fix] use safer-buffer instead of Buffer constructor
  • [Fix] utils.merge: avoid a crash with a null target and an array source
  • [Fix] utils.merge: avoid a crash with a null target and a truthy non-array source
  • [Fix] stringify: fix a crash with strictNullHandling and a custom filter/serializeDate (#279)
  • [Fix] utils: merge: fix crash when source is a truthy primitive & no options are provided
  • [Fix] when parseArrays is false, properly handle keys ending in []
  • [Robustness] stringify: avoid relying on a global undefined (#427)
  • [Refactor] use cached Array.isArray
  • [Refactor] stringify: Avoid arr = arr.concat(...), push to the existing instance (#269)
  • [readme] remove travis badge; add github actions/codecov badges; update URLs
  • [Docs] Clarify the need for "arrayLimit" option
  • [meta] fix README.md (#399)
  • [meta] Clean up license text so it’s properly detected as BSD-3-Clause
  • [meta] add FUNDING.yml
  • [actions] backport actions from main
  • [Tests] remove nonexistent tape option
  • [Dev Deps] backport from main
Commits
  • 486aa46 v6.4.1
  • 727ef5d [Fix] parse: ignore __proto__ keys (#428)
  • cd1874e [Robustness] stringify: avoid relying on a global undefined (#427)
  • 45e987c [readme] remove travis badge; add github actions/codecov badges; update URLs
  • 90a3bce [meta] fix README.md (#399)
  • 9566d25 [Fix] fix for an impossible situation: when the formatter is called with a no...
  • 74227ef Clean up license text so it’s properly detected as BSD-3-Clause
  • 35dfb22 [actions] backport actions from main
  • 7d4670f [Dev Deps] backport from main
  • 0485440 [Fix] use safer-buffer instead of Buffer constructor
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qs&package-manager=npm_and_yarn&previous-version=6.4.0&new-version=6.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fixtures/packaging/webpack-alias/dev/yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fixtures/packaging/webpack-alias/dev/yarn.lock b/fixtures/packaging/webpack-alias/dev/yarn.lock index 961a3a8208a0..2da73debceea 100644 --- a/fixtures/packaging/webpack-alias/dev/yarn.lock +++ b/fixtures/packaging/webpack-alias/dev/yarn.lock @@ -936,8 +936,8 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + version "6.4.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.1.tgz#2bad97710a5b661c366b378b1e3a44a592ff45e6" querystring-es3@^0.2.0: version "0.2.1" From a74302c02d220e3663fcad5836cb90607fc2d006 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 08:40:37 -0700 Subject: [PATCH 06/10] Bump undici from 6.21.2 to 6.23.0 in /compiler (#35512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [undici](https://github.com/nodejs/undici) from 6.21.2 to 6.23.0.
Release notes

Sourced from undici's releases.

v6.23.0

⚠️ Security Release

This fixes https://github.com/nodejs/undici/security/advisories/GHSA-g9mf-h72j-4rw9 and CVE-2026-22036.

Full Changelog: https://github.com/nodejs/undici/compare/v6.22.0...v6.23.0

v6.22.0

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.21.3...v6.22.0

v6.21.3

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.21.2...v6.21.3

Commits
  • fbc31e2 Bumped v6.23.0
  • 3477c94 chore: release flow using provenance
  • d3aafea fix: limit Content-Encoding chain to 5 to prevent resource exhaustion
  • f9c9185 Bumped v6.22.0
  • f670f2a feat: make UndiciErrors reliable to instanceof (#4472) (#4480)
  • 422e397 feat(ProxyAgent) improve Curl-y behavior in HTTP->HTTP Proxy connections (#41...
  • 4a06ffe feat(ProxyAgent): match Curl behavior in HTTP->HTTP Proxy connections (#4180)...
  • 4cb3974 fix: fix EnvHttpProxyAgent for the Node.js bundle (#4064) (#4432)
  • 44c23e5 fix: fix wrong stream canceled up after cloning (v6) (#4414)
  • da0e823 Bumped v6.21.4
  • Additional commits viewable in compare view
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for undici since your current version.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=undici&package-manager=npm_and_yarn&previous-version=6.21.2&new-version=6.23.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- compiler/yarn.lock | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/compiler/yarn.lock b/compiler/yarn.lock index f480ff498cdf..a328b70efa72 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -10525,7 +10525,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10598,7 +10607,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11064,9 +11080,9 @@ undici-types@~6.19.2: integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== undici@^6.19.5: - version "6.21.2" - resolved "https://registry.npmjs.org/undici/-/undici-6.21.2.tgz" - integrity sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g== + version "6.23.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.23.0.tgz#7953087744d9095a96f115de3140ca3828aff3a4" + integrity sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g== unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.1" @@ -11375,7 +11391,7 @@ workerpool@^6.5.1: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11393,6 +11409,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" From 1e3152365df2f7a23a5ad947e83f40914413be16 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 12 Mar 2026 10:07:06 -0700 Subject: [PATCH 07/10] Enable Fragment Ref flags across builds (#36026) --- packages/shared/ReactFeatureFlags.js | 2 +- packages/shared/forks/ReactFeatureFlags.native-oss.js | 4 ++-- packages/shared/forks/ReactFeatureFlags.test-renderer.js | 2 +- .../shared/forks/ReactFeatureFlags.test-renderer.www.js | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index ee5f22ab9588..a54483df456e 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -145,7 +145,7 @@ export const enableInfiniteRenderLoopDetection: boolean = false; export const enableFragmentRefs: boolean = true; export const enableFragmentRefsScrollIntoView: boolean = true; -export const enableFragmentRefsInstanceHandles: boolean = false; +export const enableFragmentRefsInstanceHandles: boolean = true; export const enableFragmentRefsTextNodes: boolean = true; export const enableInternalInstanceMap: boolean = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 6b0d93447966..1c34990f5814 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -70,8 +70,8 @@ export const ownerStackLimit = 1e4; export const enableFragmentRefs: boolean = true; export const enableFragmentRefsScrollIntoView: boolean = false; -export const enableFragmentRefsInstanceHandles: boolean = false; -export const enableFragmentRefsTextNodes: boolean = false; +export const enableFragmentRefsInstanceHandles: boolean = true; +export const enableFragmentRefsTextNodes: boolean = true; export const enableInternalInstanceMap: boolean = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 954d9d88eaf5..40b6926c3572 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -71,7 +71,7 @@ export const ownerStackLimit = 1e4; export const enableFragmentRefs: boolean = true; export const enableFragmentRefsScrollIntoView: boolean = true; -export const enableFragmentRefsInstanceHandles: boolean = false; +export const enableFragmentRefsInstanceHandles: boolean = true; export const enableFragmentRefsTextNodes: boolean = true; export const enableInternalInstanceMap: boolean = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 91dc33b28f35..85079001ecfe 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -74,10 +74,10 @@ export const enableSrcObject: boolean = false; export const enableHydrationChangeEvent: boolean = false; export const enableDefaultTransitionIndicator: boolean = true; -export const enableFragmentRefs: boolean = false; -export const enableFragmentRefsScrollIntoView: boolean = false; -export const enableFragmentRefsInstanceHandles: boolean = false; -export const enableFragmentRefsTextNodes: boolean = false; +export const enableFragmentRefs: boolean = true; +export const enableFragmentRefsScrollIntoView: boolean = true; +export const enableFragmentRefsInstanceHandles: boolean = true; +export const enableFragmentRefsTextNodes: boolean = true; export const ownerStackLimit = 1e4; export const enableInternalInstanceMap: boolean = false; From 5e9eedb57843dc161defdf93ed457ab7d982e324 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Thu, 12 Mar 2026 19:17:24 +0100 Subject: [PATCH 08/10] [Flight] Clear chunk reason after successful module initialization (#36024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `requireModule` triggers a reentrant `readChunk` on the same module chunk, the reentrant call can fail and set `chunk.reason` to an error. After the outer `requireModule` succeeds, the chunk transitions to initialized but retains the stale error as `reason`. When the Flight response stream later closes, it iterates all chunks and expects `reason` on initialized chunks to be a `FlightStreamController`. Since the stale `reason` is an `Error` object instead, calling `chunk.reason.error()` crashes with `TypeError: chunk.reason.error is not a function`. The reentrancy can occur when module evaluation synchronously triggers `readChunk` on the same chunk — for example, when code called during evaluation tries to resolve the client reference for the module that is currently being initialized. In Fizz SSR, `captureOwnerStack()` can trigger this because it constructs component stacks that resolve lazy client references via `readChunk`. The reentrant `requireModule` call returns the module's namespace object, but since the module is still being evaluated, accessing the export binding throws a TDZ (Temporal Dead Zone) `ReferenceError`. This sets the chunk to the errored state, and the `ReferenceError` becomes the stale `chunk.reason` after the outer call succeeds. This scenario is triggered in Next.js when a client module calls an instrumented API like `Math.random()` in module scope, which synchronously invokes `captureOwnerStack()`. --- .../react-client/src/ReactFlightClient.js | 4 + .../src/__tests__/ReactFlightDOM-test.js | 89 +++++++++++++++++++ .../src/ReactFlightReplyServer.js | 1 + 3 files changed, 94 insertions(+) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 098a1a687e3a..fa89cf69ad67 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1040,6 +1040,8 @@ function initializeModelChunk(chunk: ResolvedModelChunk): void { // Initialize any debug info and block the initializing chunk on any // unresolved entries. initializeDebugChunk(response, chunk); + // TODO: The chunk might have transitioned to ERRORED now. + // Should we return early if that happens? } try { @@ -1075,6 +1077,7 @@ function initializeModelChunk(chunk: ResolvedModelChunk): void { const initializedChunk: InitializedChunk = (chunk: any); initializedChunk.status = INITIALIZED; initializedChunk.value = value; + initializedChunk.reason = null; if (__DEV__) { processChunkDebugInfo(response, initializedChunk, value); @@ -1097,6 +1100,7 @@ function initializeModuleChunk(chunk: ResolvedModuleChunk): void { const initializedChunk: InitializedChunk = (chunk: any); initializedChunk.status = INITIALIZED; initializedChunk.value = value; + initializedChunk.reason = null; } catch (error) { const erroredChunk: ErroredChunk = (chunk: any); erroredChunk.status = ERRORED; diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 94a5ac94546a..4abc18843050 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -1418,6 +1418,95 @@ describe('ReactFlightDOM', () => { expect(reportedErrors).toEqual([]); }); + it('should not retain stale error reason after reentrant module chunk initialization', async () => { + function MyComponent() { + return
hello from client component
; + } + const ClientComponent = clientExports(MyComponent); + + let resolveAsyncComponent; + async function AsyncComponent() { + await new Promise(r => { + resolveAsyncComponent = r; + }); + return null; + } + + function ServerComponent() { + return ( + <> + + + + + + ); + } + + const {writable: flightWritable, readable: flightReadable} = + getTestStream(); + const {writable: fizzWritable, readable: fizzReadable} = getTestStream(); + + const {pipe} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream( + , + webpackMap, + ), + ); + pipe(flightWritable); + + let response = null; + function getResponse() { + if (response === null) { + response = + ReactServerDOMClient.createFromReadableStream(flightReadable); + } + return response; + } + + // Simulate a module that calls captureOwnerStack() during evaluation. + // In Fizz SSR, this causes a reentrant readChunk on the same module chunk. + // The reentrant require throws a TDZ error. + let evaluatingModuleId = null; + const origRequire = global.__webpack_require__; + global.__webpack_require__ = function (id) { + if (id === evaluatingModuleId) { + throw new ReferenceError( + "Cannot access 'MyComponent' before initialization", + ); + } + const result = origRequire(id); + if (result === MyComponent) { + evaluatingModuleId = id; + if (__DEV__) { + React.captureOwnerStack(); + } + evaluatingModuleId = null; + } + return result; + }; + + function App() { + return use(getResponse()); + } + + await serverAct(async () => { + ReactDOMFizzServer.renderToPipeableStream().pipe(fizzWritable); + }); + + global.__webpack_require__ = origRequire; + + // Resolve the async component so the Flight stream closes after the client + // module chunk was initialized. + await serverAct(async () => { + resolveAsyncComponent(); + }); + + const container = document.createElement('div'); + await readInto(container, fizzReadable); + expect(container.innerHTML).toContain('hello from client component'); + }); + it('should be able to recover from a direct reference erroring server-side', async () => { const reportedErrors = []; diff --git a/packages/react-server/src/ReactFlightReplyServer.js b/packages/react-server/src/ReactFlightReplyServer.js index d3eff13ff465..21ff08a8aa02 100644 --- a/packages/react-server/src/ReactFlightReplyServer.js +++ b/packages/react-server/src/ReactFlightReplyServer.js @@ -478,6 +478,7 @@ function loadServerReference, T>( const initializedPromise: InitializedChunk = (blockedPromise: any); initializedPromise.status = INITIALIZED; initializedPromise.value = resolvedValue; + initializedPromise.reason = null; return resolvedValue; } } else if (bound instanceof ReactPromise) { From 8f4150605449efe909822d8b20fe529d85851afe Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:19:21 -0700 Subject: [PATCH 09/10] [DevTools] fix: don't show empty suspended by section (#36011) The potential paddings and margins for the empty block are already handled via CSS selectors. --- .../devtools/views/Components/InspectedElementSuspendedBy.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js index 50186f47b215..ffcdd7df0ca8 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js @@ -584,6 +584,9 @@ export default function InspectedElementSuspendedBy({ break; } + if (groups.length === 0) { + return null; + } return (
From c80a07509582daadf275f36ffe7a88c3b12e9db4 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 12 Mar 2026 14:36:28 -0700 Subject: [PATCH 10/10] Fix focus set for delegated and already focused elements (#36010) I found two focus bugs when working on documentation for Fragment Refs. 1) If an element delegates focus handling, it will return false from setFocusIfFocusable even though a focus event has occured on a different element. The fix for this is a document level event listener rather than only listening on the current element. For example, if you have a form with multiple nested label>inputs. Calling focus on the label will focus its input but not fire an event on the label. setFocusIfFocusable returns false and you end up continuing to attempt focus down the form tree. 2) If an element is already focused, setFocusIfFocusable will return false. The fix for this is checking the document's activeElement with an early return. In the same form example, if the first input is already focused and you call fragmentInstance.focus() at the form level, the second input would end up getting focused since the focus event on the first is not triggered. --- .../src/client/ReactFiberConfigDOM.js | 18 +++- .../__tests__/ReactDOMFragmentRefs-test.js | 96 +++++++++++++++++++ 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 4cb4e8e4273a..727ec694bbf7 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -4520,18 +4520,30 @@ export function setFocusIfFocusable( // // We could compare the node to document.activeElement after focus, // but this would not handle the case where application code managed focus to automatically blur. + const element = ((node: any): HTMLElement); + + // If this element is already the active element, it's focusable and already + // focused. Calling .focus() on it would be a no-op (no focus event fires), + // so we short-circuit here. + if (element.ownerDocument.activeElement === element) { + return true; + } + let didFocus = false; const handleFocus = () => { didFocus = true; }; - const element = ((node: any): HTMLElement); try { - element.addEventListener('focus', handleFocus); + // Listen on the document in the capture phase so we detect focus even when + // it lands on a different element than the one we called .focus() on. This + // happens with