Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DevTools] Show component names while highlighting renders #31577

Merged
merged 17 commits into from
Dec 13, 2024

Conversation

piotrski
Copy link
Contributor

Summary

This PR improves the Trace Updates feature by letting developers see component names directly on the update overlay. Before this change, the overlay only highlighted updated regions, leaving it unclear which components were involved. With this update, you can now match visual updates to their corresponding components, making it much easier to debug rendering performance.

New Feature: Show component names while highlighting

When the new "Show component names while highlighting" setting is enabled, the update overlay display the names of affected components above the rectangles, along with the update count. This gives immediate context about what’s rendering and why. The preference is stored in local storage and synced with the backend, so it’s remembered across sessions.

Improvements to Drawing Logic

The drawing logic has been updated to make the overlay sharper and easier to read. Overlay now respect device pixel ratios, so they look great on high-DPI screens. Outlines have also been made crisper, which makes it easier to spot exactly where updates are happening.

Note

Grouping Logic and Limitations
Updates are grouped by their screen position (left, top coordinates) to combine overlapping or nearby regions into a single group. Groups are sorted by the highest update count within each group, making the most frequently updated components stand out.
Overlapping labels may still occur when multiple updates involve components that overlap but are not in the exact same position. This is intentional, as the logic aims to maintain a straightforward mapping between update regions and component names without introducing unnecessary complexity.

Testing

This PR also adds tests for the new groupAndSortNodes utility, which handles the logic for grouping and sorting updates. The tests ensure the behavior is reliable across different scenarios.

Before & After

Before.mov
After.with.labels.mov

Copy link

vercel bot commented Nov 19, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 13, 2024 11:46am

Comment on lines +88 to +100
<div className={styles.Setting}>
<label>
<input
type="checkbox"
checked={showNamesWhenTracing}
disabled={!traceUpdatesEnabled}
onChange={({currentTarget}) =>
setShowNamesWhenTracing(currentTarget.checked)
}
/>{' '}
Show component names while highlighting.
</label>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should only be visible if "Highlight updates when components render." is checked.

It is okay for now, I am thinking of moving this option to somewhere else, so it could be just a one-click toggle on / off.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left it visible with a disabled style for now to help with discoverability. I also have a separate branch where "Highlight updates when components render." is a toggle in the navbar next to the search, but I didn’t want to make this PR bigger, and I wasn’t sure which icons to use. Open to suggestions!

Screenshot 2024-12-03 at 14 39 27

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left it visible with a disabled style for now to help with discoverability.

Nice, this should be enough for now

I also have a separate branch where "Highlight updates when components render." is a toggle in the navbar next to the search

Feel free to open a separate PR for this, or the one on top of that

@@ -86,6 +96,11 @@ function traceUpdates(nodes: Set<HostInstance>): void {
rect = measureNode(node);
}

