Commit Graph

877 Commits

Author SHA1 Message Date
Ruslan Lesiutin
e2ba45bb39 [DevTools] fix: keep search query in a local sync state (#34423)
When the search query changes, we kick off a transition that updates the
search query in a reducer for TreeContext. The search input is also
using this value for an `input` HTML element.

For a larger applications, sometimes there is a noticeable delay in
displaying the updated search query. This changes the approach to also
keep a local synchronous state that is being updated on a change
callback.
2025-09-10 18:38:47 +01:00
Sebastian Markbåge
886b3d36d7 [DevTools] Show suspended by subtree from Activity to next Suspense boundary (#34438)
Stacked on #34435.

This adds a method to get all suspended by filtered by a specific
Instance. The purpose of this is to power the feature when you filter by
Activity. This would show you the "root" within that Activity boundary.

This works by selecting the nearest Suspense boundary parent and then
filtering its data based on if all the instances for a given I/O info is
within the Activity instance. If something suspended within the Suspense
boundary but outside the Activity it's not included even if it's also
suspending inside the Activity since we assume it would've already been
loaded then.

Right now I wire this up to be a special case when you select an
Activity boundary same as when you select a Suspense boundary in the
Components tab but we could also only use this when you select the root
in the Suspense tab for example.
2025-09-10 09:44:51 -04:00
Sebastian Markbåge
288d428af1 [DevTools] Only show the highest end/byteSize I/O of RSC streams (#34435)
Stacked on #34425.

RSC stream info is split into one I/O entry per chunk. This means that
when a single instance or boundary depends on multiple chunks, it'll
show the same stream multiple times. This makes it so just the last one
is shown.

This is a special case for the name "RSC stream" but ideally we'd more
explicitly model the concept of awaiting only part of a stream.

<img width="667" height="427" alt="Screenshot 2025-09-09 at 2 09 43 PM"
src="https://github.com/user-attachments/assets/890f6f61-4657-4ca9-82fd-df55a696bacc"
/>

Another remaining issue is that it's possible for an intermediate chunk
to be depended on by just a child boundary. In that case that can be
considered a "unique suspender" even though the parent depends on a
later one. Ideally it would dedupe on everything below. Could also model
it as every Promise depends on its chunk and every previous chunk.
2025-09-10 09:08:36 -04:00
Sebastian "Sebbie" Silbermann
6b70072c4f [DevTools] Finalize heuristic for naming unnamed <Suspense> (#34428) 2025-09-09 17:56:26 +02:00
Sebastian "Sebbie" Silbermann
8943025358 [DevTools] Fix handling of host roots on mount (#34400) 2025-09-08 22:53:02 +02:00
Sebastian "Sebbie" Silbermann
3fb190f729 [DevTools] Avoid renders of stale Suspense store (#34396) 2025-09-08 11:42:03 +02:00
KimCookieYa
c4e2508dad [react-devtools-shared] Fix URL construction when base URL is invalid (#34407)
### Problem
- Users encounter “Failed to construct 'URL': Invalid base URL” when
clicking the “View source” action in DevTools if the underlying base URL
is invalid.
- This exception originates from `new URL(relative, base)` and bubbles
up, interrupting the DevTools UI.
- Fixes GitHub issue
[#34317](https://github.com/facebook/react/issues/34317)

### Solution
- Wrap URL construction to:
  - First try `new URL(sourceMapAt, sourceURL)`.
  - If that fails, try `new URL(sourceMapAt)` as an absolute URL.
  - If both fail, return `null` (no symbolication) rather than throwing.
- This preserves normal behavior for valid bases and absolute URLs,
while avoiding crashes for invalid bases.

### Implementation details
- Updated `symbolicateSource` in
`packages/react-devtools-shared/src/symbolicateSource.js` to handle
invalid base URL scenarios without throwing.
- Added/verified tests in
`packages/react-devtools-shared/src/__tests__/utils-test.js`:
- “should not throw for invalid base URL with relative source map” →
resolves to `null`.
- “should resolve absolute source map even if base URL is invalid” →
still resolves correctly.

### Test plan
- Lint/format:
  - `yarn prettier-check`
  - `yarn linc`
- Type checking:
  - `yarn flow dom-node`
- Unit tests:
  - `yarn test --watchAll=false utils-test`
  - Optionally: `yarn test --watchAll=false utils-test inspectedElement`
- All of the above pass locally for experimental channel.

### Risks and rollout
- Risk: Low. Only affects cases where the base URL is invalid.
- Normal cases (valid base or absolute `sourceMappingURL`) are
unchanged.
- No user-facing API changes; DevTools UX becomes more resilient.

### Affected packages
- `react-devtools-shared`

### Related
- Fixes GitHub issue
[#34317](https://github.com/facebook/react/issues/34317)

### Checklist
- [x] Ran `yarn prettier-check`
- [x] Ran `yarn linc`
- [x] Ran `yarn flow dom-node`
- [x] Relevant unit tests passing
- [x] Linked issue and added a concise summary


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

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

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

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

## Summary

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

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->
2025-09-06 14:00:45 +01:00
Sebastian "Sebbie" Silbermann
b9a045368b [DevTools] Allow inspecting root when navigating Suspense timeline (#34380) 2025-09-04 16:42:25 +02:00
Sebastian "Sebbie" Silbermann
e2cc315a1b [DevTools] Don't suspend shell while retrieving original source for "open-in-editor" (#34381) 2025-09-04 16:39:07 +02:00
Sebastian "Sebbie" Silbermann
ba6590dd7c [DevTools] Rerender boundaries when they unsuspend when advancing the timeline (#34359) 2025-09-04 10:49:16 +02:00
Sebastian "Sebbie" Silbermann
8e60cb7ed5 [DevTools] Remove markers from Suspense timeline (#34357) 2025-09-02 14:59:15 +02:00
Sebastian "Sebbie" Silbermann
6a58b80020 [DevTools] Only inspect elements on left mouseclick (#34361) 2025-09-02 12:40:54 +02:00
Sebastian "Sebbie" Silbermann
b1b0955f2b [DevTools] Fix inspected element scroll in Suspense tab (#34355) 2025-09-01 16:40:30 +02:00
Sebastian "Sebbie" Silbermann
89a803fcec [DevTools] Add breadcrumbs to Suspense tab (#34312) 2025-08-28 16:03:54 +02:00
Sebastian "Sebbie" Silbermann
213594860f [DevTools] Better scrolling in Suspense tab (#34299) 2025-08-27 16:00:06 +02:00
Sebastian "Sebbie" Silbermann
cb1e73be04 [DevTools] Batch Suspense toggles when advancing the Suspense timeline (#34251) 2025-08-26 17:22:30 +02:00
Sebastian "Sebbie" Silbermann
bb7c9c1b8a Create more realistic containers in DevTools fixture (#34296) 2025-08-26 17:13:37 +02:00
Sebastian "Sebbie" Silbermann
44f8451ede [DevTools] Avoid tearing Suspense store (#34294) 2025-08-26 17:09:55 +02:00
Sebastian "Sebbie" Silbermann
ad4ecb6e6e [DevTools] Fix symbolication with Index Source Maps (#34300) 2025-08-26 15:18:20 +02:00
Jan Kassens
26e87b5f15 Fix Flow issue from land race (#34293)
A Flow upgrade removed the bundled library definitinos for
SynthaticEvent and we probably want to use our internal definitions.
Those are not properly typed at this point yet, but we can look into
that as a followup.
2025-08-25 12:58:12 -04:00
Sebastian "Sebbie" Silbermann
75dc0026d6 [DevTools] Initial version of Suspense timeline (#34233) 2025-08-25 17:47:29 +02:00
Jan Kassens
df10309e2b Update Flow to 0.279 (#34277)
Multiple of these version upgrades required minor additional
annotations.
2025-08-25 11:02:56 -04:00
Sebastian "Sebbie" Silbermann
e42f3d30ca [DevTools] Include name prop when highlighting host instances (#34258) 2025-08-25 16:40:56 +02:00
Jan Kassens
4049cfeeab Update Flow to 0.273 (#34274)
This version introduces "Natural Inference" which requires a couple more
type annotations to make Flow pass.
2025-08-22 16:58:01 -04:00
Jan Kassens
06cfa99f37 Update Flow to 0.267 (#34272)
Changes to type inference require some more annotations.
2025-08-22 15:53:07 -04:00
Jan Kassens
05addfc663 Update Flow to 0.266 (#34271)
- replace `$ElementType` and `$PropertyType` with `T[K]` accesses.
- Use component types
2025-08-22 15:46:41 -04:00
Jan Kassens
d260b0d8b8 Update Flow to 0.265 (#34270)
Looks like this version removed `Object.prototype` although I didn't see
that in the changelog. This is fine for this code here.
2025-08-22 15:22:22 -04:00
Jan Kassens
6de32a5a07 Update Flow to 0.263 (#34269)
This update was a bit more involved.

- `React$Component` was removed, I replaced it with Flow component
types.
- Flow removed shipping the standard library. This adds the environment
libraries back from `flow-typed` which seemed to have changed slightly
(probably got more precise and less `any`s). Suppresses some new type
errors.
2025-08-22 12:10:13 -04:00
Sebastian Markbåge
11d7bcf88c [DevTools] Use source maps to infer name asynchronously (#34212) 2025-08-22 00:38:09 +02:00
Sebastian Markbåge
a85ec041d6 [DevTools] Ignore List Stack Traces (#34210)
Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>
2025-08-22 00:03:05 +02:00
Jan Kassens
ec5dd0ab3a Update Flow to 0.257 (#34253)
After an easy couple version with #34252, this version is less flexible
(and safer) on inferring exported types mainly.

We require to annotate some exported types to differentiate between
`boolean` and literal `true` types, etc.
2025-08-21 13:30:01 -04:00
Jan Kassens
873f711299 Update Flow to 0.248 (#34248)
This update remove support for `%checks`.

Thanks @SamChou19815 for finding a close replacement that works.
2025-08-21 11:15:34 -04:00
Jan Kassens
5f06c3d22a Update Flow to 0.247 (#34245)
`$Call` was removed.
2025-08-20 22:19:57 -04:00
Sebastian "Sebbie" Silbermann
03fda05d2c [DevTools] Fix display of stack frames with anonymous sources (#34237) 2025-08-20 17:31:42 +02:00
Sebastian "Sebbie" Silbermann
ae5c2f82b3 [DevTools] Handle reorders when resuspending while fallback contains Suspense (#34225) 2025-08-19 20:22:54 +02:00
Sebastian "Sebbie" Silbermann
01ed0e9642 [DevTools] Avoid uncached Promise when symbolicating sources in environments without file fetching (#34224) 2025-08-18 12:46:19 +02:00
Sebastian "Sebbie" Silbermann
b58a8e3c40 [DevTools] Handle mount of disconnected Suspense boundaries (#34208) 2025-08-18 10:15:56 +02:00
Sebastian Markbåge
42b1b33a24 [DevTools] Add byteSize field to ReactIOInfo and show this in the tooltip (#34221)
This is intended to be used by various client side resources where the
transfer size is interesting to know how it'll perform in various
network conditions. Not intended to be added by the server.

For now it's only added internally by DevTools itself on img/css but
I'll add it from Flight Client too in a follow up.

This now shows this as the "transfer size" which is the encoded body
size + headers/overhead. Where as the "fileSize" that I add to images is
the decoded body size, like what you'd see on disk. This is what Chrome
shows so it's less confusing if you compare Network tab and this view.
2025-08-17 16:17:11 -04:00
Sebastian "Sebbie" Silbermann
546bac7281 [DevTools] Always attempt to mount dehydrated roots (#34209) 2025-08-16 10:45:39 +02:00
Sebastian "Sebbie" Silbermann
2cb8edbb05 [DevTools] Handle dehydrated Suspense boundaries (#34196) 2025-08-16 10:34:19 +02:00
Sebastian Markbåge
431bb0bddb [DevTools] Mark Unknown Reasons for Suspending with a Note (#34200)
We currently only track the reason something might suspend in
development mode through debug info but this excludes some cases. As a
result we can end up with boundary that suspends but has no cause. This
tries to detect that and show a notice for why that might be. I'm also
trying to make it work with old React versions to cover everything.

In production we don't track any of this meta data like `_debugInfo`,
`_debugThenable` etc. so after resolution there's no information to take
from. Except suspensey images / css which we can track in prod too. We
could track lazy component types already. We'd have to add something
that tracks after the fact if something used a lazy child, child as a
promise, hooks, etc. which doesn't exist today. So that's not backwards
compatible and might add some perf/memory cost. However, another
strategy is also to try to replay the components after the fact which
could be backwards compatible. That's tricky for child position since
there's so many rules for how to do that which would have to be
replicated.

If you're in development you get a different error. Given that we've
added instrumentation very recently. If you're on an older development
version of React, then you get a different error. Unfortunately I think
my feature test is not quite perfect because it's tricky to test for the
instrumentation I just added.
https://github.com/facebook/react/pull/34146 So I think for some
prereleases that has `_debugOwner` but doesn't have that you'll get a
misleading error.

Finally, if you're in a modern development environment, the only reason
we should have any gaps is because of throw-a-Promise. This will
highlight it as missing. We can detect that something threw if a
Suspense boundary commits with a RetryCache but since it's a WeakSet we
can't look into it to see anything about what it might have been. I
don't plan on doing anything to improve this since it would only apply
to new versions of React anyway and it's just inherently flawed. So just
deprecate it #34032.

Note that nothing in here can detect that we suspended Transition. So
throwing at the root or in an update won't show that anywhere.
2025-08-15 18:32:27 -04:00
Sebastian "Sebbie" Silbermann
8dba9311e5 [DevTools] Handle fallback unmount in Suspense update path (#34199) 2025-08-15 19:40:35 +02:00
Sebastian "Sebbie" Silbermann
2d98b45d92 [DevTools] Fix Suspense boundaries always being marked as not suspended (#34206) 2025-08-15 19:39:59 +02:00
Sebastian Markbåge
2ba7b07ce1 [DevTools] Compute a min and max range for the currently selected suspense boundary (#34201)
This computes a min and max range for the whole suspense boundary even
when selecting a single component so that each component in a boundary
has a consistent range.

The start of this range is the earliest start of I/O in that boundary or
the end of the previous suspense boundary, whatever is earlier. If the
end of the previous boundary would make the range large, then we cap it
since it's likely that the other boundary was just an independent
render.

The end of the range is the latest end of I/O in that boundary. If this
is smaller than the end of the previous boundary plus the 300ms
throttle, then we extend the end. This visualizes what throttling could
potentially do if the previous boundary committed right at its end. Ofc,
it might not have committed exactly at that time in this render. So this
is just showing a potential throttle that could happen. To see actual
throttle, you look in the Performance Track.

<img width="661" height="353" alt="Screenshot 2025-08-14 at 12 41 43 AM"
src="https://github.com/user-attachments/assets/b0155e5e-a83f-400c-a6b9-5c38a9d8a34f"
/>

We could come up with some annotation to highlight that this is eligible
to be throttled in this case. If the lines don't extend to the edge,
then it's likely it was throttled.
2025-08-15 13:34:07 -04:00
Sebastian "Sebbie" Silbermann
02a8811864 [SuspenseTab] Scuffed version of Suspense rects (#34188) 2025-08-14 18:24:41 +02:00
Sebastian "Sebbie" Silbermann
379a083b9a Include stack of cause in React instrumentation errors (#34198) 2025-08-13 19:18:02 +02:00
Sebastian Markbåge
db06f6b751 [DevTools] Track virtual debug info from suspensey images (#34181)
Same as #34166 but for Suspensey images.

The trick here is to check the `SuspenseyImagesMode` since not all
versions of React and not all subtrees will have Suspensey images
enabled yet.

The other trick is to read back from `currentSrc` to get the image url
we actually resolved to in this case. Similar to how for Suspensey CSS
we check if the media query would've matched.

<img width="591" height="205" alt="Screenshot 2025-08-11 at 9 32 56 PM"
src="https://github.com/user-attachments/assets/ac98785c-d3e0-407c-84e0-c27f86c0ecac"
/>
2025-08-13 09:26:21 -04:00
Sebastian Markbåge
14c50e344c [DevTools] Use Visually Lighter Skeletons (#34185)
The skeletons right now are too jarring because they're visually heavier
than the content that comes in later. This makes them draw attention to
themselves as flashing things.

A good skeleton and loading indicator should ideally start as invisible
as possible and then gradually become more visible the longer time
passes so that if it loads quickly then it was never much visible at
all.

Even at its max it should never be heavier weight than the final content
so that it visually reverts into lesser. Another rule of thumb is that
it should be as close as possible to the final content in size but if
it's unknown it should always be smaller than the final content so that
the content grows into its slot rather than the slot contracting.

This makes the skeleton fade from invisible into the dimmest color just
as a subtle hint that something is still loading.

I also added a missing skeleton since the stack traces in rendered by
can now suspend while source mapping.

The other tweak I did is use disabled buttons in all the cases where we
load the ability to enable a button. This is more subtle and if you
hover over you can see why it's still disabled. Rather than flashing the
button each time you change element.
2025-08-12 23:10:31 -04:00
Sebastian "Sebbie" Silbermann
0422a00e3e [DevTools] Fix missing key warning (#34186) 2025-08-12 19:58:19 +02:00
Sebastian Markbåge
47fd2f5e14 [DevTools] Fix index (#34187)
I used the wrong indexer and tested with one entry.
2025-08-12 13:57:35 -04:00