From 91bc1283caae042bd356387e15f162fab56c14c5 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 4 Aug 2025 16:19:06 -0400 Subject: [PATCH 1/4] Pass environment name to owners and badge them with the environment --- .../react-devtools-shared/src/backend/fiber/renderer.js | 2 ++ .../react-devtools-shared/src/backend/legacy/renderer.js | 1 + packages/react-devtools-shared/src/backend/types.js | 1 + .../src/devtools/views/Components/ElementBadges.js | 7 ++++++- .../views/Components/InspectedElementSuspendedBy.js | 2 ++ .../src/devtools/views/Components/InspectedElementView.js | 1 + .../src/devtools/views/Components/OwnerView.js | 3 +++ .../src/devtools/views/Components/OwnersStack.js | 2 ++ packages/react-devtools-shared/src/frontend/types.js | 1 + 9 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 189d504ad51..cbc23fd55cc 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -4630,6 +4630,7 @@ export function attach( displayName: getDisplayNameForFiber(fiber) || 'Anonymous', id: instance.id, key: fiber.key, + env: null, type: getElementTypeForFiber(fiber), }; } else { @@ -4638,6 +4639,7 @@ export function attach( displayName: componentInfo.name || 'Anonymous', id: instance.id, key: componentInfo.key == null ? null : componentInfo.key, + env: componentInfo.env == null ? null : componentInfo.env, type: ElementTypeVirtual, }; } diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index d2b846bee24..6010cdb4e2a 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -795,6 +795,7 @@ export function attach( displayName: getData(owner).displayName || 'Unknown', id: getID(owner), key: element.key, + env: null, type: getElementType(owner), }); if (owner._currentElement) { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 6324e63da14..45ae028601e 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -256,6 +256,7 @@ export type SerializedElement = { displayName: string | null, id: number, key: number | string | null, + env: null | string, type: ElementType, }; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/ElementBadges.js b/packages/react-devtools-shared/src/devtools/views/Components/ElementBadges.js index a829ad0153a..5a3355c60c4 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/ElementBadges.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/ElementBadges.js @@ -16,18 +16,21 @@ import styles from './ElementBadges.css'; type Props = { hocDisplayNames: Array | null, + environmentName: string | null, compiledWithForget: boolean, className?: string, }; export default function ElementBadges({ compiledWithForget, + environmentName, hocDisplayNames, className = '', }: Props): React.Node { if ( !compiledWithForget && - (hocDisplayNames == null || hocDisplayNames.length === 0) + (hocDisplayNames == null || hocDisplayNames.length === 0) && + environmentName == null ) { return null; } @@ -36,6 +39,8 @@ export default function ElementBadges({
{compiledWithForget && } + {environmentName != null ? {environmentName} : null} + {hocDisplayNames != null && hocDisplayNames.length > 0 && ( {hocDisplayNames[0]} )} 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 a1b76e49b6a..c321e8503da 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js @@ -157,6 +157,7 @@ function SuspendedByRow({ | null, + environmentName: string | null, compiledWithForget: boolean, id: number, isInStore: boolean, @@ -27,6 +28,7 @@ type OwnerViewProps = { export default function OwnerView({ displayName, + environmentName, hocDisplayNames, compiledWithForget, id, @@ -65,6 +67,7 @@ export default function OwnerView({ diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js index 0fa5c0910bb..09bdb96af01 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js @@ -220,6 +220,7 @@ function ElementsDropdown({owners, selectOwner}: ElementsDropdownProps) { @@ -268,6 +269,7 @@ function ElementView({isSelected, owner, selectOwner}: ElementViewProps) { diff --git a/packages/react-devtools-shared/src/frontend/types.js b/packages/react-devtools-shared/src/frontend/types.js index 622205dd672..d613f282d5b 100644 --- a/packages/react-devtools-shared/src/frontend/types.js +++ b/packages/react-devtools-shared/src/frontend/types.js @@ -208,6 +208,7 @@ export type SerializedElement = { displayName: string | null, id: number, key: number | string | null, + env: null | string, hocDisplayNames: Array | null, compiledWithForget: boolean, type: ElementType, From 48291dd84876e18e486c6b458e741dca3dc9d1dd Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 4 Aug 2025 16:52:31 -0400 Subject: [PATCH 2/4] Only badge owners if they have a different environment than the inspected instance --- packages/react-devtools-shared/src/backend/fiber/renderer.js | 4 ++++ packages/react-devtools-shared/src/backend/legacy/renderer.js | 2 ++ packages/react-devtools-shared/src/backend/types.js | 4 ++++ packages/react-devtools-shared/src/backendAPI.js | 2 ++ .../src/devtools/views/Components/InspectedElementView.js | 4 +++- packages/react-devtools-shared/src/frontend/types.js | 3 +++ 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index cbc23fd55cc..c5fda9499a5 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -5265,6 +5265,8 @@ export function attach( // List of owners owners, + env: null, + rootType, rendererPackageName: renderer.rendererPackageName, rendererVersion: renderer.version, @@ -5368,6 +5370,8 @@ export function attach( // List of owners owners, + env: componentInfo.env == null ? null : componentInfo.env, + rootType, rendererPackageName: renderer.rendererPackageName, rendererVersion: renderer.version, diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index 6010cdb4e2a..6153e08832a 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -858,6 +858,8 @@ export function attach( // List of owners owners, + env: null, + rootType: null, rendererPackageName: null, rendererVersion: null, diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 45ae028601e..585654252da 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -302,6 +302,10 @@ export type InspectedElement = { // List of owners owners: Array | null, + + // Environment name that this component executed in or null for the client + env: string | null, + source: ReactFunctionLocation | null, type: ElementType, diff --git a/packages/react-devtools-shared/src/backendAPI.js b/packages/react-devtools-shared/src/backendAPI.js index d6aa18cd317..a27e70c26d0 100644 --- a/packages/react-devtools-shared/src/backendAPI.js +++ b/packages/react-devtools-shared/src/backendAPI.js @@ -255,6 +255,7 @@ export function convertInspectedElementBackendToFrontend( id, type, owners, + env, source, context, hooks, @@ -299,6 +300,7 @@ export function convertInspectedElementBackendToFrontend( owners === null ? null : owners.map(backendToFrontendSerializedElementMapper), + env, context: hydrateHelper(context), hooks: hydrateHelper(hooks), props: hydrateHelper(props), diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementView.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementView.js index 2b6b26db2d0..95f7aee68da 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementView.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementView.js @@ -174,7 +174,9 @@ export default function InspectedElementView({ key={owner.id} displayName={owner.displayName || 'Anonymous'} hocDisplayNames={owner.hocDisplayNames} - environmentName={owner.env} + environmentName={ + inspectedElement.env === owner.env ? null : owner.env + } compiledWithForget={owner.compiledWithForget} id={owner.id} isInStore={store.containsElement(owner.id)} diff --git a/packages/react-devtools-shared/src/frontend/types.js b/packages/react-devtools-shared/src/frontend/types.js index d613f282d5b..e4a4c5400bf 100644 --- a/packages/react-devtools-shared/src/frontend/types.js +++ b/packages/react-devtools-shared/src/frontend/types.js @@ -266,6 +266,9 @@ export type InspectedElement = { // List of owners owners: Array | null, + // Environment name that this component executed in or null for the client + env: string | null, + // Location of component in source code. source: ReactFunctionLocation | null, From abb99ff498757db4252ee70e226dbbd283586b81 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 4 Aug 2025 17:12:13 -0400 Subject: [PATCH 3/4] Badge the last row of the stack trace if it's different from the owner This could happen if you execute a cached function inside one component environment but it's called from a parent component in the parent environment. Such as calling a cached function from a server component. --- .../Components/InspectedElementSuspendedBy.js | 34 ++++++++++++++++--- .../views/Components/StackTraceView.js | 26 ++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) 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 c321e8503da..c24dd881e98 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js @@ -150,14 +150,28 @@ function SuspendedByRow({ {isOpen && (
- {showIOStack && } + {showIOStack && ( + + )} {(showIOStack || !showAwaitStack) && ioOwner !== null && ioOwner.id !== inspectedElement.id ? (
awaited at:
{asyncInfo.stack !== null && asyncInfo.stack.length > 0 && ( - + )} {asyncOwner !== null && asyncOwner.id !== inspectedElement.id ? ( {formatLocationForDisplay(url, line, column)} +
); } type Props = { stack: ReactStackTrace, + environmentName: null | string, }; -export default function StackTraceView({stack}: Props): React.Node { +export default function StackTraceView({ + stack, + environmentName, +}: Props): React.Node { return (
{stack.map((callSite, index) => ( - + ))}
); From e1385cd3976f1e95d5b3da7f3c80f8f4167ad1b9 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 4 Aug 2025 19:23:18 -0400 Subject: [PATCH 4/4] Update test --- .../react-devtools-shared/src/__tests__/profilingCache-test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index c0f0804f416..795f37183a8 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -862,6 +862,7 @@ describe('ProfilingCache', () => { { "compiledWithForget": false, "displayName": "render()", + "env": null, "hocDisplayNames": null, "id": 1, "key": null, @@ -903,6 +904,7 @@ describe('ProfilingCache', () => { { "compiledWithForget": false, "displayName": "createRoot()", + "env": null, "hocDisplayNames": null, "id": 1, "key": null, @@ -943,6 +945,7 @@ describe('ProfilingCache', () => { { "compiledWithForget": false, "displayName": "createRoot()", + "env": null, "hocDisplayNames": null, "id": 1, "key": null,