## Summary
- Bump React DevTools from 7.0.1 to 8.0.0 (packages + extension
manifests only; no publish).
- `scripts/devtools/prepare-release.js` only supports minor/patch, so
this major bump is manual.
- Changelog is curated from DevTools commits since 7.0.1 (features vs
bugfixes; internal/test-only changes omitted).
## Test plan
- [ ] Confirm published package versions would be 8.0.0 for
`react-devtools`, `react-devtools-core`, and `react-devtools-inline`
- [ ] Confirm Chrome/Edge/Firefox extension manifests show 8.0.0
- [ ] Review `packages/react-devtools/CHANGELOG.md` 8.0.0 section for
accuracy before undrafting
## Summary
The extension build writes `new Date().toLocaleDateString()` into
Chrome/Edge `version_name` and into every browser's manifest
description. That string changes with the calendar, timezone, and
locale, so a Firefox AMO rebuild on another day cannot match the
uploaded zip.
Stop stamping dates. `version_name` stays the value from the source
manifest (still updated by `prepare-release.js` on version bumps). The
description still records the commit from #37305.
Depends on #37305. Next: #37307.
## How did you test this change?
Build-script only. After this, `manifest.json` description is `Created
from revision <commit>.` and Chrome/Edge `version_name` is the committed
version string.
---------
Co-authored-by: Ruslan Lesiutin <hoxy@meta.com>
## Summary
`git show --format=%h` is not stable: abbreviation length depends on
`core.abbrev` and how unique the prefix is in that clone. Two rebuilds
of the same commit can therefore embed different strings in
`DEVTOOLS_VERSION` and the extension manifest.
Always take the full hash (`%H`) and slice it to 10 characters so the
value is the same everywhere.
This also removes the `build/COMMIT_SHA` fallback used when Mozilla
rebuilds from a git archive (no `.git`). That path used a different
length (7) and a different source, so it could not match a git checkout
of the same commit. Firefox source review should rebuild from a checkout
of the commit in #37307, not from the tarball alone.
Stack: this PR → #37306 → #37307.
## How did you test this change?
Build-script only. `getGitCommit()` now returns `HEAD` sliced to 10
chars, independent of `core.abbrev`.
Co-authored-by: Ruslan Lesiutin <hoxy@meta.com>
## Summary
With the tab gone, everything that fed it is unreachable. This deletes
`packages/react-devtools-timeline` (74 files) and the backend that
produced its data, `backend/profilingHooks.js`, along with
`SidebarEventInfo`, the two timeline test suites, the `timelineData`
snapshot serializer, and the scheduling-profiler fixture.
It also unwires the plumbing that only existed to carry timeline data:
`recordTimeline` across the reload-and-profile path (hook →
sessionStorage → agent → renderer), `timelineData` on
`ProfilingDataBackend` and the profile export, the `supportsTimeline`
Store config, the `rootSupportsTimelineProfiling` capability, the
`DevToolsProfilingHooks` type and the `ReactRenderer` members DevTools
used to inject it, the 40 `--color-timeline-*` theme variables in both
themes plus the orphaned `--color-scroll-caret`, and `hook.js`'s
internal-module-range tracking with its `react-devtools-facade` stubs.
`yarn.lock` is regenerated: 52 distinct package-versions and 68
requirement specs drop out, with no additions and no version changes to
anything that remains.
## Deliberate non-changes
- **`PROFILER_EXPORT_VERSION` stays at 5.**
`prepareProfilingDataFrontendFromExport` compares versions with `!==`,
so a bump would reject every profile anyone has already saved.
`timelineData` was an optional key, so dropping it is invisible in both
directions.
- **Profiling flag bit `0b010` is retired, not reused**, and the
constant is replaced by a comment saying so. Shipped backends keep
setting it, so renumbering `PROFILING_FLAG_PERFORMANCE_TRACKS_SUPPORT`
into that slot would make a new frontend misread older backends as
tracks-capable.
- **The `displayName` properties on DevTools' cache thenables are
kept.** They look timeline-only, but `ReactFiberThenable` reads
`thenable.displayName` to name I/O in async debug info, which feeds the
Performance tracks. Only their stale comments are corrected.
- **`react-reconciler`, `shared/ReactFeatureFlags.js` and
`scripts/rollup` are untouched**; `enableSchedulingProfiler` is still
live for www and native-fb.
## Follow-ups (not in this stack)
Three stale comments still name the removed package:
`scripts/rollup/wrappers.js:532` and `ReactFiberLane.js:38,125`. Left
alone to keep this stack purely DevTools-side.
## Test plan
`yarn linc`, `yarn flow dom-node`, and the DevTools suite all pass on
this commit in isolation (40/40 suites, 582 tests).
Previously, every instance of ErrorBoundary, which wraps every custom
panel in extension, was subscribing to errors from the Store. This would
report the same error for every mounted panel.
ErrorBoundary now only intercepts render-time errors, and Store errors
are captured and reported in an external subscription at the place where
Store is created.
I have noticed inconsistency errors being thrown during browser
navigations that involve entries from BFCache. The main argument on why
this could be affecting React DevTools backend lifecycle is the fact
that Chrome kills the port manually, while freezing and preserving the
JavaScript heap -
https://developer.chrome.com/blog/bfcache-extension-messaging-changes.
Basically, we could end up in a permutation, where port is dead, but
Backend / Agent are alive. Such setup is not expected by React DevTools.
On `main`:
https://github.com/user-attachments/assets/9ca10286-b545-4384-bd6b-33d9a4ddde3d
With these changes:
https://github.com/user-attachments/assets/c4639c4a-6385-4248-a5c4-a39895d7fff6
I couldn't come up with a good test for this yet, but I will try to add
something. I am not convinced yet that emulating `pagehide` / `pageshow`
would be sufficient to reproduce browser environment during BFCache
entries.
The main reason why I am doing this is because there is no API in the
browser to "unmount" the created panel.
If you have React DevTools installed, we should always create a panel,
but the contents of the panel should be dynamically populated based on
the target. If it is not a React app, we will continue showing the stub
message.
Previously, we wouldn't mount a panel at all, and historically we've
received a few reports of this as a bug.
I've been triaging some lifecycle races during sessions with BFCache
involved and noticed a few type errors in real world scenario. These
objects were not properly typed, fixing in this PR.
Buffers Bridge messages during extension port reconnects and adds a
readiness handshake for ordered queue flushing. Includes regression
coverage for reconnect delivery and listener cleanup.
Potential scenario could be a long user session, where Chrome kills one
of the extension ports to save resources and then user re-connects by
navigating back to the DevTools UI.
Builds on #37048 by replacing `any`-based Bridge and Wall boundaries
with typed `mixed` values and explicit runtime validation. Invalid
messages and post-shutdown operations now throw, while shutdown reliably
flushes queued messages even if cleanup fails.
Strengthens the DevTools Bridge and Wall contracts:
- Models event dictionaries as event-to-payload maps, using `void` for
events without payloads.
- Types `send(event, payload?)` directly, eliminating runtime
payload-arity handling.
- Replaces broad `any` transport types with `mixed` and boundary
validation.
- Throws on invalid lifecycle usage instead of warning or silently
returning.
- Ensures shutdown flushes queued messages even when Wall cleanup fails.
- Updates Wall implementations and adds Bridge lifecycle coverage.
## Summary
Mostly changing the casting syntax from `(x: Y)` to `x as Y`, as the old
syntax was deprecated and always causing an error in Flow
## How did you test this change?
`yarn flow-ci`
## Summary
Notable changes:
- Only $FlowFixMe, $FlowExpectedError suppression comments are supported
- All suppression comments need error code
- A lot of new invalid-compare and constant-condition errors suppressed.
These errors reveal potential logical bugs
## How did you test this change?
`yarn flow-ci`
This eliminates the gap in a reproducer for the React DevTools browser
extension from the source code that we submit to Firefox extension
stores.
We use the commit hash as part of the Backend version, here:
https://github.com/facebook/react/blob/2cfb221937eac48209d01d5dda5664de473b1953/packages/react-devtools-extensions/utils.js#L26-L38
The problem is that we archive the source code for Mozilla extension
store reviews and there is no git. But since we still download the React
sources from the CI, we could reuse the hash from `build/COMMIT_HASH`
file.
This has been causing some issues with the submission review on Firefox
store: we use OS-level paths in these source maps, which makes the build
artifact different from the one that's been submitted.
Also saves ~100Kb for main.js artifact.
If there is a large owner stack, we could potentially spam multiple
fetch requests for the same source map. This adds a simple deduplication
logic, based on URL.
Also, this adds a timeout of 60 seconds to all fetch requests initiated
by fileFetcher content script.
This fixes the displaying of "rendered by" section if owner stacks
contained any native frames. This regressed after
https://github.com/facebook/react/pull/34185, where we added the
Suspense boundary for the StackTraceView.
This fails because the Promise that is responsible for symbolication of
the source is never getting resolved or rejected.
Previously, we would just throw an Error without sending a corresponding
message to the `main` script, and it would just cache a Promise that is
never resolved, hence the Suspense boundary for "rendered by" section is
never resolved.
In a separate change, I think we need to update StackTraceView component
to display `native` as location, instead of `:0`:
<img width="712" height="118" alt="Screenshot 2025-08-20 at 00 20 42"
src="https://github.com/user-attachments/assets/c79735c9-fdd2-467c-96cd-2bc29d38c4e0"
/>
Stacked on #33983.
Allow React to be configured as the default handler of all links in
Chrome DevTools. To do this you need to configure the Chrome DevTools
setting for "Link Handling:" to be set to "React Developer Tools". By
default this doesn't do anything but if you then check the box added in
#33983 it starts open local files directly in the external editor.
This needs docs to show how to enable that option.
(As far as I can tell this broke in Chrome Canary 🙄 but hopefully fixed
before stable.)
When the browser theme changes, we don't immediately rerender the UI so
we don't pick up the new theme if the React devtools are set to auto.
This picks up the change immediately.
The `useOpenResource` hook is now used to open links. Currently, the
`<>` icon for the component stacks and the link in the bottom of the
components stack. But it'll also be used for many new links like stacks.
If this new option is configured, and this is a local file then this is
opened directly in the external editor. Otherwise it fallbacks to open
in the Sources tab or whatever the standalone or inline is configured to
use.
<img width="453" height="252" alt="Screenshot 2025-07-24 at 4 09 09 PM"
src="https://github.com/user-attachments/assets/04cae170-dd30-4485-a9ee-e8fe1612978e"
/>
I prominently surface this option in the Source pane to make it
discoverable.
<img width="588" height="144" alt="Screenshot 2025-07-24 at 4 03 48 PM"
src="https://github.com/user-attachments/assets/0f3a7da9-2fae-4b5b-90ec-769c5a9c5361"
/>
When this is configured, the "Open in Editor" is hidden since that's
just the default. I plan on deprecating this button to avoid having the
two buttons going forward.
Notably there's one exception where this doesn't work. When you click an
Action or Event listener it takes you to the Sources tab and you have to
open in editor from there. That's because we use the `inspect()`
mechanism instead of extracting the source location. That's because we
can't do the "throw trick" since these can have side-effects. The Chrome
debugger protocol would solve this but it pops up an annoying dialog. We
could maybe only attach the debugger only for that case. Especially if
the dialog disappears before you focus on the browser again.
I broke Firefox DevTools extension in #33968.
It turns out the Firefox has a placeholder object for the sources panel
which is empty. We need to detect the actual event handler.
This adds a "Code Editor" pane for the Chrome extension in the bottom
right corner of the "Sources" panel. If you end up getting linked to the
"Sources" panel from stack traces in console, performance tab, stacks in
React Component tab like the one added in #33954 basically everywhere
there's a link to source code. Then going from there to open in a code
editor should be more convenient. This adds a button to open the current
file.
<img width="1387" height="389" alt="Screenshot 2025-07-22 at 10 22
19 PM"
src="https://github.com/user-attachments/assets/fe01f84c-83c2-4639-9b64-4af1a90c3f7d"
/>
This only makes sense in the extensions since in standalone it needs to
always open by default in an editor. Unfortunately Firefox doesn't
support extending the Sources panel.
Chrome is also a bit buggy where it doesn't send a selection update
event when you switch tabs in the Sources panel. Only when the actual
cursor position changes. This means that the link can be lagging behind
sometimes. We also have some general bugs where if React DevTools loses
connection it can break the UI which includes this pane too.
This has a small inline configuration too so that it's discoverable:
<img width="559" height="143" alt="Screenshot 2025-07-22 at 10 22 42 PM"
src="https://github.com/user-attachments/assets/1270bda8-ce10-4f9d-9fcb-080c0198366a"
/>
<img width="527" height="123" alt="Screenshot 2025-07-22 at 10 22 30 PM"
src="https://github.com/user-attachments/assets/45848c95-afd8-495f-a7cf-eb2f46e698f2"
/>
Since we can't add a separate link to open-in-editor or open-in-sources
everywhere I plan on adding an option to open in editor by default in a
follow up. That option needs to be even more discoverable.
I moved the configuration from the Components settings to the General
settings since this is now a much more general features for opening
links to resources in all types of panes.
<img width="673" height="311" alt="Screenshot 2025-07-22 at 10 22 57 PM"
src="https://github.com/user-attachments/assets/ea2c0871-942c-4b55-a362-025835d2c2bd"
/>
In RSC and other stacks now we use a lot of `ReactFunctionLocation` type
to represent the location of a function. I.e. the location of the
beginning of the function (the enclosing line/col) that is represented
by the "Source" of the function. This is also what the parent Component
Stacks represents.
As opposed to `ReactCallSite` which is what normal stack traces and
owner stacks represent. I.e. the line/column number of the callsite into
the next function.
We can start sharing more code by using the `ReactFunctionLocation` type
to represent the component source location and it also helps clarify
which ones are function locations and which ones are callsites as we
start adding more stack traces (e.g. for async debug info and owner
stack traces).