Commit Graph

13863 Commits

Author SHA1 Message Date
Andrew Clark d1845ad0ff Default updates should not interrupt transitions (#20771)
The only difference between default updates and transition updates is
that default updates do not support suspended refreshes — they will
instantly display a fallback.

Co-authored-by: Rick Hanlon <rickhanlonii@gmail.com>
2021-02-10 00:00:24 -08:00
Andrew Clark 3499c343ab Apply #20778 to new fork, too (#20782)
* Apply #20778 to new fork, too

* Fix tests that use runWithPriority

Where possible, I tried to rewrite in terms of an idiomatic API.

For DOM tests, we should be dispatching an event with the desired
priority level.

For Idle updates (very unstable feature), probably need an unstable
API like ReactDOM.unstable_IdleUpdates.

Some of these fixes are not great, but we can replace them once we've
landed the more of our planned changes to the layering between
Scheduler, the reconciler, and the renderer.
2021-02-09 23:21:46 -08:00
Dan Abramov 3d10eca241 Move scheduler priority check into ReactDOM (#20778)
* Move scheduler priority check into ReactDOM

* TODO
2021-02-09 22:54:57 +00:00
Dan Abramov ad8211d96a Add more non-React events to the priority list (#20774)
* Add a test for mouseover being continuous

* Add more non-React events to the priority list
2021-02-09 22:04:23 +00:00
Dan Abramov d919e2c41c Add tests for non-React discrete events flushing in a microtask (#20772)
* Convert some old discrete tests to Hooks

I'm planning to copy paste so why not update them anyway.

* Copy paste discrete tests into another file

These are still using React events. I'll change that next.

* Convert the test to use native events
2021-02-09 19:56:15 +00:00
Dan Abramov 97fce318a6 Experiment: Infer the current event priority from the native event (#20748)
* Add the feature flag

* Add a host config method

* Wire it up to the work loop

* Export constants for third-party renderers

* Document for third-party renderers
2021-02-09 18:32:20 +00:00
Andrew Clark 6c526c5153 Don't shift interleaved updates to separate lane (#20681)
Now that interleaved updates are added to a special queue, we no longer
need to shift them into their own lane. We can add to a lane that's
already in the middle of rendering without risk of tearing.

See #20615 for more background.

I've only changed this in the new fork, and only behind the
enableTransitionEntanglements flag.

Most of this commit involves updating tests. The "shift-to-a-new" lane
trick was intentionally used in a handful of tests where two or more
updates need to be scheduled in different lanes. Most of these tests
were written before `startTransition` existed, and all of them were
written before transitions were assigned arbitrary lanes.

So I ported these tests to use `startTransition` instead, which is the
idiomatic way to mark an update as parallel.

I didn't change the old fork at all. Writing these tests in such a way
that they also pass in the old fork actually revealed a few flaws in the
current implementation regarding interrupting a suspended refresh
transition early, which is a good reminder that we should be writing our
tests using idiomatic patterns as much as we possibly can.
2021-02-09 00:03:07 -08:00
Dan Abramov 35f7441d37 Use Lanes instead of priority event constants (#20762) 2021-02-08 22:30:23 +00:00
Dan Abramov b4658f2daa Reduce some constant duplication (#20761)
* Reduce some constant duplication

* Alphabetize
2021-02-08 22:30:12 +00:00
Andrew Clark a014c915c7 Parallel transitions: Assign different lanes to consecutive transitions (#20672)
* Land enableTransitionEntanglement changes

Leaving the flag though because I plan to reuse it for additional,
similar changes.

* Assign different lanes to consecutive transitions

Currently we always assign the same lane to all transitions. This means
if there are two pending transitions at the same time, neither
transition can finish until both can finish, even if they affect
completely separate parts of the UI.

The new approach is to assign a different lane to each consecutive
transition, by shifting the bit to the right each time. When we reach
the end of the bit range, we cycle back to the first bit. In practice,
this should mean that all transitions get their own dedicated lane,
unless we have more pending transitions than lanes, which should
be rare.

We retain our existing behavior of assigning the same lane to all
transitions within the same event. This is achieved by caching the first
lane assigned to a transition, then re-using that one until the next
React task, by which point the event must have finished. This preserves
the guarantee that all transition updates that result from a single
event will be consistent.
2021-02-08 13:26:48 -08:00
Dan Abramov 77754ae618 Decouple event priority list from event name list (#20760)
* Remove some dead code

* Decouple event priority list from event name list

* Fix lint
2021-02-08 20:48:47 +00:00
Dan Abramov b5bac18219 Align event group constant naming with lane naming (#20744)
* Rename ContinuousEvent to DefaultEvent

* Rename UserBlockingEvent to ContinuousEvent
2021-02-08 17:48:31 +00:00
Andrew Clark bbb2ba8c8d sizebot: Combine stable and experimental results (#20753)
Because we have access to the artifacts in CI, we can read bundle sizes
directly from the filesystem, instead of the JSON files emitted by our
custom Rollup plugin.

This gives us some flexibility if we ever have artifacts that aren't
generated by Rollup, or if we rewrite our build script.

Personally, I also prefer to see the whole file path, instead of just
the name, because some of our names are repeated.

My immediate motivation, though, is because it gives us a way to merge
the separate "experimental" and "stable" size results. Instead
everything is reported in a single table and disambiguated by path.

I also added a section at the top that always displays the size impact
to certain critical bundles — right now, that's the React DOM production
bundles for each release channel. This section will also include any
size changes larger than 2%.

Below that is a section that is collapsed by default and includes all
size changes larger than 0.2%.
2021-02-06 12:57:11 -08:00
Andrew Clark 903384ab0c sizebot: Fix wrong order of base, head arguments (#20751)
The base and head arguments were flipped, so an n% decrease in bundle
size was instead reported as an n% increase.
2021-02-05 15:45:25 -08:00
Dan Abramov 4ecf11977c Remove the Fundamental internals (#20745) 2021-02-05 20:36:55 +00:00
Dan Abramov eeb1325b03 Fix UMD bundles by removing usage of global (#20743) 2021-02-05 17:13:42 +00:00
Andrew Clark 4e08fb10c9 Update release documentation (#20736)
Added information about automated prereleases
2021-02-04 13:20:49 -08:00
Ricky b12d0078a4 Fix codesandbox build command (#20731) 2021-02-04 11:24:07 -05:00
Andrew Clark a703c3f7e8 Fix cron syntax
Let's try this again?
2021-02-04 10:07:39 -06:00
Andrew Clark 365080f4f5 Autopublish prereleases using head of main branch
Instead of using pipeline parameter. Fixes copypasta from the other
workflow, which accepts the SHA parameter via an API call.
2021-02-04 09:34:12 -06:00
Andrew Clark f58ad2ad8e Auto-publish prereleases every weekday (#20733)
Sets up a cron trigger to publish prereleases at 16:00 UTC (11 am
Eastern, 8 am Pacific) on every weekday (Monday through Friday).
2021-02-03 21:08:34 -08:00
Andrew Clark c64d6d21be Implement CI job that publishes prereleases (#20732)
PR #20728 added a command to initiate a prerelease using CI, but it left
the publish job unimplemented. This fills in the publish job.

Uses an npm automation token for authorization, which bypasses the need
for a one-time password. The token is configured via CircleCI's
environment variable panel.

Currently, it will always publish the head of the main branch. If the
head has already been published, it will exit gracefully.

It does not yet support publishing arbitrary commits, though we could
easily add that. I don't know how important that use case is, because
for PR branches, you can use CodeSandbox CI instead. Or as a last
resort, run the publish script locally.

Always publishing from main is nice because it further incentivizes us
to keep main in a releasable state. It also takes the guesswork out of
publishing a prerelease that's in a broken state: as long as we don't
merge broken PRs, we're fine.
2021-02-03 20:57:31 -08:00
Andrew Clark 4c019585e8 Empty commit to replace "broken" head of main
Head commit had a "broken" (but not really) CircleCI job and CircleCI
doesn't give me a way to clear/restart it. So I'm doing this.
2021-02-03 20:33:27 -06:00
Ricky 3b02ae5cc6 Add silent to codesandbox config (#20730) 2021-02-03 18:53:07 -05:00
Andrew Clark c1cfa734fd Add command to publish preleases via CI (#20728)
```
yarn publish-prereleases
```

Script to trigger a CircleCI workflow that publishes preleases.

**The CI workflow doesn't actually publish yet; it just runs and logs
its inputs.**
2021-02-03 15:42:34 -08:00
Andrew Clark 00e38c80b2 Fallback if GitHub status is stuck as "pending" (#20729)
GitHub's status API is super flaky. Sometimes it reports a job as
"pending" even after it completes in CircleCI. If it's still pending
when we time out, return the build ID anyway. TODO: The location of the
retry loop is a bit weird. We should probably combine this function with
the one that downloads the artifacts, and wrap the retry loop around the
whole thing.
2021-02-03 15:33:46 -08:00
Andrew Clark 3be750eee9 Add --ci option to publish script (#20727)
When running in CI, the publish script will skip interactive prompts,
including the prompt for a one-time password.

Instead, CI will need to use an automation access token:
https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow
2021-02-03 12:17:40 -08:00
Andrew Clark 85f489a129 Add publish workflow, triggerable via API request (#20726)
Adds a new CircleCI workflow, which I will use to publish prereleases
(`next` and `experimental`) for a given commit.

The CircleCI API doesn't yet support triggering a specific workflow, but
it does support triggering a pipeline. So as a workaround you can
triggger the entire pipeline and use parameters to disable everything
except the workflow you want. CircleCI recommends this workaround here:
https://support.circleci.com/hc/en-us/articles/360050351292-How-to-trigger-a-workflow-via-CircleCI-API-v2-

Eventually we can set this workflow to trigger on a cron schedule (once
per week, for example).
2021-02-03 12:17:29 -08:00
Andrew Clark 0935a1db3d Delete consolidateBundleSizes script (#20724)
This was ported to the new workflow by #20720
2021-02-03 08:45:29 -08:00
Andrew Clark b936ab660a Update sizebot to new workflow (#20719)
* build-combined: Fix bundle sizes path

* Output COMMIT_SHA in build directory

Alternative to parsing an arbitrary package's version number, or
its `build-info.json`.

* Remove CircleCI environment variable requirement

I think this only reason we needed this was to support passing any
job id to `--build`, instead of requiring the `process_artifacts` job.
And to do that you needed to use the workflows API endpoint, which
requires an API token.

But now that the `--commit` argument exists and automatically finds the
correct job id, we can just use that.

* Add CI job that gets base artifacts

Uses download-experimental script and places the base artifacts into
a top-level folder.

* Migrate sizebot to combined workflow

Replaces the two separate sizebot jobs (one for each channel, stable and
experimental) with a single combined job that outputs size information
for all bundles in a single GitHub comment.

I didn't attempt to simplify the output at all, but we should. I think
what I would do is remove our custom Rollup sizes plugin, and read the
sizes from the filesystem instead. We would lose some information about
the build configuration used to generate each artifact, but that can be
inferred from the filepath. For example, the filepath
`fb-www/ReactDOM-dev.classic.js` already tells us everything we need to
know about the artifact. Leaving this for a follow up.

* Move GitHub status check inside retry loop

The download script will poll the CircleCI endpoint until the build job
is complete; it should also poll the GitHub status endpoint if the
build job hasn't been spawned yet.

* Only run get_base_build on main branch
2021-02-03 08:29:51 -08:00
Brian Vaughn 2d025753e2 Remove --build flag from release scripts (#20723)
Also update instructions to match recent script changes.

Also add reproducible commit SHA to post download instructions to support publishing the Firefox DevTools extension.
2021-02-03 11:11:56 -05:00
Andrew Clark 0e526bcec2 Fix release script --commit param (#20720)
PR #20717 accidentally broke the `--commit` parameter because the
script errors if you provide both a `--build` and a `--commit`.

I solved by removing the validation error. When there's a conflict, it
will choose the --`build`.

(Although maybe we should `--build` entirely and always uses `--commit`.
I think `--commit` is a sufficient replacement.)
2021-02-02 19:30:37 -08:00
Andrew Clark 7e36d8beba Some release script fixes (#20718)
* Retry loop should not start over from beginning

When the otp times out, we should not retry the packages that were
already successfully published. We should pick up where we left off.

* Don't crash if build-info.json doesn't exist

The "print follow up instructions" step crashes if build-info.json is
not found. The new build workflow doesn't include those yet (might not
need to) and since the instructions that depend on it only affect
semver (latest) releases, I've moved the code to that branch. Will
follow up with a proper fix, either by adding back a build-info.json
file or removing that dependency and reading the commit some other way.
2021-02-02 14:48:02 -08:00
Brian Vaughn c47f3cfa17 Restore experimental build script's ability to auto download latest build (#20717) 2021-02-02 16:40:31 -05:00
Brian Vaughn 3e0bdbefa3 DevTools: Patch console methods even when only show-inline-warnings/errors enabled (#20688) 2021-02-02 10:19:53 -05:00
Andrew Clark 7cb9fd7ef8 Land interleaved updates change in main fork (#20710)
* Land #20615 in main fork

Includes change to interleaved updates.

```
yarn replace-fork
```

* Check deferRenderPhaseUpdateToNextBatch in test
2021-02-01 16:05:42 -08:00
Andrew Clark dc27b5aaae useMutableSource: Use StrictMode double render to detect render phase mutation (#20698)
* Concurrent Mode test for uMS render mutation

Same test as the one added in #20665, but for Concurrent Mode.

* Use double render to detect render phase mutation

PR #20665 added a mechanism to detect when a `useMutableSource` source
is mutated during the render phase. It relies on the fact that we double
invoke components that error during development using
`invokeGuardedCallback`. If the version in the double render doesn't
match the first, that indicates there must have been a mutation during
render.

At first I thought it worked by detecting inside the *other* double
render, the one we do for Strict Mode. It turns out that while it does
warn then, the warning is suppressed, because we suppress all console
methods that occur during the Strict Mode double render. So it's really
the `invokeGuardedCallback` one that makes it work.

Anyway, let's set that aside that issue for a second. I realized during
review that errors that occur during the Strict Mode double render
reveal a useful property: A pure component will never throw during the
double render, because if it were pure, it would have also thrown during
the first render... in which case it wouldn't have double rendered! This
is true of all such errors, not just the one thrown by
`useMutableSource`.

Given this, we can simplify the `useMutableSource` mutation detection
mechanism. Instead of tracking and comparing the source's version, we
can instead check if we're inside a double render when the error is
thrown.

To get around the console suppression issue, I changed the warning to an
error. It errors regardless, in both dev and prod, so it doesn't have
semantic implications.

However, because of the paradox I described above, we arguably
_shouldn't_ throw an error in development, since we know that error
won't happen in production, because prod doesn't double render. (It's
still a tearing bug, but that doesn't mean the component will actually
throw.) I considered that, but that requires a larger conversation about
how to handle errors that we know are only possible in development. I
think we should probably be suppressing *all* errors (with a warning)
that occur during a double render.
2021-02-01 12:11:51 -08:00
Andrew Clark f8545f6eb8 Add automatic retry to download script (#20704)
If build job is still pending, the script will continously poll until
it reaches the retry limit.

I've set the limit at 10 minutes, since our CI pipeline almost always
finishes before that.
2021-02-01 08:30:50 -08:00
Andrew Clark f8b6969da6 Add --commit param to release scripts (#20703)
Alternative to `--build`. Uses same logic as sizebot and www
sync script.

Immediate motivation is I want sizebot to use the
`download-experimental-build` command in CI. Will do that next.
2021-02-01 08:27:59 -08:00
Sebastian Silbermann bb1b7951d1 fix: don't run effects if a render phase update results in unchanged deps (#20676)
The memoized state of effect hooks is only invalidated when deps change. Deps are compared between the previous effect and the current effect. This can be problematic if one commit consists of an update that has changed deps followed by an update that has equal deps. That commit will lead to memoizedState containing the changed deps even though we committed with unchanged deps.

The n+1 update will therefore run an effect because we compare the updated deps with the deps with which we never actually committed.

To prevent this we now invalidate memoizedState on every updateEffectImpl call so that memoizedStat.deps always points to the latest deps.
2021-01-29 10:51:11 -05:00
Brian Vaughn 766a7a28a9 Improve React error message when mutable sources are mutated during render (#20665)
Changed previous error message from:
> Cannot read from mutable source during the current render without tearing. This is a bug in React. Please file an issue.

To:
> Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.

Also added a DEV only warning about the unsafe side effect:
> A mutable source was mutated while the %s component was rendering. This is not supported. Move any mutations into event handlers or effects.

I think this is the best we can do without adding production overhead that we'd probably prefer to avoid.
2021-01-29 10:22:55 -05:00
Andrew Clark a922f1c710 Fix cache refresh bug that broke DevTools (#20687)
Will follow up with test
2021-01-28 13:07:00 -08:00
Ricky e51bd6c1fa Queue discrete events in microtask (#20669)
* Queue discrete events in microtask

* Use callback priority to determine cancellation

* Add queueMicrotask to react-reconciler README

* Fix invatiant conditon for InputDiscrete

* Switch invariant null check

* Convert invariant to warning

* Remove warning from codes.json
2021-01-27 18:24:58 -05:00
Ricky aa736a0fa6 Add queue microtask to host configs (#20668)
* Queue discrete events in microtask

* Fix flow types

* Add to createReactNoop

* More flow types

* Remove import

* Add to custom HostConfig as well
2021-01-27 15:01:21 -05:00
Andrew Clark deeeaf1d22 Entangle overlapping transitions per queue (#20670)
When multiple transitions update the same queue, only the most recent
one should be allowed to finish. We shouldn't show intermediate states.

See #17418 for background on why this is important.

The way this currently works is that we always assign the same lane to
all transitions. It's impossible for one transition to finish without
also finishing all the others.

The downside of the current approach is that it's too aggressive. Not
all transitions are related to each other, so one should not block
the other.

The new approach is to only entangle transitions if they update one or
more of the same state hooks (or class components), because this
indicates that they are related. If they are unrelated, then they can
finish in any order, as long as they have different lanes.

However, this commit does not change anything about how the lanes are
assigned. All it does is add the mechanism to entangle per queue. So it
doesn't actually change any behavior, yet. But it's a requirement for my
next step, which is to assign different lanes to consecutive transitions
until we run out and cycle back to the beginning.
2021-01-27 11:55:27 -08:00
Joshua Gross e316f78552 RN: Implement sendAccessibilityEvent in RN Renderer that proxies between Fabric/non-Fabric (#20554)
* RN: Implement `sendAccessibilityEvent` on HostComponent

Implement `sendAccessibilityEvent` on HostComponent for Fabric and non-Fabric RN.

Currently the Fabric version is a noop and non-Fabric uses
AccessibilityInfo directly. The Fabric version will be updated once
native Fabric Android/iOS support this method in the native UIManager.

* Move methods out of HostComponent

* Properly type dispatchCommand and sendAccessibilityEvent handle arg

* Implement Fabric side of sendAccessibilityEvent

* Add tests: 1. Fabric->Fabric, 2. Paper->Fabric, 3. Fabric->Paper, 4. Paper->Paper

* Fix typo: ReactFaricEventTouch -> ReactFabricEventTouch

* fix flow types

* prettier
2021-01-26 20:02:40 -08:00
Ricky 9c32622cf0 Improve tests that use discrete events (#20667) 2021-01-26 19:15:06 -05:00
Andrew Clark d13f5b9538 Experiment: Unsuspend all lanes on update (#20660)
Adds a feature flag to tweak the internal heuristic used to "unsuspend"
lanes when a new update comes in.

A lane is "suspended" if we couldn't finish rendering it because it was
missing data, and we chose not to commit the fallback. (In this context,
"suspended" does not include updates that finished with a fallback.)

When we receive new data in the form of an update, we need to retry
rendering the suspended lanes, since the new data may have unblocked the
previously suspended work. For example, the new update could navigate
back to an already loaded route.

It's impractical to retry every combination of suspended lanes, so we
need some heuristic that decides which lanes to retry and in
which order.

The existing heuristic roughly approximates the old Expiration Times
model. It unsuspends all lower priority lanes, but leaves higher
priority lanes suspended.

Then when we start rendering, we choose the lanes that have the highest
LanePriority and render those -- and then we add to that all the lanes
that are highher priority.

If this sounds terribly confusing, it's because it barely makes sense.
(It made more sense in the Expiration Times world, I promise, but it
was still confusing.) I don't think it's worth me trying to explain the
old behavior too much because the point here is that we can replace it
with something simpler.

The new heurstic is to unsuspend all suspended lanes whenever there's
an update.

This is effectively what we already do except in a few very specific
edge cases, ever since we removed the delayed suspense feature from
everything that's not a refresh transition.

We can optimize this in the future to only unsuspend lanes that are
either 1) in the `lanes` or `subtreeLanes` of the node that was updated,
or 2) in the `lanes` of the return path of the node that was updated.
This would exclude lanes that are only located in unrelated sibling
trees. But, this optimization wouldn't be useful currently because we
assign the same transition lane to all transitions. It will become
relevant again once we start assigning arbitrary lanes to transitions
-- but that in turn requires us to implement entanglement of overlapping
transitions, one of our planned projects.

So to sum up: the goal here is to remove the weird edge cases and switch
to a simpler model, on top of which we can make more substantial
improvements.

I put it behind a flag so I can run an A/B test and confirm it doesn't
cause a regression.
2021-01-26 12:23:34 -08:00
Brian Vaughn db5945efee Set default release channel for download-experimental-build script (#20663) 2021-01-26 15:17:56 -05:00
Sebastian Markbåge a511dc7090 Error for deferred value and transition in Server Components (#20657) 2021-01-25 13:58:47 -08:00