This replaces the HTML renderer with instead resolving host elements into
arrays tagged with the react.element symbol. These turn into proper
React Elements on the client.
The symbol is encoded as the magical value "$". This has security implications
so this special value needs to remain escaped for other strings.
We could just encode the element as {$$typeof: "$", key: key props: props}
but that's a lot more bytes. So instead I encode it as:
["$", key, props] and then convert it back.
It would be nicer if React's reconciler could just accept these tuples.
* Add ReactFlightServerConfig intermediate
This just forwards to the stream version of Flight which is itself forked
between Node and W3C streams.
The dom-relay goes directly to the Relay config though which allows it to
avoid the stream part of Flight.
* Separate streaming protocol into the Stream config
* Split streaming parts into the ReactFlightServerConfigStream
This decouples it so that the Relay implementation doesn't have to encode
the JSON to strings. Instead it can be fed the values as JSON objects and
do its own encoding.
* Split FlightClient into a basic part and a stream part
Same split as the server.
* Expose lower level async hooks to Relay
This requires an external helper file that we'll wire up internally.
* Rename to clarify that it's client-only
* Rename FizzStreamer to FizzServer for consistency
* Rename react-flight to react-client/flight
For consistency with react-server. Currently this just includes flight
but it could be expanded to include the whole reconciler.
* Add Relay Flight Build
* Rename ReactServerHostConfig to ReactServerStreamConfig
This will be the config specifically for streaming purposes.
There will be other configs for other purposes.
* Require deep for reconcilers
* Delete inline* files
* Delete react-reconciler/persistent
This no longer makes any sense because it react-reconciler takes
supportsMutation or supportsPersistence as options. It's no longer based
on feature flags.
* Fix jest mocking
* Fix Flow strategy
We now explicitly list which paths we want to be checked by a renderer.
For every other renderer config we ignore those paths.
Nothing is "any" typed. So if some transitive dependency isn't reachable
it won't be accidentally "any" that leaks.
* Lazify Blocks
Blocks now initialize lazily.
* Initialize Blocks eagerly in ChildFiber
This is for the case when it's a new Block that hasn't yet initialized.
We need to first initialize it to see what "render function" it resolves
to so that we can use that in our comparison.
* Remove extra import type line
* Failing: Dropped effects in Legacy Mode Suspense
* Transfer mounted effects on suspend in legacy mode
In legacy mode, a component that suspends bails out and commit in
its previous state. If the component previously had mounted effects,
we must transfer those to the work-in-progress so they don't
get dropped.
In CI, we run our test suite against multiple build configurations. For
example, we run our tests in both dev and prod, and in both the
experimental and stable release channels. This is to prevent accidental
deviations in behavior between the different builds. If there's an
intentional deviation in behavior, the test author must account
for them.
However, we currently don't run tests against the www builds. That's
a problem, because it's common for features to land in www before they
land anywhere else, including the experimental release channel.
Typically we do this so we can gradually roll out the feature behind
a flag before deciding to enable it.
The way we test those features today is by mutating the
`shared/ReactFeatureFlags` module. There are a few downsides to this
approach, though. The flag is only overridden for the specific tests or
test suites where you apply the override. But usually what you want is
to run *all* tests with the flag enabled, to protect against unexpected
regressions.
Also, mutating the feature flags module only works when running the
tests against source, not against the final build artifacts, because the
ReactFeatureFlags module is inlined by the build script.
Instead, we should run the test suite against the www configuration,
just like we do for prod, experimental, and so on. I've added a new
command, `yarn test-www`. It automatically runs in CI.
Some of the www feature flags are dynamic; that is, they depend on
a runtime condition (i.e. a GK). These flags are imported from an
external module that lives in www. Those flags will be enabled for some
clients and disabled for others, so we should run the tests against
*both* modes.
So I've added a new global `__VARIANT__`, and a new test command `yarn
test-www-variant`. `__VARIANT__` is set to false by default; when
running `test-www-variant`, it's set to true.
If we were going for *really* comprehensive coverage, we would run the
tests against every possible configuration of feature flags: 2 ^
numberOfFlags total combinations. That's not practical, though, so
instead we only run against two combinations: once with `__VARIANT__`
set to `true`, and once with it set to `false`. We generally assume that
flags can be toggled independently, so in practice this should
be enough.
You can also refer to `__VARIANT__` in tests to detect which mode you're
running in. Or, you can import `shared/ReactFeatureFlags` and read the
specific flag you can about. However, we should stop mutating that
module going forward. Treat it as read-only.
In this commit, I have only setup the www tests to run against source.
I'll leave running against build for a follow up.
Many of our tests currently assume they run only in the default
configuration, and break when certain flags are toggled. Rather than fix
these all up front, I've hard-coded the relevant flags to the default
values. We can incrementally migrate those tests later.
* Implemented Profiler onCommit() and onPostCommit() hooks
* Added enableProfilerCommitHooks feature flag for commit hooks
* Moved onCommit and onPassiveCommit behind separate feature flag
* Revert "Revert "feat: honor displayName of context types (#18035)" (#18223)"
This reverts commit 3ee812e6b6.
* Add warning of displayName is set on the consumer
* dedupe warning
* This type is all wrong and nothing cares because it's all any
* Refine Flow types of Lazy Components
We can type each condition.
* Remove _ctor field from Lazy components
This field is not needed because it's only used before we've initialized,
and we don't have anything else to store before we've initialized.
* Check for _ctor in case it's an older isomorphic that created it
We try not to break across minors but it's no guarantee.
* Move types and constants from shared to isomorphic
The "react" package owns the data structure of the Lazy component. It
creates it and decides how any downstream renderer may use it.
* Move constants to shared
Apparently we can't depend on react/src/ because the whole package is
considered "external" as far as rollup is concerned.
* Bugfix: Expiring a partially completed tree (#17926)
* Failing test: Expiring a partially completed tree
We should not throw out a partially completed tree if it expires in the
middle of rendering. We should finish the rest of the tree without
yielding, then finish any remaining expired levels in a single batch.
* Check if there's a partial tree before restarting
If a partial render expires, we should stay in the concurrent path
(performConcurrentWorkOnRoot); we'll stop yielding, but the rest of the
behavior remains the same.
We will only revert to the sync path (performSyncWorkOnRoot) when
starting on a new level.
This approach prevents partially completed concurrent work from
being discarded.
* New test: retry after error during expired render
* Regression: Expired partial tree infinite loops
Adds regression tests that reproduce a scenario where a partially
completed tree expired then fell into an infinite loop.
The code change that exposed this bug made the assumption that if you
call Scheduler's `shouldYield` from inside an expired task, Scheduler
will always return `false`. But in fact, Scheduler sometimes returns
`true` in that scenario, which is a bug.
The reason it worked before is that once a task timed out, React would
always switch to a synchronous work loop without checking `shouldYield`.
My rationale for relying on `shouldYield` was to unify the code paths
between a partially concurrent render (i.e. expires midway through) and
a fully concurrent render, as opposed to a render that was synchronous
the whole time. However, this bug indicates that we need a stronger
guarantee within React for when tasks expire, given that the failure
case is so catastrophic. Instead of relying on the result of a dynamic
method call, we should use control flow to guarantee that the work is
synchronously executed.
(We should also fix the Scheduler bug so that `shouldYield` always
returns false inside an expired task, but I'll address that separately.)
* Always switch to sync work loop when task expires
Refactors the `didTimeout` check so that it always switches to the
synchronous work loop, like it did before the regression.
This breaks the error handling behavior that I added in 5f7361f (an
error during a partially concurrent render should retry once,
synchronously). I'll fix this next. I need to change that behavior,
anyway, to support retries that occur as a result of `flushSync`.
* Retry once after error even for sync renders
Except in legacy mode.
This is to support the `useOpaqueReference` hook, which uses an error
to trigger a retry at lower priority.
* Move partial tree check to performSyncWorkOnRoot
* Factor out render phase
Splits the work loop and its surrounding enter/exit code into their own
functions. Now we can do perform multiple render phase passes within a
single call to performConcurrentWorkOnRoot or performSyncWorkOnRoot.
This lets us get rid of the `didError` field.
* Added missing @flow pragma to React.js
* Fixed useContext() return type definition
* Fixed previously masked Flow errors in DevTools and react-interactions packages
* Added displayName to internal Context Flow type
* Removed Flow generic annotations for createResponder
This seems to cause a parsing error. (Not sure why.) The API is deprecated anyway so I'm being lazy for now and just adding a .
* Only use Rollup's CommonJS plugin for "react-art"
We still need it for the "art" UMD builds but nothing else should have
CommonJS dependencies anymore.
* react-debug-tools and jest-react should leave object-assign as an external dep
This avoids it being compiled into the output.
* Check in a forked version of object-assign
This one uses ES modules so that we can inline it into UMD builds.
We could wait for object-assign to make an ESM export but we're going to
remove this dependency and assume global polyfills in the next version
anyway. However, we'd have to figure out how to keep the copyright header
and it'll get counted in terms of byte size (even if other tooling removes
it).
A lot of headache when we have our own implementation anyway. So I'll just
use that.
Ours is not resilient to checking certain browser bugs but those browsers
are mostly unused anyway. (Even FB breaks on them presumably.)
We also don't need to be resilient to Symbols since the way React uses it
we shouldn't need to copy symbols
* Don't transpile Object.assign to object-assign in object-assign
The polyfill needs to be able to feature detect Object.assign.
* improve findByType error message
* fix flow typing
* Adding a test for the "Unknown" branch when `getComponentName()` returns a falsy value. The error message in this case not the most descriptive but seems consistent with the `getComponentName(type) || 'Unknown'` pattern seen in multiple places in this code base.
* Move remaining things to named exports
The interesting case here is the noop renderers. The wrappers around the
reconciler now changed to use a local export that gets mutated.
ReactNoop and ReactNoopPersistent now have to destructure the object to
list out the names it's going to export. We should probably refactor
ReactNoop away from createReactNoop. Especially since it's also not Flow
typed.
* Switch interactions to star exports
This will have esModule compatibility flag on them. They should ideally
export default instead.