Commit Graph

4193 Commits

Author SHA1 Message Date
Robert Balicki aa80a309b1
[react devtools][easy] Rename LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY to LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY (#25154)
* This more accurately describes what this constant does
2022-08-30 13:32:52 -04:00
Tianyu Yao 9ff738f53f
[devtools][easy] Fix flow type (#25147) 2022-08-26 18:47:39 -07:00
Ricky 0de3ddf56e
Remove Symbol Polyfill (again) (#25144) 2022-08-25 17:01:30 -04:00
Samuel Susla b36f722357
Remove ReactFiberFlags MountLayoutDev and MountPassiveDev (#25091) 2022-08-25 20:23:10 +01:00
Andrew Clark b6978bc38f
experimental_use(promise) (#25084)
* Internal `act`: Unwrapping resolved promises

This update our internal implementation of `act` to support React's new
behavior for unwrapping promises. Like we did with Scheduler, when 
something suspends, it will yield to the main thread so the microtasks
can run, then continue in a new task.

I need to implement the same behavior in the public version of `act`,
but there are some additional considerations so I'll do that in a
separate commit.

* Move throwException to after work loop resumes

throwException is the function that finds the nearest boundary and
schedules it for a second render pass. We should only call it right 
before we unwind the stack — not if we receive an immediate ping and
render the fiber again.

This was an oversight in 8ef3a7c that I didn't notice because it happens
to mostly work, anyway. What made me notice the mistake is that
throwException also marks the entire render phase as suspended
(RootDidSuspend or RootDidSuspendWithDelay), which is only supposed to
be happen if we show a fallback. One consequence was that, in the 
RootDidSuspendWithDelay case, the entire commit phase was blocked,
because that's the exit status we use to block a bad fallback
from appearing.

* Use expando to check whether promise has resolved

Add a `status` expando to a thrown thenable to track when its value has
resolved.

In a later step, we'll also use `value` and `reason` expandos to track
the resolved value.

This is not part of the official JavaScript spec — think of
it as an extension of the Promise API, or a custom interface that is a
superset of Thenable. However, it's inspired by the terminology used
by `Promise.allSettled`.

The intent is that this will be a public API — Suspense implementations
can set these expandos to allow React to unwrap the value synchronously
without waiting a microtask.

* Scaffolding for `experimental_use` hook

Sets up a new experimental hook behind a feature flag, but does not
implement it yet.

* use(promise)

Adds experimental support to Fiber for unwrapping the value of a promise
inside a component. It is not yet implemented for Server Components, 
but that is planned.

If promise has already resolved, the value can be unwrapped
"immediately" without showing a fallback. The trick we use to implement
this is to yield to the main thread (literally suspending the work
loop), wait for the microtask queue to drain, then check if the promise
resolved in the meantime. If so, we can resume the last attempted fiber
without unwinding the stack. This functionality was implemented in 
previous commits.

Another feature is that the promises do not need to be cached between
attempts. Because we assume idempotent execution of components, React
will track the promises that were used during the previous attempt and
reuse the result. You shouldn't rely on this property, but during
initial render it mostly just works. Updates are trickier, though,
because if you used an uncached promise, we have no way of knowing 
whether the underlying data has changed, so we have to unwrap the
promise every time. It will still work, but it's inefficient and can
lead to unnecessary fallbacks if it happens during a discrete update.

When we implement this for Server Components, this will be less of an
issue because there are no updates in that environment. However, it's
still better for performance to cache data requests, so the same
principles largely apply.

The intention is that this will eventually be the only supported way to
suspend on arbitrary promises. Throwing a promise directly will
be deprecated.
2022-08-25 14:12:07 -04:00
Luna Ruan 11ed7010c6
[Transition Tracing] onMarkerIncomplete - Tracing Marker/Suspense Boundary Deletions (#24885)
This PR adds the `onMarkerIncomplete` callback for tracing marker name changes. Specifically, this PR:
* Adds the `onMarkerIncomplete` callback
* When a tracing marker is deleted, call `onMarkerIncomplete` with the `name` of the tracing marker for the tracing marker. 
* When a tracing marker/suspense boundary is deleted, call `onMarkerIncomplete` for every parent tracing marker with the `name` of the tracing marker that caused the transition to be incomplete. 
* Don't call `onTransitionComplete` or `onMarkerComplete` when `onMarkerIncomplete` is called for all tracing markers with the same transitions, but continue to call `onTransitionProgress`
2022-08-25 11:03:03 -07:00
Sebastian Markbåge b79894259a
[Flight] Add support for Webpack Async Modules (#25138)
This lets you await the result of require(...) which will then
mark the result as async which will then let the client unwrap the Promise
before handing it over in the same way.
2022-08-25 12:27:30 -04:00
kwzr c8b778b7f4
Fix typo: supportsMicrotask -> supportsMicrotasks (#25142) 2022-08-25 16:56:24 +01:00
Sebastian Markbåge d0f396651b
Allow functions to be used as module references (#25137) 2022-08-25 07:47:38 -04:00
Sebastian Markbåge 38c5d8a035
Test the node-register hooks in unit tests (#25132) 2022-08-24 19:05:39 -04:00
Tianyu Yao 3f70e68cea
Return closestInstance in `getInspectorDataForViewAtPoint` (#25118) 2022-08-24 11:26:08 -07:00
Tianyu Yao 181525338e
[DevTools] Highlight RN elements on hover (#25106)
* [DevTools] Highlight RN elements on hover

* Remove unused TODO
2022-08-24 11:25:22 -07:00
Tim Neutkens 3d443cad74
Update fixtures/flight to webpack 5 (#25115)
* Add new flight fixture

* Move flight dir files

* Enable writeToDisk and distDir

* Move flight2 -> flight

* flight2 -> flight

* Remove unused files

* Remove unused files

* Run prettier

* Ignore eslint cache

Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
2022-08-23 21:18:05 -04:00
Samuel Susla 5d1ce65139
Align StrictMode behaviour with production (#25049)
* Skip double invoking effects in Offscreen

* Run yarn replace-fork

* Use executionContext to disable profiler timer

* Restructure recursion into two functions

* Fix ReactStrictMode test

* Use gate pragma in ReacetOffscreenStrictMode test

* Set and reset current debug fiber in dev

* Skip over paths that don't include any insertions

* Extract common logic to check for profiling to a helper function

* Remove hasPassiveEffects flag from StrictMode

* Fix flow issues

* Revert "Skip over paths that don't include any insertions"
2022-08-23 18:19:07 +01:00
Joseph Savona 9e67e7a315
Scaffolding for useMemoCache hook (#25123)
* Scaffolding for useMemoCache hook
* cleanup leftovers from copy/paste of use() diff

Co-authored-by: Andrew Clark <git@andrewclark.io>
2022-08-23 09:36:02 +01:00
taiga e25648b0a8
devtools: Fix typo from directores to directories (#25124) 2022-08-22 18:40:26 +02:00
Tianyu Yao 26ba5fb2e0
[DevTools] Add events necessary for click to inspect on RN (#25111)
* Add inspectingNative events for RN

* Enable inspection toggle UI for RN

* Add a stopInspectingNative method for agent
2022-08-19 16:18:14 -07:00
Jiachi Liu 19e9a4c68e
Add missing createServerContext for experimental shared subset (#25114) 2022-08-18 09:33:36 -04:00
Josh Story 1e5245df89
support subresource integrity for bootstrapScripts and bootstrapModules (#25104) 2022-08-17 08:31:05 +01:00
Josh Story 6ef466c681
make preamble and postamble types explicit and fix typo (#25102) 2022-08-16 12:17:49 +01:00
Josh Story 796d31809b
Implement basic stylesheet Resources for react-dom (#25060)
Implement basic support for "Resources". In the context of this commit, the only thing that is currently a Resource are

<link rel="stylesheet" precedence="some-value" ...>

Resources can be rendered anywhere in the react tree, even outside of normal parenting rules, for instance you can render a resource before you have rendered the <html><head> tags for your application. In the stream we reorder this so the browser always receives valid HTML and resources are emitted either in place (normal circumstances) or at the top of the <head> (when you render them above or before the <head> in your react tree)

On the client, resources opt into an entirely different hydration path. Instead of matching the location within the Document these resources are queried for in the entire document. It is an error to have more than one resource with the same href attribute.

The use of precedence here as an opt-in signal for resourcifying the link is in preparation for a more complete Resource implementation which will dedupe resource references (multiple will be valid), hoist to the appropriate container (body, head, or elsewhere), order (according to precedence) and Suspend boundaries that depend on them. More details will come in the coming weeks on this plan.

This feature is gated by an experimental flag and will only be made available in experimental builds until some future time.
2022-08-12 13:27:53 -07:00
Luna Ruan 32baab38f8
[Transition Tracing] Add Tag Field to Marker Instance (#25085)
We were previously using `markerInstance.name` to figure out whether the marker instance was on the tracing marker or the root, but this is unsustainable. This adds a tag field so we can explicitly check this.
2022-08-11 23:04:45 -04:00
Andrew Clark 8ef3a7c08c
Resume immediately pinged fiber without unwinding (#25074)
* Yield to main thread if continuation is returned

Instead of using an imperative method `requestYield` to ask Scheduler to
yield to the main thread, we can assume that any time a Scheduler task
returns a continuation callback, it's because it wants to yield to the
main thread. We can assume the task already checked some condition that
caused it to return a continuation, so we don't need to do any
additional checks — we can immediately yield and schedule a new task
for the continuation.

The replaces the `requestYield` API that I added in ca990e9.

* Move unwind after error into main work loop

I need to be able to yield to the main thread in between when an error
is thrown and when the stack is unwound. (This is the motivation behind
the refactor, but it isn't implemented in this commit.) Currently the
unwind is inlined directly into `handleError`.

Instead, I've moved the unwind logic into the main work loop. At the
very beginning of the function, we check to see if the work-in-progress
is in a "suspended" state — that is, whether it needs to be unwound. If
it is, we will enter the unwind phase instead of the begin phase.

We only need to perform this check when we first enter the work loop:
at the beginning of a Scheduler chunk, or after something throws. We
don't need to perform it after every unit of work.

* Yield to main thread whenever a fiber suspends

When a fiber suspends, we should yield to the main thread in case the
data is already cached, to unblock a potential ping event.

By itself, this commit isn't useful because we don't do anything special
in the case where to do receive an immediate ping event. I've split this
out only to demonstrate that it doesn't break any existing behavior.

See the next commit for full context and motivation.

* Resume immediately pinged fiber without unwinding

If a fiber suspends, and is pinged immediately in a microtask (or a
regular task that fires before React resumes rendering), try rendering
the same fiber again without unwinding the stack. This can be super
helpful when working with promises and async-await, because even if the
outermost promise hasn't been cached before, the underlying data may
have been preloaded. In many cases, we can continue rendering
immediately without having to show a fallback.

This optimization should work during any concurrent (time-sliced)
render. It doesn't work during discrete updates because those are
semantically required to finish synchronously — those get the current
behavior.
2022-08-11 22:01:56 -04:00
Robert Balicki 4e60dbd905
[easy] Clarify folders in react devtools readme #25077
Clarify the folder from which we run various commands in the react-devtools readme
2022-08-11 19:47:02 -04:00
Samuel Susla 7bcc687720
Remove argument committedLanes from reappearLayoutEffects and recursivelyTraverseReappearLayoutEffects (#25080) 2022-08-11 14:24:56 +01:00
Andrew Clark ca990e9a75
Add API to force Scheduler to yield for macrotask (#25044)
We need a way to yield control of the main thread and schedule a
continuation in a separate macrotask. (This is related to some Suspense
optimizations we have planned.)

Our solution needs account for how Scheduler is implemented. Scheduler
tasks are not 1:1 with real browser macrotasks — many Scheduler "tasks"
can be executed within a single browser task. If a Scheduler task yields
control and posts a continuation, but there's still time left in the
frame, Scheduler will execute the continuation immediately
(synchronously) without yielding control back to the main thread. That's
not what we want — we want to schedule a new macrotask regardless of
where we are in the browser's render cycle.

There are several ways we could approach this. What I ended up doing was
adding a new Scheduler method `unstable_requestYield`. (It's similar to
the existing `unstable_requestPaint` that we use to yield at the end of
the frame.)

It works by setting the internal start time of the current work loop to
a large negative number, so that when the `shouldYield` call computes
how much time has elapsed, it's guaranteed to exceed the deadline. The
advantage of doing it this way is that there are no additional checks in
the normal hot path of the work loop.

The existing layering between Scheduler and React DOM is not ideal. None
of the APIs are public, so despite the fact that Scheduler is a separate
package, I consider that a private implementation detail, and think of
them as part of the same unit.

So for now, though, I think it makes sense to implement this macrotask
logic directly inside of Scheduler instead of layering it on top.

The rough eventual plan for Scheduler is turn it into a `postTask`
prollyfill. Because `postTask` does not yet have an equivalent for
`shouldYield`, we would split that out into its own layer, perhaps
directly inside the reconciler. In that world, the macrotask logic I've
added in this commit would likely live in that same layer. When the
native `postTask` is available, we may not even need any additional
logic because it uses actual browser tasks.
2022-08-04 21:20:15 -04:00
Andrew Clark b4204ede66
Clean up unused Deletion flag (#24992)
This was replaced by the ChildDeletion flag when we refactored the 
commit phase.
2022-08-03 17:03:53 -04:00
Luna Ruan e193be87e6
[Transition Tracing] Add Offscreen Test (#25035)
Add a test to make sure offscreen trees don't stop transitions from completing.
2022-08-03 13:24:41 -04:00
Sebastian Markbåge 9fcaf88d58
Remove rootContainerInstance from unnecessary places (#25024)
We only really use this for the create APIs since the DOM requires it.

We could probably use the Host Context for this instead since they're
updated at the same time and the namespace is related to this concept.
2022-08-01 23:30:04 -04:00
Konpaku Youmu 3f3b46c845
docs(react-devtools-inline): `react-dom@experimental` instead of `react-dom@experimenal` (#25001) 2022-07-30 10:57:13 +02:00
Andrew Clark 80f3d88190
Mount/unmount passive effects when Offscreen visibility changes (#24977)
* Remove unnecessary try-catch from passive deletion

The individual unmount calls are already wrapped in a catch block, so
this outer one serves no purpose.

* Extract passive unmount effects to separate functions
    
I'm about to add a "disconnect passive effects" function that will share
much of the same code as commitPassiveUnmountOnFiber. To minimize the
duplicated code, I've extracted the shared parts into separate
functions, similar to what I did for commitLayoutEffectOnFiber and
reappearLayoutEffects.

This may not save much on code size because Closure will likely inline
some of it, anyway, but it makes it harder for the two paths to
accidentally diverge.

* Mount/unmount passive effects on hide/show

This changes the behavior of Offscreen so that passive effects are
unmounted when the tree is hidden, and re-mounted when the tree is
revealed again. This is already how layout effects worked.

In the future we will likely add an option or heuristic to only unmount
the effects of a hidden tree after a delay. That way if the tree quickly
switches back to visible, we can skip toggling the effects entirely.

This change does not apply to suspended trees, which happen to use
the Offscreen fiber type as an implementation detail. Passive effects
remain mounted while the tree is suspended, for the reason described
above — it's likely that the suspended tree will resolve and switch
back to visible within a short time span.

At a high level, what this capability enables is a feature we refer to
as "resuable state". The real value proposition here isn't so much the
behavior of effects — it's that you can switch back to a previously
rendered tree without losing the state of the UI.

* Add more coverage for nested Offscreen cases
2022-07-29 19:34:28 -04:00
Andrew Clark 4ea064eb09
Don't fire passive effects during initial mount of a hidden Offscreen tree (#24967)
* Change OffscreenInstance isHidden to bitmask

The isHidden field of OffscreenInstance is a boolean that represents
whether the tree is currently hidden. To implement resuable effects, we
need to also track whether the passive effects are currently connected.
So I've changed this field to a bitmask.

No other behavior has changed in this commit. I'll update the effects
behavior in the following steps.

* Extract passive mount effects to separate functions

I'm about to add a "reappear passive effects" function that will share
much of the same code as commitPassiveMountEffectOnFiber. To minimize
the duplicated code, I've extracted the shared parts into separate
functions, similar to what I did for commitLayoutEffectOnFiber and
reappearLayoutEffects.

This may not save much on code size because Closure will likely inline
some of it, anyway, but it makes it harder for the two paths to
accidentally diverge.

* Don't mount passive effects in a new hidden tree

This changes the behavior of Offscreen so that passive effects do not
fire when prerendering a brand new tree. Previously, Offscreen did not
affect passive effects at all — only layout effects, which mount or
unmount whenever the visibility of the tree changes.

When hiding an already visible tree, the behavior of passive effects is
unchanged, for now; unlike layout effects, the passive effects will not
get unmounted. Pre-rendered updates to a hidden tree in this state will
also fire normally. This is only temporary, though — the plan is for
passive effects to act more like layout effects, and unmount them when
the tree is hidden. Perhaps after a delay so that if the visibility
toggles quickly back and forth, the effects don't need to remount. I'll
implement this separately.

* "Atomic" passive commit effects must always fire

There are a few cases where commit phase logic always needs to fire even
inside a hidden tree. In general, we should try to design algorithms
that don't depend on a commit effect running during prerendering, but
there's at least one case where I think it makes sense.

The experimental Cache component uses reference counting to keep track
of the lifetime of a cache instance. This allows us to expose an
AbortSignal object that data frameworks can use to cancel aborted
requests. These cache objects are considered alive even inside a
prerendered tree.

To implement this I added an "atomic" passive effect traversal that runs
even when a tree is hidden. (As a follow up, we should add a special
subtree flag so that we can skip over nodes that don't have them. There
are a number of similar subtree flag optimizations that we have planned,
so I'll leave them for a later refactor.)

The only other feature that currently depends on this behavior is
Transition Tracing. I did not add a test for this because Transition
Tracing is still in development and doesn't yet work with Offscreen.
2022-07-29 19:22:57 -04:00
Andrew Clark 2c7dea7365
Implement Offscreen in Fizz (#24988)
During server rendering, a visible Offscreen subtree acts exactly like a
fragment: a pure indirection.

A hidden Offscreen subtree is not server rendered at all. It's ignored
during hydration, too. Prerendering happens only on the client. We
considered prerendering hidden trees on the server, too, but our
conclusion is that it's a waste of bytes and server computation. We
can't think of any compelling cases where it's the right trade off. (If
we ever change our mind, though, the way we'll likely model it is to
treat it as if it's a Suspense boundary with an empty fallback.)
2022-07-26 00:35:51 -04:00
Mengdi Chen 5f34b051df
[Devtools] add logs for profiler tab switch & settings change (#24966)
* [devtools] add logs for profiler tab switch & settings change

* prettier

* remove unnecessary console.log

* better naming: logEvent -> loggerEvent

* use same object for event and metadata
2022-07-25 11:53:38 -04:00
Sebastian Silbermann b66936ece7
devtools: Remove ForwardRef/Memo from display name if `displayName` is set (#21952)
* feat(devtools): Remove ForwardRef/Memo from display name if `displayName` is set

* Avoid potentially wasting work by inlining `functionName`
2022-07-25 09:02:12 +02:00
davidrenne 49f8254d6d
Bug fix for <App /> vs. <Counter /> (#24972) 2022-07-22 11:24:49 -04:00
Sebastian Silbermann 6b28bc9c5a
test: Throw custom error instead of relying on runtime error (#24946) 2022-07-21 15:46:57 -04:00
Sebastian Silbermann 9bd0dd4c18
test(react-debug-tools): Improve coverage of currentDispatcher.current setter (#24945) 2022-07-21 15:46:43 -04:00
Sebastian Silbermann 59bc52a16c
Add 4.5.0 release to eslint rules CHANGELOG (#24853)
Eye-balled from https://app.renovatebot.com/package-diff?name=eslint-plugin-react-hooks&from=4.4.0&to=4.5.0#d2h-042857 which changes were included.
2022-07-21 15:46:10 -04:00
Mengdi Chen 3ddbedd052
[devtools] log more events + metadata (#24951)
* [devtools] log more events + metadata

* better typing

* consistent string type
2022-07-19 15:22:09 -04:00
Andrew Clark cfb6cfa250 Reused components commit with timing as new ones
When an Offscreen tree goes from hidden -> visible, the tree may include
both reused components that were unmounted when the tree was hidden, and
also brand new components that didn't exist in the hidden tree.

Currently when this happens, we commit all the reused components'
effects first, before committing the new ones, using two separate
traversals of the tree.

Instead, we should fire all the effects with the same timing as if it
were a completely new tree. See the test I wrote for an example.

This is also more efficient because we only need to traverse the
tree once.
2022-07-19 14:11:33 -04:00
Andrew Clark 679eea3282 Extract layout effects to separate functions
There's a lot of duplicated code between commitLayoutEffectOnFiber and the
"reappear layout effects" path that happens when an Offscreen tree goes from
hidden back to visible. I'm going to refactor these to share more of the same
code. As a first step, this extracts the shared parts into separate functions.

This may not save much on code size because Closure will likely inline some of
it, anyway, but it makes it harder for the two paths to accidentally diverge.
2022-07-19 14:11:32 -04:00
Andrew Clark 41287d4475 Use recursion to traverse during "reappear layout" phase
This converts the "reappear layout" phase to iterate over its effects
recursively instead of iteratively. This makes it easier to track
contextual information, like whether a fiber is inside a hidden tree.

We already made this change for several other phases, like mutation and
layout mount. See 481dece for more context.
2022-07-19 14:11:32 -04:00
Andrew Clark 697702bf34 Use recursion to traverse during "disappear layout" phase
This converts the "disappear layout" phase to iterate over its effects
recursively instead of iteratively. This makes it easier to track
contextual information, like whether a fiber is inside a hidden tree.

We already made this change for several other phases, like mutation and
layout mount. See 481dece for more context.
2022-07-19 14:11:32 -04:00
Mengdi Chen 992911981b
[DevTools] add simple usage events for internal logging (#24888)
* [DevTools] add simple events for internal logging

* fix lint

* fix lint

* better event name

* fix flow

* better way to fix flow

* combine 'select-element'

* use same event name for selecting element by inspecting
2022-07-18 15:52:53 -04:00
Luna Ruan 6daf600609
add transistion callbacks to hydrateRoot (#24937)
This PR adds transition callbacks to hydrateRoot.
2022-07-18 10:22:47 -07:00
Andrew Clark 02206099af
Use recursion to traverse during passive unmount phase (#24918)
This converts the layout phase to iterate over its effects recursively
instead of iteratively. This makes it easier to track contextual
information, like whether a fiber is inside a hidden tree.

We already made this change for several other phases, like mutation and
layout mount. See 481dece for more context.
2022-07-14 11:08:08 -04:00
Mengdi Chen d54880d424
React DevTools 4.24.7 -> 4.25.0 (#24919) 2022-07-13 15:57:50 -04:00
Luna Ruan f629495199
[Transition Tracing] Rename transitionCallbacks to unstable_transitionCallbacks (#24920)
Renaming transitionCallbacks to unstable_transitionCallbacks as per convention
2022-07-13 15:27:12 -04:00
Mengdi Chen 4bc83e6821
[DevTools] enable `enableProfilerComponentTree` flag for all builds (#24921) 2022-07-13 15:21:32 -04:00