We've been shipping unprefixed experimental APIs (like `createRoot` and
`useTransition`) to the Experimental release channel, with the rationale
that because these APIs do not appear in any stable release, we're free
to change or remove them later without breaking any downstream projects.
What we didn't consider is that downstream projects might be tempted to
use feature detection:
```js
const useTransition = React.useTransition || fallbackUseTransition;
```
This pattern assumes that the version of `useTransition` that exists in
the Experimental channel today has the same API contract as the final
`useTransition` API that we'll eventually ship to stable.
To discourage feature detection, I've added an `unstable_` prefix to
all of our unstable APIs.
The Facebook builds still have the unprefixed APIs, though. We will
continue to support those; if we make any breaking changes, we'll
migrate the internal callers like we usually do. To make testing easier,
I added the `unstable_`-prefixed APIs to the www builds, too. That way
our tests can always use the prefixed ones without gating on the
release channel.
* DevTools console override handles new component stack format
DevTools does not attempt to mimic the default browser console format for its component stacks but it does properly detect the new format for Chrome, Firefox, and Safari.
* Migrate conditional tests to gate pragma
I searched through the codebase for this pattern:
```js
describe('test suite', () => {
if (!__EXPERIMENTAL__) { // or some other condition
test("empty test so Jest doesn't complain", () => {});
return;
}
// Unless we're in experimental mode, none of the tests in this block
// will run.
})
```
and converted them to the `@gate` pragma instead.
The reason this pattern isn't preferred is because you end up disabling
more tests than you need to.
* Add flag for www release channels
Using a heuristic where I check a flag that is known to only be enabled
in www. I left a TODO to instead set the release channel explicitly in
each test config.
* Implement component stack extraction hack
* Normalize errors in tests
This drops the requirement to include owner to pass the test.
* Special case tests
* Add destructuring to force toObject which throws before the side-effects
This ensures that we don't double call yieldValue or advanceTime in tests.
Ideally we could use empty destructuring but ES lint doesn't like it.
* Cache the result in DEV
In DEV it's somewhat likely that we'll see many logs that add component
stacks. This could be slow so we cache the results of previous components.
* Fixture
* Add Reflect to lint
* Log if out of range.
* Fix special case when the function call throws in V8
In V8 we need to ignore the first line. Normally we would never get there
because the stacks would differ before that, but the stacks are the same if
we end up throwing at the same place as the control.
* Add feature flag
* Split stack from current fiber
You can get stack from any fiber, not just current.
* Refactor description of component frames
These should use fiber tags for switching. This also puts the relevant code
behind DEV flags.
* We no longer expose StrictMode in component stacks
They're not super useful and will go away later anyway.
* Update tests
Context is no longer part of SSR stacks. This was already the case on the
client.
forwardRef no longer is wrapped on the stack. It's still in getComponentName
but it's probably just noise in stacks. Eventually we'll remove the wrapper
so it'll go away anyway. If we use native stack frames they won't have this
extra wrapper.
It also doesn't pick up displayName from the outer wrapper. We could maybe
transfer it but this will also be fixed by removing the wrapper.
* Forward displayName onto the inner function for forwardRef and memo in DEV
This allows them to show up in stack traces.
I'm not doing this for lazy because lazy is supposed to be called on the
consuming side so you shouldn't assign it a name on that end. Especially
not one that mutates the inner.
* Use multiple instances of the fake component
We mutate the inner component for its name so we need multiple copies.
* Enable prefer-const rule
Stylistically I don't like this but Closure Compiler takes advantage of
this information.
* Auto-fix lints
* Manually fix the remaining callsites
DevTools previously used the NPM events package for dispatching events. This package has an unfortunate flaw though- if a listener throws during event dispatch, no subsequent listeners are called. I've replaced that event dispatcher with my own implementation that ensures all listeners are called before it re-throws an error.
This commit replaces that event emitter with a custom implementation that calls all listeners before re-throwing an error.
Previously, DevTools filtered empty commits on the backend, while profiling, through the use of a bailout heuristic that React currently happens to use. This approach was brittle and may have exacerbated the long-standing Profiler bug #16446.
This PR removes that heuristic and adds as a post-processing filtering pass instead. This removes the coupling between DevTools and a React internal implementation detail that may change.
I believe DevTools has two choices of criteria for this filtering:
* Filter commits that have no actual duration metadata.
* Filter commits that have no recorded operations (no mutations to the tree, no changed tree base durations).
I chose the first option, filtering by commits that have no reported metadata. It will miss an edge case, e.g. , but we would have nothing meaningful to show in the Profiler for those cases anyway. (This particular edge case is why one of the snapshots changed with this commit.)
The second option, filtering by recorded operations, could potentially miss a more important edge case: where a component *did* render, but its didn't change. (In that event, there would be no operations to send.)
DevTools previously called in several places with user-defined values. This could lead to runtime errors if those values had an overriden attribute. This commit replaces those callse with instead.
New test cases have been added.
The Profiler stores:
1. A snapshot of the React tree when profiling started
2. The operations array for each commit
3. Profiling metadata (e.g. durations, what changed, etc) for each commit
It uses this information (snapshot + operations diff) to reconstruct the state of the application for a given commit as it's viewed in the Profiler UI. Because of this, it's very important that the operations and metadata arrays align. If they don't align, the profiler will be unable to correctly reconstruct the tree, and it will likely throw errors (like 'Could not find node…')
#16446 tracks a long-standing bug where these two arrays get misaligned. I am still not entirely sure what causes this bug, but with PR #17253, I exacerbated things by introducing another potential way for it to happen. This PR addresses the regression at least (and adds test coverage for it).
I will follow up this afternoon on the original #16446 issue. I think I may have a lead on what's happening at least, if not exactly an idea of how to reproduce it.
Previously, when props/state contained a regexp, it was shown as an
empty object. This commit adds regexps as values in need of special
rehydration (like Symbols or TypedArrays), and display them as a user
might expect.
Co-authored-by: Zirak <zirakertan@gmail.com>
* Added rudimentary context menu hook and menu UI
* Added backend support for copying a value at a specific path for the inspected element
* Added backend support for storing a value (at a specified path) as a global variable
* Added special casing to enable copying undefined/unserializable values to the clipboard
* Added copy and store-as-global context menu options to selected element props panel
* Store global variables separately, with auto-incremented name (like browsers do)
* Added tests for new copy and store-as-global backend functions
* Fixed some ownerDocument/contentWindow edge cases
* Refactored context menu to support dynamic options
Used this mechanism to add a conditional menu option for inspecting the current value (if it's a function)
* Renamed "safeSerialize" to "serializeToString" and added inline comment
* Skip abandoned project folders in Jest config
This fixes a problem that occurs after renaming a package.
* Fix test_build_devtools to run test-build-devtools
* Exclude console.error plugin for DevTools packages
* Use correct release channel for DevTools tests
This should fix the createRoot error.
* Fix TZ dependent test
* Change DT job dependencies
* Improved inspected element props with inline previews
This mimics the inline preview shown by the brower console and dramatically improves the UX when inspecting deep values. I also updated tests to add more coverage for this new functionality.
* Cleaned up the DataView vs typed array check
* Added early bailouts to DevTools when generating preview strings for iterables/objects/arrays, to avoid doing unnecessary work
* fix: make serializable data for bridge in react-devtools
* fix: add bigint data type in hydration
* refactor: remove console.log
* test: update unit tests for bigint in react-devtools
1. Add a Store test for memo, lazy, and forwardRef components
2. Remove dead code for React.lazy
3. Update DT tests to include HOC badge names in the serialized store
* SuspenseList support in DevTools
This adds SuspenseList tags to DevTools so that the name properly shows
up.
It also switches to use the tag instead of Symbol type for Suspense
components. We shouldn't rely on the type for any built-ins since that
field will disappear from the fibers. How the Fibers get created is an
implementation detail that can change e.g. with a compiler or if we
use instanceof checks that are faster than symbol comparisons.
* Add SuspenseList test to shell app
* Tests run in experimental mode by default
For local development, you usually want experiments enabled. Unless
the release channel is set with an environment variable, tests will
run with __EXPERIMENTAL__ set to `true`.
* Remove concurrent APIs from stable builds
Those who want to try concurrent mode should use the experimental
builds instead.
I've left the `unstable_` prefixed APIs in the Facebook build so we
can continue experimenting with them internally without blessing them
for widespread use.
* Turn on SSR flags in experimental build
* Remove prefixed concurrent APIs from www build
Instead we'll use the experimental builds when syncing to www.
* Remove "canary" from internal React version string
* Update useEditableValue to mirror value cahnges
Previously, the hook initialized local state (in useState) to mirror the prop/state value. Updates to the value were ignored though. (Once the state was initialized, it was never updated.) The new hook updates the local/editable state to mirror the external value unless there are already pending, local edits being made.
* Optimistic CHANGELOG update
* Added additional useEditableValue() unit test cases
* [react-devtools-shared] Added string type check for object name prop in getDisplayName function from utils.js file; tests included;
* Re-added empty string check to getDisplayName()
* Tweaked tests to use real functions
This more closely simulates how the utility is being used in production, and would catch cases like anonymous functions (with empty string names).