Commit Graph
1032 Commits
Author SHA1 Message Date
Ruslan LesiutinandGitHub e70ba593ac [DevTools] feat: display subtree for Activity and dim in hidden mode (#36094)
With this change, Components panel will display subtree of the Activity.
When it is in hidden mode, the subtree will be dimmed.

Added Jest tests and a sandbox case to `react-devtools-shell`.

Demo:


https://github.com/user-attachments/assets/69a2e8d6-585d-4fcd-b57e-e9ae06d0a1b3
2026-03-23 14:29:38 +00:00
Ruslan LesiutinandGitHub 6844e8011f [DevTools] chore: extract getInternalReactConstants (#35986)
The test is quite naive, but worth having as additional check for
changes in this logic.
2026-03-20 14:17:15 +00:00
Ruslan LesiutinandGitHub aba4f90381 [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.
2026-03-12 14:19:21 -07: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
Sebastian "Sebbie" SilbermannandGitHub b4d0874823 [DevTools] Fix a crash when rendering a new class Component when simulating errored state (#35985) 2026-03-10 18:05:48 +01:00
932543873d [DevTools] Fix null ref crash in ContextMenu when items list is empty (#35929)
Co-authored-by: Sebastian Sebbie Silbermann <[email protected]>
2026-03-05 16:52:23 +01:00
Ruslan LesiutinandGitHub 8aa3683da6 [DevTools] chore: extract pure functions from fiber/renderer.js (#35924)
I am in a process of splitting down the renderer implementation into
smaller units of logic that can be reused. This change is about
extracting pure functions only.
2026-03-03 12:27:05 +00:00
Sebastian "Sebbie" SilbermannandGitHub ad10f7c20d [DevTools] Only schedule a single update per Supense when changing timeline (#35927) 2026-03-03 12:21:46 +01:00
Sebastian "Sebbie" SilbermannandGitHub 8d395dce04 [DevTools] Fix alignment of breadcrumbs separator (#35817) 2026-02-18 10:53:49 -08:00
Ruslan LesiutinandGitHub a1077c4596 [DevTools] Check suspense child node presence in parentSuspense.children before removing (#35775)
Currently, this silently removes the last child in the list, which
doesn't contain the `id`.
2026-02-13 15:33:22 +00:00
Sebastian "Sebbie" SilbermannandGitHub 9e1fb1aab8 [DevTools] Dedicated empty state for roots that aren't suspended by anything (#35769) 2026-02-12 17:48:02 +01:00
Sebastian "Sebbie" SilbermannandGitHub f60a406297 [DevTools] Enable Suspense tab by default (#35768) 2026-02-12 16:50:29 +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
Sebastian "Sebbie" SilbermannandGitHub 6e94f65dfa [DevTools] Display React.optimisticKey in key positions (#35760) 2026-02-11 00:35:36 +01:00
Sebastian "Sebbie" SilbermannandGitHub 2bb178edeb [DevTools] Only block child Suspense boundaries if the parent has all shared suspenders removed (#35737) 2026-02-10 17:52:35 +01:00
d0206107b3 Consistent handling of work tags for rename, delete, and overriding state (#35740)
Co-authored-by: Ruslan Lesiutin <[email protected]>
2026-02-10 16:35:02 +01:00
Sebastian "Sebbie" SilbermannandGitHub 75593946c9 [DevTools] Fix memory leak when unmounting hoistables (#35741) 2026-02-10 13:09:23 +01:00
Sebastian "Sebbie" SilbermannandGitHub c6983ae9a2 [test] Include uniqueSuspenders in Suspense tree snapshots (#35736) 2026-02-10 12:51:58 +01:00
Ruslan LesiutinandGitHub 4210e49bb3 [DevTools] Don't capture durations for disconnected subtrees when profiling (#35718)
After https://github.com/facebook/react/pull/34089, when updating
(possibly, mounting) inside disconnected subtree, we don't record this
as an operation. This only happens during reconnect. The issue is that
`recordProfilingDurations()` can be called, which diffs tree base
duration and reports it to the Frontend:

https://github.com/facebook/react/blob/cba2bc83d8ce7887fabb90775d25b67ade36e5c3/packages/react-devtools-shared/src/backend/fiber/renderer.js#L4506-L4521

This operation can be recorded before the "Add" operation, and it will
not be resolved properly on the Frontend side.

Before the fix:
```
commit tree › Suspense › should handle transitioning from fallback back to content during profiling

    Could not clone the node: commit tree does not contain fiber "5". This is a bug in React DevTools.

      162 |     const existingNode = nodes.get(id);
      163 |     if (existingNode == null) {
    > 164 |       throw new Error(
          |             ^
      165 |         `Could not clone the node: commit tree does not contain fiber "${id}". This is a bug in React DevTools.`,
      166 |       );
      167 |     }

      at getClonedNode (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:164:13)
      at updateTree (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:348:24)
      at getCommitTree (packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:112:20)
      at ProfilingCache.getCommitTree (packages/react-devtools-shared/src/devtools/ProfilingCache.js:40:46)
      at Object.<anonymous> (packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js:257:44)
```
2026-02-09 22:18:17 +00:00
Sebastian "Sebbie" SilbermannandGitHub c31165650f [DevTools] Allow renaming Host Component props (#35735) 2026-02-09 23:14:46 +01:00
Sebastian "Sebbie" SilbermannandGitHub e33fa11c51 [DevTools] Fix crash when revealing stable, filtered <Activity> children (#35734) 2026-02-09 22:52:24 +01:00
Ruslan LesiutinandGitHub 4d6a84745e [DevTools] Fix false-positive re-render reports for filtered nodes (#35723)
Fixes https://github.com/facebook/react/issues/33423,
https://github.com/facebook/react/issues/35245,
https://github.com/facebook/react/issues/19732.

As demoed
[here](https://github.com/facebook/react/issues/33423#issuecomment-2970750588),
React DevTools incorrectly highlights re-renders for descendants of
filtered-out nodes that didn't actually render.

There were multiple fixes suggesting changes in `didFiberRender()`
function, but these doesn't seem right, because this function is used in
a context of whether the Fiber actually rendered something (updated),
not re-rendered compared to the previous Fiber.

Instead, this PR adds additional validation at callsites that either
used for highlighting re-renders or capturing tree base durations and
are relying on `didFiberRender`. I've also added a few tests that
reproduce the failure scenario. Without the changes, the tests are
failing.
2026-02-09 20:39:33 +00:00
Sebastian "Sebbie" SilbermannandGitHub 048e4a3e1a [Fiber] Avoid duplicate debug info for array children (#35733) 2026-02-09 20:36:56 +01:00
Sebastian "Sebbie" SilbermannandGitHub cba2bc83d8 [test] Move profilingCommitTreeBuilder to versioned renderer (#35711) 2026-02-06 16:00:43 +01:00
Sebastian "Sebbie" SilbermannandGitHub f0425d4279 [DevTools] Fix broken commit tree builder for initial operations (#35710) 2026-02-06 15:16:23 +01:00
Sebastian "Sebbie" SilbermannandGitHub 514d8140c3 [DevTools] Separate breadcrumbs with » (#35705) 2026-02-06 00:40:31 +01:00
Sebastian "Sebbie" SilbermannandGitHub 50a8fab165 [DevTools] Avoid scrollbars in Suspense breadcrumbs (#35700) 2026-02-05 23:27:57 +01:00
Ruslan LesiutinandGitHub bf70c37a31 [DevTools] Throw an error when attempting to clone non-existent node (#35702)
There is an existing issue with serialisation logic for the traces from
Profiler panel.

I've discovered that `TREE_OPERATION_UPDATE_TREE_BASE_DURATION`
operation for some reason appears earlier in a sequence of operations,
before the `TREE_OPERATION_ADD` that registers the new node. It ends up
cloning non-existent node, which just creates an empty object and adds
it to the map of nodes.

This change only adds additional layer of validation to cloning logic,
so we don't swallow the error, if we attempt to clone non-existent node.
2026-02-05 17:49:18 +00:00
Sebastian "Sebbie" SilbermannandGitHub ae4dd460f5 [DevTools] Shrink/Deshrink Owners breadcrumbs on any resizes (#35694) 2026-02-05 12:08:02 +01:00
Sebastian "Sebbie" SilbermannandGitHub 6684f5a42e [DevTools] Disable Activity slices by default (#35685) 2026-02-04 10:56:33 +01:00
Ruslan LesiutinandGitHub 2647358088 [DevTools] Fix commit index reset when switching profiler roots (#35672)
Fixes https://github.com/facebook/react/issues/31463,
https://github.com/facebook/react/issues/30114.

When switching between roots in the profiler flamegraph, the commit
index was preserved from the previous root. This caused an error
"Invalid commit X. There are only Y commits." when the new root had
fewer commits than the selected index.

This fix resets the commit index to 0 (or null if no commits) when the
commitData changes, which happens when switching roots.
2026-02-03 12:44:04 +00:00
Sebastian "Sebbie" SilbermannandGitHub f49e0a25cb [DevTools] Apply component filters on initial load (#35587) 2026-01-26 11:06:04 +01:00
Sebastian "Sebbie" SilbermannandGitHub b1d37915c7 [DevTools] Update inspected element on component filter changes (#35599) 2026-01-26 11:04:06 +01:00
Sebastian "Sebbie" SilbermannandGitHub 4337f132b1 [DevTools] Stop setting unused global variables (#35532) 2026-01-16 16:13:29 +01:00
Sebastian "Sebbie" SilbermannandGitHub 0be64314a5 [DevTools] Clear element inspection if host element not owned by any renderer is selected (#35504) 2026-01-16 13:20:44 +01:00
Sebastian "Sebbie" SilbermannandGitHub 919828c090 Typecheck React DevTools extension main script (#35519) 2026-01-16 13:08:28 +01:00
Sebastian "Sebbie" SilbermannandGitHub c33cde8480 [DevTools] Show fallback in inspected element pane when no element is selected (#35503) 2026-01-15 14:28:02 +01:00
Sebastian "Sebbie" SilbermannandGitHub d2df88809e [DevTools] Add React Element pane to browser Elements panel (#35240) 2026-01-15 13:24:06 +01:00
48f97abf95 Improve the detection of changed hooks (#35123)
## Summary

cc @hoxyq 

Fixes https://github.com/facebook/react/issues/28584. Follow up to PR:
https://github.com/facebook/react/pull/34547

This PR updates getChangedHooksIndices to account for the fact that
`useSyncExternalStore`, `useTransition`, `useActionState`,
`useFormState` internally mounts more than one hook while DevTools
should treat it as a single user-facing hook.

Approach idea came from
[this](https://github.com/facebook/react/pull/34547#issuecomment-3504113776)
comment 😄

Before:


https://github.com/user-attachments/assets/6bd5ce80-8b52-4bb8-8bb1-5e91b1e65043


After:


https://github.com/user-attachments/assets/47f56898-ab34-46b6-be7a-a54024dcefee



## How did you test this change?

I used this component to reproduce this issue locally (I followed
instructions in `packages/react-devtools/CONTRIBUTING.md`).

<details><summary>Details</summary>

```ts

import * as React from 'react';

function useDeepNestedHook() {
  React.useState(0); // 1
  return React.useState(1); // 2
}

function useNestedHook() {
  const deepState = useDeepNestedHook();
  React.useState(2); // 3
  React.useState(3); // 4

  return deepState;
}

// Create a simple store for useSyncExternalStore
function createStore(initialValue) {
  let value = initialValue;
  const listeners = new Set();
  return {
    getSnapshot: () => value,
    subscribe: listener => {
      listeners.add(listener);
      return () => {
        listeners.delete(listener);
      };
    },
    update: newValue => {
      value = newValue;
      listeners.forEach(listener => listener());
    },
  };
}

const syncExternalStore = createStore(0);

export default function InspectableElements(): React.Node {
  const [nestedState, setNestedState] = useNestedHook();

  // 5
  const syncExternalValue = React.useSyncExternalStore(
    syncExternalStore.subscribe,
    syncExternalStore.getSnapshot,
  );

  // 6
  const [isPending, startTransition] = React.useTransition();

  // 7
  const [formState, formAction, formPending] = React.useActionState(
    async (prevState, formData) => {
      return {count: (prevState?.count || 0) + 1};
    },
    {count: 0},
  );

  const handleTransition = () => {
    startTransition(() => {
      setState(Math.random());
    });
  };

  // 8
  const [state, setState] = React.useState('test');

  return (
    <>
      <div
        style={{
          padding: '20px',
          display: 'flex',
          flexDirection: 'column',
          gap: '10px',
        }}>
        <div
          onClick={() => setNestedState(Math.random())}
          style={{backgroundColor: 'red', padding: '10px', cursor: 'pointer'}}>
          State: {nestedState}
        </div>

        <button onClick={handleTransition} style={{padding: '10px'}}>
          Trigger Transition {isPending ? '(pending...)' : ''}
        </button>

        <div style={{display: 'flex', gap: '10px', alignItems: 'center'}}>
          <button
            onClick={() => syncExternalStore.update(syncExternalValue + 1)}
            style={{padding: '10px'}}>
            Trigger useSyncExternalStore
          </button>
          <span>Value: {syncExternalValue}</span>
        </div>

        <form
          action={formAction}
          style={{display: 'flex', gap: '10px', alignItems: 'center'}}>
          <button
            type="submit"
            style={{padding: '10px'}}
            disabled={formPending}>
            Trigger useFormState {formPending ? '(pending...)' : ''}
          </button>
          <span>Count: {formState.count}</span>
        </form>

        <div
          onClick={() => setState(Math.random())}
          style={{backgroundColor: 'red', padding: '10px', cursor: 'pointer'}}>
          State: {state}
        </div>
      </div>
    </>
  );
}
```


</details>

---------

Co-authored-by: Ruslan Lesiutin <[email protected]>
2026-01-15 11:06:14 +00:00
Sebastian "Sebbie" SilbermannandGitHub 8d6f60fefe [test] Fix DevTools regression tests (#35501) 2026-01-13 16:00:16 +01:00
Sebastian "Sebbie" SilbermannandGitHub baef9cb1ea [DevTools] Attach async info in filtered fallback to parent of Suspense (#35456) 2026-01-10 11:33:48 +01:00
laurenandGitHub c991e8353d [ci] Increase DevTools test shards and bump timeout (#35459)
[ci] Increase DevTools test shards and bump timeout

- Increase DevTools test shards from 3 to 5
- Bump timeout to 20s

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35459).
* #35458
* __->__ #35459
2026-01-06 21:23:05 -05:00
7cdeeb16eb Devtools disable log dimming strict mode setting (#35207)
<!--

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`).

-->

## Summary

Currently, every second console log is dimmed, receiving a special style
that indicates to user that it was raising because of [React Strict
Mode](https://react.dev/reference/react/StrictMode) second rendering.
This introduces a setting to disable this.

## How did you test this change?
Test in console-test.js


https://github.com/user-attachments/assets/af6663ac-f79b-4824-95c0-d46b0c8dec12

Browser extension react devtools


https://github.com/user-attachments/assets/7e2ecb7a-fbdf-4c72-ab45-7e3a1c6e5e44

React native dev tools:


https://github.com/user-attachments/assets/d875b3ac-1f27-43f8-8d9d-12b2d65fa6e6

---------

Co-authored-by: Ruslan Lesiutin <[email protected]>
2025-12-15 13:41:43 +00:00
Ruslan LesiutinandGitHub eea0071c3a fix[devtools]: feature-check document with typeof instead of direct reference (#35343)
Follow-up to https://github.com/facebook/react/pull/35296.

We can get `ReferenceError` if this is unavailable. Using `typeof` check
instead for safety.
2025-12-11 12:15:00 +00:00
Ruslan LesiutinandGitHub e9f545c3c2 fix[devtools]: feature-check structure stack trace methods (#35293)
`Error.prepareStackTrace` is non-standard feature and not all JavaScript
runtimes implement the methods that we are using in React DevTools
backend.

This PR adds additional checks for the presence of the methods that we
are using.
2025-12-10 19:21:54 +00:00
Ruslan LesiutinandGitHub 6a426a5011 fix[devtools]: still show overlay, if getClientRects is not implemented (#35294)
Follow-up to https://github.com/facebook/react/pull/34653.

React Native doesn't implement `getClientRect`, since this is applicable
to CSS box, which is not a concept for Native (maybe yet).

I am loosening the condition that gates `showOverlay()` call to pass if
`getClientRect` is not implemented.

Conceptually, everything that is inside `react-devtools-shared/backend`
should be Host-agnostic, because both on Web and Native it is installed
inside the Host JavaScript runtime, be it main frame of the page, or RN
instance. Since overlay & highlighting logic also lives there, it should
also follow these principles.
2025-12-10 19:21:28 +00:00
emily8rownandGitHub 6f7f9d4d1c [Devtools] Navigating commits performance panel hotkey (#35238)
## Summary
Add keyboard shortcuts (Cmd/Ctrl + Left/Right arrow keys) to navigate
between commits in the Profiler's snapshot view.

Moved `filteredCommitIndices` management and commit navigation logic
(`selectNextCommitIndex`, `selectPrevCommitIndex`) from
`SnapshotSelector` into `useCommitFilteringAndNavigation` used by
`ProfilerContext` to enable keyboard shortcuts from the top-level
Profiler component.

## How did you test this change?
- New tests in ProfilerContext-tests
- Built browser extension: `yarn build:<browser name>`
- tested in browser: `yarn run test:<browser name>`
- Manually verified Left/Right arrow navigation cycles through commits
- Verified navigation respects commit duration filter
- Verified reload-and-profile button unaffected

Chrome:


https://github.com/user-attachments/assets/01d2a749-13dc-4d08-8bcb-3d4d45a5f97c

Edge with duration filter:


https://github.com/user-attachments/assets/a7f76ff7-2a0b-4b9c-a0ce-d4449373308b

firefox mixing hotkey with clicking arrow buttons:


https://github.com/user-attachments/assets/48912d68-7c75-40f2-a203-5e6d7e6b2d99
2025-12-10 13:07:35 +00:00
Ruslan LesiutinandGitHub c27682c6cc fix[devtools]: no-op unsupported backend bridge events (#35296)
Follow-up to https://github.com/facebook/react/pull/34641.
Similar to https://github.com/facebook/react/pull/35293,
https://github.com/facebook/react/pull/35294.

React DevTools backend can be used in non-DOM environments, so we have
to feature-check some DOM APIs.
For now I am just no-oping newly added commands for Native, we should
revisit this decision once we would roll out Suspense panel there, if
needed. I am not sure if scrolling will be required as much as it is
needed on Web.

`isReactNativeEnvironment()` check is kinda clowny, but we've been
relying on it for quite some time already.
2025-12-05 16:41:58 +00:00
Sebastian "Sebbie" SilbermannandGitHub 37482da5f8 [test] Only run tests overriding fallback and error states in supported versions (#35234) 2025-11-27 16:15:14 +01:00
Sebastian "Sebbie" SilbermannandGitHub e3736f803e [DevTools] Move "Back to full tree view" into Activity list item (#35164) 2025-11-26 10:42:18 +01:00