Commit Graph
19463 Commits
Author SHA1 Message Date
Brian Vaughn 5634ed16aa Scheduling Profiler: Misc UX and performance improvements (#22043) 2021-08-09 17:11:33 -04:00
Brian Vaughn ecd73e17bc Enable enableSuspenseLayoutEffectSemantics flag statically for Facebook (#22050) 2021-08-09 15:45:12 -04:00
Konstantin Popov 64931821a9 Fix typo in parseHookNames.js (#22042)
representated -> represented
2021-08-08 15:58:50 -04:00
Brian Vaughn 2edf449803 Scheduling Profiler: Renamed a misnamed variable 2021-08-06 15:03:35 -04:00
Brian Vaughn 5660c52b89 Scheduling Profiler: Improve warnings and add unit tests (#22038)
* Scheduling Profiler: Updated instructions to mentioned v18+ requirement

* Moved long-event warning to post processing

This lets us rule out non-React work or React work that started before the event and finished quickly during the event.

Also added unit tests for this warning and the various cases.

* Moved long-event warning to post processing

This lets us rule out non-React work or React work that started before the event and finished quickly during the event.

Also added unit tests for this warning and the various cases.

* Updated nested update warning text

* Udpate warning about suspending outside of a transition

Handle edge case where component suspends before the first commit (and label metadata) has been logged.

Add unit tests.

* Fixed logic error in getBatchRange() with minStartTime

* PR feedback: Combined a conditional statement
2021-08-06 14:57:52 -04:00
Juan b9934d6db5 [DevTools] Hook names are correctly extracted when parsing nested hook calls (#22037)
## Summary

This commit fixes an issue where DevTools would currently not correctly extract the hook names for a hook call when the hook call was nested under *another* hook call, e.g.:

```javascript
function Component() {
  const InnerComponent = useMemo(() => () => {
    const [state, setState] = useState(0);

    return state;
  }); 
  return null;
};
```

Although it seems pretty rare to encounter this case in actual product code, DevTools wasn't handling it correctly:

**Expected Names:**
- `InnerComponent` for the `useMemo()` call.
- `state` for the `useState()` call.

**Actual**
- `InnerComponent` for the `useMemo()` call.
- `InnerComponent` for the `useState()` call.

The reason that we were extracting the name for the nested hook call incorrectly is that the `checkNodeLocation` function (which attempts to check if the location of the hook matches the location in the original source code), was too "lenient" and would return a match even if the start lines of the locations didn't match.

Specifically, for our example, it would consider that the location of the outer hook call "matched" the location of the inner hook call (even though they were on different lines), and would then return the wrong hook name.


### Fix

The fix in this commit is to update the `checkNodeLocation` function to more strictly check for matching start lines. The assumption here is that if 2 locations are on different starting lines, they can't possibly correspond to the same hook call.

## Test Plan

- yarn flow
- Tests still pass
  - yarn test
  - yarn test-build-devtools
- new regression tests added
- named hooks still work on manual test of browser extension on a few different apps (code sandbox, create-react-app, internally). 
![image](https://user-images.githubusercontent.com/1271509/128409571-d62e0a74-6b7b-4c3f-ad86-6799ecd71962.png)

![image](https://user-images.githubusercontent.com/1271509/128409943-f898f27b-67ab-4260-a931-40d9c1942395.png)

![image](https://user-images.githubusercontent.com/1271509/128410326-79a0f822-55b1-4b90-a9b9-78f13fa0b5c5.png)
2021-08-05 16:36:59 -04:00
Brian Vaughn a8725a3e62 Scheduling profiler: Added lane labels and durations to React measures (#22029) 2021-08-05 13:50:39 -04:00
Andrew Clark 19092ac8c3 Re-add old Fabric Offscreen impl behind flag (#22018)
* Re-add old Fabric Offscreen impl behind flag

There's a chance that #21960 will affect layout in a way that we don't
expect, so I'm adding back the old implementation so we can toggle the
feature with a flag.

The flag should read from the ReactNativeFeatureFlags shim so that we
can change it at runtime. I'll do that separately.

* Import dynamic RN flags from external module

Internal feature flags that we wish to control with a GK can now be
imported from an external module, which I've called
"ReactNativeInternalFeatureFlags".

We'll need to add this module to the downstream repo.

We can't yet use this in our tests, because we don't have a test
configuration that runs against the React Native feature flags fork. We
should set up that up the same way we did for www.
2021-08-03 19:30:20 -07:00
Andrew Clark 215db465a2 [Fabric] Add flex: 1 to Offscreen view container (#22019)
Without this style property, the layout of the children is messed up.

The goal is for the container view to have no layout at all. It should
be a completely transparent wrapper, except for when we set `display:
none` to hide its contents. On the web, the equivalent (at least in the
spec) is `display: contents`.

After some initial testing, this seems to be close enough to the desired
behavior that we can ship it. We'll try rolling it out behind a flag.
2021-08-03 19:26:49 -07:00
Sinan Sonmez (Chaush) 8a37b0ef3f typos fixed (#21955) 2021-08-03 14:05:20 -04:00
Brian Vaughn e3049bb850 DevTools scheduling profiler: Add React component measures (#22013) 2021-08-03 13:03:29 -04:00
Vyacheslav 'SLEL' Solomin b54f36f2b6 [DevTools] Fix: highlight updates with memoized components (#22008) 2021-08-03 11:50:00 -04:00
Kevin Chavez 3a1dc3ec85 Switch on enableProfilerChangedHookIndices flag for OSS devtools builds (#22011) 2021-08-03 08:55:15 -04:00
Brian Vaughn 42251331d8 DevTools: Scheduling profiler (#22006) 2021-08-02 14:30:43 -04:00
houssemchebebandBrian Vaughn e3b76a85c5 Devtools: Refactor imperative theme code (#21950)
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
2021-08-02 11:20:04 -04:00
Ryota Murakami d3f8747c8d [DevTools] Disable sizeBot on DevTools Rull Request (#21885)
* [DevTools] Disable sizeBot on DevTools Rull Request

Because DevTools code doesn't affect production bundle size.
Meaningless sizeBot comment give us frastration within Pull Request discussion.

* Revert "[DevTools] Disable sizeBot on DevTools Rull Request"

This reverts commit a43aab9207.

* check whether devtools package file only committed
2021-08-02 09:51:53 -04:00
Brian Vaughn d1a58da55d Optimized DevTools extension images 2021-08-02 09:32:46 -04:00
Ilham Syahid S dfd9d62636 [DevTools] Optimize Images yarn command (part 2) (#21968) 2021-08-02 09:32:17 -04:00
Brian Vaughn 27bf6f9a83 Scheduling profiler UX changes (#21990) 2021-08-02 09:23:48 -04:00
Juan b537247678 New devtools test for named hooks verifying case when hooks are used indirectly (#21996)
## Summary
Adds a new unit test to `parseHookNames-test` which verifies that we correctly give names to hooks when they are used indirectly: 

e.g.
```
  const countState = useState(0);
  const count = countState[0];
  const setCount = countState[1];
``` 

Should produce `count` as the name.

## Test plan

```
yarn test
yarn test-build-devtools
yarn test-build-devtools parseHookNames
```
2021-07-30 17:10:46 -04:00
Andrew Clark f0d354efc6 [Fabric] Fix reparenting bug in legacy Suspense mount (#21995)
* Add reparenting invariant to React Noop

Fabric does not allow nodes to be reparented, so I added the equivalent
invariant to React Noop's so we can catch regressions.

This causes some tests to fail, which I'll fix in the next step.

* Fix: Use getOffscreenContainerProps

The type of these props is different per renderer. An oversight
from #21960. Unfortunately wasn't caught by Flow because fiber props
are `any`-typed.

* [Fabric] Fix reparenting in legacy Suspense mount

Fixes a weird case during legacy Suspense mount where the offscreen host
container of a tree that suspends during initial mount is recreated
instead of cloned, since there's no current fiber to clone from.

Fabric considers this a reparent even though the parent from the first
pass never committed.

Instead we can override the props from the first pass before the
container completes. It's a bit of a hack, but no more so than the rest
of the legacy root Suspense implementation — the hacks are designed
to make it usable by non-strict mode-compliant trees.
2021-07-30 12:47:40 -07:00
Shubham PandeyandShubham Pandey 6f3fcbd6fa Some remaining instances of master to main (#21982)
Co-authored-by: Shubham Pandey <shubham.pandey@mfine.co>
2021-07-30 08:56:55 -04:00
Andrew Clark 34308b5ada Tidy up early bailout logic at start of begin phase (#21852)
* Extract early bailout to separate function

This block is getting hard to read so I moved it to a separate function.
I'm about to refactor the logic that wraps around this path.

Ideally this early bailout path would happen before the begin phase
phase. Perhaps during reconcilation of the parent fiber's children.

* Extract state and context check to separate function

The only reason we pass `updateLanes` to some begin functions is to
check if we can perform an early bail out. But this is also available
as `current.lanes`, so we can read it from there instead.

I think the only reason we didn't do it this way originally is because
components that have two phases — error and Suspense boundaries —
use `workInProgress.lanes` to prevent a bail out, since during the
initial render there is no `current`. But we can check the `DidCapture`
flag instead, which we use elsewhere to detect the second phase.
2021-07-29 06:59:59 -07:00
Brian Vaughn d9dd96530f Added testing instructions to devtools contributing guide 2021-07-28 19:05:01 -04:00
Piotr Szulc 9f88b5355b Devtools: Display as link if value is in specified protocols (#21964) 2021-07-28 09:29:13 -04:00
Sebastian Markbåge 321087d134 [Fizz] Don't add aborted segments to the completedSegments list (#21976)
* Don't add aborted segments to the completedSegments list

* Update error message to include aborted status
2021-07-27 21:53:37 -04:00
Brian Vaughn cdccdbe171 Display warnings in tooltips for native events that render sync updates (#21975) 2021-07-27 17:22:44 -04:00
Brian Vaughn d95434082f Scheduling profiler: UX tweaks (#21971) 2021-07-27 14:34:05 -04:00
Brian Vaughn 87239321b0 Sceduling profiler: Added custom view cursors (#21970) 2021-07-27 12:23:01 -04:00
Timothy Yung 4cc8ec64c2 Separate unit tests for ReactFabricHostComponent (#21969) 2021-07-26 23:45:26 -07:00
Timothy Yung d4d7864934 Fix ReactFabricHostComponent methods if detached (#21967) 2021-07-26 21:02:06 -07:00
Brian Vaughn c21e8fccad Scheduling profiler: Improve native events UI (#21966)
Also highlight events that have synchronous updates inside of them. (We may want to relax this highlighting later to not warn about event handlers that are still fast enough.)
2021-07-26 19:30:43 -04:00
Andrew Clark 392253a774 [Fabric] Use container node to toggle the visibility of Offscreen and Suspense trees (#21960)
* Fix type of Offscreen props argument

Fixes an oversight from a previous refactor. The fiber that wraps
a Suspense component's children used to be a Fragment but now it's on
Offscreen fiber, so its props type has changed. There's a special
hydration path where I forgot to update this. This isn't observable
because we don't ever end up rendering this particular fiber (because
the Suspense boundary is in its fallback state) but we should fix it
anyway to avoid a potential regression in the future.

* Extract createOffscreenFromFiber logic

...into a new method called `createWorkInProgressOffscreenFiber`. Just
for symmetry with `updateWorkInProgressOffscreenFiber`. Doesn't change
any behavior.

* [Fabric] Use container node to hide/show tree

This changes how we hide and show the contents of Offscreen boundaries
in the React Fabric renderer (persistent mode), and also Suspense
boundaries which use the same feature.=

The way it used to work was that when a boundary is hidden, in the
complete phase, instead of calling the normal `cloneInstance` method
inside `appendAllChildren`, we would call a forked method called
`cloneHiddenInstance` for each of the nearest host nodes within the
subtree. This design was largely based on how it works in React DOM
(mutation mode), where instead of cloning the nearest host nodes, we
mutate their `style.display` property.

The motivation for doing it this way in React DOM was because there's no
built-in browser API for hiding a collection of DOM nodes without
affecting their layout.

In Fabric, however, there is no such limitation, so we can instead wrap
in an extra host node and apply a hidden style.

The immediate motivation for this change is that Fabric on Android has a
view pooling mechanism for instances that relies on the assumption that
a current Fiber that is cloned and replaced by a new Fiber will never
appear in a future commit. When this assumption is broken, it may cause
crashes. In the current implementation, that can indeed happen when a
node that was previously hidden is toggled back to visible. Although
this change sidesteps the issue, we may introduce in other features in
the future that would benefit from being able to revert back to an older
node without cloning it again, such as animations.

The way I've implemented this is to insert an additional HostComponent
fiber as the child of each OffscreenComponent. The extra fiber is not
ideal — the way I'd prefer to do it is to attach the host instance to
the OffscreenComponent. However, the native Fabric implementation
currently expects a 1:1 correspondence between HostComponents and host
instances, so I've deferred that optimization to a future PR to derisk
fixing the Fabric pooling crash. I left a TODO in the host config with a
description of the remaining steps, but this alone should be sufficient
to unblock.
2021-07-26 13:17:08 -07:00
Andrew Clark 419cc9c379 Fix: Hide new/updated nodes in already hidden tree (#21929)
When a new node is added to an already hidden Offscreen tree, we need
to schedule a visibility effect to hide it. Previously we would only
hide when the boundary initially switches from visible to hidden, which
meant that newly inserted nodes would be visible.

We need to do the same thing for nodes that are updated, because the
update might affect the DOM node's `style.display` property.

The implementation is to check the `subtreeFlags` for an Insertion or
Update effect.

This only affects Offscreen, not Suspense, because Suspense boundaries
cannot be updated while in their fallback (hidden) state.

And it only affects mutation mode, because in persistent mode we
implement hiding by cloning the host tree during the complete phase,
which already happens on every update.
2021-07-26 08:18:55 -07:00
Brian Vaughn b1811ebf01 [DevTools] Add native events to the scheduling profiler (#21947) 2021-07-26 10:36:16 -04:00
Brian Vaughn 4758e4533e React Native: Export getInspectorDataForInstance API (#21572)
This PR exports a new top-level API, getInspectorDataForInstance, for React Native (both development and production). Although this change adds a new export to the DEV bundle, it only impacts the production bundle for internal builds (not what's published to NPM).
2021-07-26 09:56:59 -04:00
Brian Vaughn c76e4dbbc1 Removed an accidental console.log from DevTools source code 2021-07-22 16:11:37 -04:00
Brian Vaughn f4161c3ec7 [DRAFT] Import scheduling profiler into DevTools Profiler (#21897) 2021-07-22 13:58:57 -04:00
Andrew Clark ae5d26154b Fix: LegacyHidden should not toggle effects (#21928)
LegacyHidden is a transitional API that we added to replace the old
`<div hidden={true} />` API that we used to use for pre-rendering. The
plan is to replace this with the Offscreen component, once it's ready.

The idea is that LegacyHidden has identical behavior to Offscreen except
that it doesn't change the behavior of effects. (Which is basically how
`<div hidden={true} />` worked — it prerendered the hidden content in
the background, but nothing else.) That way, while we're rolling this
out, we could toggle the feature behind a feature flag either for
performance testing or as a kill switch.

It looks like we accidentally enabled the effects flag for both
Offscreen _and_ LegacyHidden. I suppose it's a good thing that nobody
has complained yet, since we eventually do want to ship this
behavior everywhere?

But I do think we should remove it from LegacyHidden, and roll it out by
gating the component type in the downstream repo. That way if there's an
issue related to the use of LegacyHidden, we can disable that without
disabling the behavior for Suspense boundaries.

In retrospect, I might have implemented this as an unstable prop on
Offscreen instead of a completely separate type — though at the time,
Offscreen didn't exist. I originally added LegacyHidden to unblock the
Lanes refactor, so I could move the deprioritization logic out of the
HostComponent implementation.

Not a big deal since we're going to remove this soon. The implementation
is almost the same regardless: before disconnecting or reconnecting
the effects, check the fiber tag. The rest of the logic is the same.
2021-07-21 10:34:08 -07:00
Lucas Correia 25f09e3e4e DevTools: Parse named source AST in a worker (#21902)
Resolves #21855

Ended up using workerize in order to setup the worker once it allows easy imports (for babel's parse function) and exports.
2021-07-21 12:16:08 -04:00
Andrew Clark 9ab90de602 Clean-up: Move Offscreen logic from Suspense fiber (#21925)
Much of the visibility-toggling logic is shared between the Suspense and
Offscreen types, but there is some duplicated code that exists in both.
Specifically, when a Suspense fiber's state switches from suspended to
resolved, we schedule an effect on the parent Suspense fiber, rather
than the inner Offscreen fiber. Then in the commit phase, the Suspense
fiber is responsible for committing the visibility effect on Offscreen.

There two main reasons we implemented it this way, neither of which
apply any more:

- The inner Offscreen fiber that wraps around the Suspense children used
  to be conditionally added only when the boundary was in its fallback
  state. So when toggling back to visible, there was no inner fiber to
  handle the visibility effect. This is no longer the case — the
  primary children are always wrapped in an Offscreen fiber.
- When the Suspense fiber is in its fallback state, the inner Offscreen
  fiber does not have a complete phase, because we bail out of
  rendering that tree. In the old effects list implementation, that
  meant the Offscreen fiber did not get added to the effect list, so
  it didn't have a commit phase. In the new recursive effects
  implementation, there's no list to maintain. Marking a flag on the
  inner fiber is sufficient to schedule a commit effect.

Given that these are no relevant, I was able to remove a lot of old
code and shift more of the logic out of the Suspense implementation
and into the Offscreen implementation so that it is shared by both.
(Being able to share the implementaiton like this was in fact one of
the reasons we stopped conditionally removing the inner
Offscreen fiber.)

As a bonus, this happens to fix a TODO in the Offscreen implementation
for persistent (Fabric) mode, where newly inserted nodes inside an
already hidden tree must also be hidden. Though we'll still need to
make this work in mutation (DOM) mode, too.
2021-07-20 16:05:16 -07:00
Andrew Clark 5c6543771b Fix global reference to Promise (#21926)
Referencing Promise without a type check will throw in environments
where Promise is not defined.

We will follow up with a lint rule that restricts access to all globals
except in dedicated module indirections.
2021-07-20 15:39:57 -07:00
Deniz Susman 3f62dec84a Typo fix (#21729)
emitted instead of emmitted
2021-07-19 17:19:52 -04:00
Ricky 5579f1dc87 Update test comments with explanations (#21857) 2021-07-19 15:07:38 -04:00
Christian Schulze 9b76d2d7b3 react-devtools: set icon on macos (#21908) 2021-07-19 10:26:41 -04:00
Andrew Clark 262ff7ad2c Refactor "disappear" logic into its own traversal (#21901)
Similar to #21898, but for "disappear" logic. Previously this lived
inside `hideOrUnhideAllChildren`, the function that mutates the nearest
DOM nodes to override their `display` style.

This makes the feature work in persistent mode (Fabric); it didn't
before because `hideOrUnhideAllChildren` only runs in mutation mode.
2021-07-16 15:58:11 -07:00
Andrew Clark 34600f4fad Refactor "reappear" logic into its own traversal (#21898)
When a Suspense boundary switches to its fallback state — or similarly,
when an Offscreen boundary switches from visible to hidden — we unmount
all its layout effects. When it resolves — or when Offscreen switches
back to visible — we mount them again. This "reappearing" logic
currently happens in the same commit phase traversal where we perform
normal layout effects.

I've changed it so that the "reappear" logic happens in its own
recurisve traversal that is separate from the commit phase one.

In the next step, I will do the same for the "disappear" logic that
currently lives in the `hideOrUnhideAllChildren` function.

There are a few reasons to model it this way, related to future
Offscreen features that we have planned. For example, we intend to
provide an imperative API to "appear" and "reappear" all the effects
within an Offscreen boundary. This API would be called from outside the
commit phase, during an arbitrary event. Which means it can't rely on
the regular commit phase — it's not part of a commit. This isn't the
only motivation but it illustrates why the separation makes sense.
2021-07-16 15:05:39 -07:00
Ricky 310187264d Clean up flushSync flow types (#21887) 2021-07-16 10:37:57 -04:00
Brian Vaughn d0ec283819 DevTools 4.13.5 -> 4.14.0 2021-07-16 00:25:01 -04:00
Brian Vaughn 6840c98c32 Remove named hooks feature flag (#21894) 2021-07-16 00:14:20 -04:00