let displayName = agent.getComponentNameForHostInstance(node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to gate it under showNames? To save some milliseconds if this option is disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Do you think there’s a cleaner way to check if the component was optimized by the compiler? I saw the parseElementDisplayNameFromBackend utility can return compiledWithForget, but it needs thetype. Not sure if I can get that from HostNode since it’s typed as an object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I can get that from HostNode since it’s typed as an object.

Here we operate with HostInstance: HTMLElement for Web (with react-dom), and something completely different for Native, based on version and architecture of React Native.

You could leave it like this for now, maybe later we could add a new method to Agent, which would map HostInstance to DevToolsInstance (this is what getComponentNameForHostInstance is already doing), and then return if component is compiled or not, and maybe filter out HOC names.

const color = COLORS[colorIndex];
execute(rect, color, node);
execute({...data, color, node});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid unnecessary copying?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can convert it back to attributes if needed. I went with an object here because it felt more type-safe and flexible, but let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can convert it back to attributes if needed. I went with an object here because it felt more type-safe and flexible, but let me know what you think.

This might become expensive, if the whole page re-renders? For each HTMLElement you will create a temporary copy here just for iteration purposes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I’ve been unwell. I replaced the spread operator with explicit object construction to avoid extra copies. Let me know if this solves the issue for you.

@hoxyq
Copy link
Contributor

hoxyq commented Dec 3, 2024

Love these improvements, thanks for opening this PR! Left some comments. I will try to get this supported for React Native, and I am also thinking about moving the checkbox to some other place, so this feature gets more visibility.

Copy link
Contributor

@hoxyq hoxyq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left 1 comment, please address it, linter and Flow issues.

Looks good overall, so once this is fixed, I can merge this

Comment on lines 99 to 117
let displayName = this.showNames && agent.getComponentNameForHostInstance(node);
if (displayName != null && displayName.startsWith('Forget(')) {
displayName = '✨' + displayName.slice(7, -1);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a chance you might end up receiving TypeError: calling displayName.startsWith(...) if this.showNames is false.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank for pointing that out. I’ve updated the code to avoid the potential TypeError by ensuring displayName is only processed when showNames is true.

I also revamped the display name parsing logic to make it more extensible. As part of this, I added a 🧠 icon for components wrapped in React.Memo, and display names are now consistently unwrapped from HOCs for better clarity. Let me know if there’s anything else!

piotrski and others added 16 commits December 13, 2024 11:33
…ative

- Introduced the `drawGroupedTraceUpdatesWithNames` event in `Agent` for emitting grouped trace updates.
- This maintains backward compatibility while improving trace update organization for React Native.

Note: This change only covers the JavaScript implementation; the native side still needs to be implemented.
@hoxyq hoxyq merged commit a7b8295 into facebook:main Dec 13, 2024
187 checks passed
hoxyq added a commit that referenced this pull request Jan 9, 2025
Feature was added in #31577, lets
enable it by default. Note: for gradual rollout with React Native, we
will continue to emit different event, requires some changes on React
Native side to support this.

I have plans to make this feature to be accessible via browser context
menu, which has really limited API. In order to minimize potential
divergence, lets make this the default state for the feature.
hoxyq added a commit that referenced this pull request Jan 16, 2025
List of changes in this release:

* fix[DevTools]: fix HostComponent naming in filters for Native
([hoxyq](https://github.com/hoxyq) in
[#32086](#32086))
* Fix copy functionality in Firefox ([V3RON](https://github.com/V3RON)
in [#32077](#32077))
* chore[DevTools]: don't use batchedUpdate
([hoxyq](https://github.com/hoxyq) in
[#32074](#32074))
* Prevent crash when starting consecutive profiling sessions
([V3RON](https://github.com/V3RON) in
[#32066](#32066))
* fix[DevTools/Tree]: only scroll to item when panel is visible
([hoxyq](https://github.com/hoxyq) in
[#32018](#32018))
* feat[Tree]: set initial scroll offset when inspected element index is
set ([hoxyq](https://github.com/hoxyq) in
[#31968](#31968))
* DevTools: merge element fields in TreeStateContext
([hoxyq](https://github.com/hoxyq) in
[#31956](#31956))
* DevTools: fix initial host instance selection
([hoxyq](https://github.com/hoxyq) in
[#31892](#31892))
* chore[DevTools/Tree]: don't pre-select root element and remove unused
code ([hoxyq](https://github.com/hoxyq) in
[#32015](#32015))
* chore[DevTools/TraceUpdates]: display names by default
([hoxyq](https://github.com/hoxyq) in
[#32019](#32019))
* Add ViewTransitionComponent to Stacks and DevTools
([sebmarkbage](https://github.com/sebmarkbage) in
[#32034](#32034))
* Add <ViewTransition> Component
([sebmarkbage](https://github.com/sebmarkbage) in
[#31975](#31975))
* chore[react-devtools-shell]: disable warnings in dev server overlay
([hoxyq](https://github.com/hoxyq) in
[#32005](#32005))
* DevTools: fork FastRefresh test for <18 versions of React
([hoxyq](https://github.com/hoxyq) in
[#31893](#31893))
* Show component names while highlighting renders
([piotrski](https://github.com/piotrski) in
[#31577](#31577))
* allow non-coercible objects in formatConsoleArgumentsToSingleString
([henryqdineen](https://github.com/henryqdineen) in
[#31444](#31444))
* Remove enableRefAsProp feature flag
([kassens](https://github.com/kassens) in
[#30346](#30346))
* [flow] Eliminate usage of more than 1-arg `React.AbstractComponent` in
React codebase ([SamChou19815](https://github.com/SamChou19815) in
[#31314](#31314))
* Audit try/finally around console patching
([sebmarkbage](https://github.com/sebmarkbage) in
[#31286](#31286))
* tests[react-devtools]: added tests for Compiler integration
([hoxyq](https://github.com/hoxyq) in
[#31241](#31241))
* Add Bridge types for Fusebox
([EdmondChuiHW](https://github.com/EdmondChuiHW) in
[#31274](#31274))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants