We need the regression config moduleNameMapper to come before the current moduleNameMapper so when it tries to map "/^react-dom\/([^/]+)$/ it doesn't get confused. The reason is because order in which the mappings are defined matters. Patterns are checked one by one until one fits, and the most specific rule should be listed first.
This PR adds a script that downloads the specified react version from NPM (ie. react-dom, react, and react-test-renderer) and replaces the corresponding files in the build folder with the downloaded react files.
The scheduler package, unlike react-dom, react, and react-test-renderer, is versioned differently, so we also need to specifically account for that in the script.
Some older React versions have different module import names and are missing certain features. This PR mocks modules that don't exist and maps modules in older versions to the ones that are required in tests. Specifically:
* In React v16.5, scheduler is named schedule
* In pre concurrent React, there is no act
* Prior to React v18.0, react-dom/client doesn't exist
* In DevTools, we expect to use scheduler/tracing-profiling instead of scheduler/tracing
`string.replaceAll` doesn't exist in our CircleCI Docker environment. We also don't need it in this case because `semver.satisfies` allows for whitespace when specifying a range. This PR removes the unnecessary call.
I added a `--sourceMaps` option to our test command that enables inline
source maps. I've kept it disabled by default, since it makes the tests
run slower. But it's super useful when attaching to a debugger.
This reverts #24106.
There was a regression in CircleCI's artifacts API recently where you
could no longer access artifacts without an authorization token. This
broke our size reporting CI job because we can't use an authorization
token on external PRs without potentially leaking it. As a temporary
workaround, I changed the size reporting job to use a public mirror of
our build artifacts.
The CircleCI API has since been fixed to no longer require
authorization, so we can revert the workaround.
Add `--reactVersion` argument. This argument is only used in DevTools. When this is specified, run only the tests that have the `// @reactVersion` pragma that satisfies the semver version range. Otherwise, run tests as normal
In DevTools tests, if the REACT_VERSION specified, we know this is a regression test (testing older React Versions). Because a lot of tests test the DevTools front end and we don't want to run them in the regression test scenario, we decided to only run tests that have the // @reactVersion pragma defined.
Because if there are no tests specified, jest will fail, we also opt to use jest.skip to skip all the tests that we don't want to run for a specific React version istead.
This PR makes this change.
This PR:
Adds a transform-react-version-pragma that transforms // @reactVersion SEMVER_VERSION into _test_react_version(...) and _test_react_version_focus(...) that lets us only run a test if it satisfies the right react version.
Adds _test_react_version and _test_react_version_focus to the devtools setupEnv file
Add a devtools preprocessor file for devtools specific plugins
The `version` field exported by the React package currently corresponds
to the `@next` release for that build. This updates the build script
to output the same version that is used in the package.json file.
It works by doing a find-and-replace of the React version after the
build has completed. This is a bit weird but it saves us from having
to build the `@next` and `@latest` releases separately; they are
identical except for the version numbers.
Fix matching in the build script.
It's possible to provide a custom bundle name in the case we build deep
imports. We should match those names as a convenience.
The script also calls toLowerCase on requested names but some entries have
upper case now.
* Add fixture for comparing baseline render perf for renderToString and renderToPipeableStream
Modified from ssr2 and https://github.com/SuperOleg39/react-ssr-perf-test
* Implement buffering in pipeable streams
The previous implementation of pipeable streaming (Node) suffered some performance issues brought about by the high chunk counts and innefficiencies with how node streams handle this situation. In particular the use of cork/uncork was meant to alleviate this but these methods do not do anything unless the receiving Writable Stream implements _writev which many won't.
This change adopts the view based buffering techniques previously implemented for the Browser execution context. The main difference is the use of backpressure provided by the writable stream which is not implementable in the other context. Another change to note is the use of standards constructs like TextEncoder and TypedArrays.
* Implement encodeInto during flushCompletedQueues
encodeInto allows us to write directly to the view buffer that will end up getting streamed instead of encoding into an intermediate buffer and then copying that data.
The problem in scripts\babel\transform-object-assign.js is that file path separator has '/' and '\' between Linux, MacOS and Windows, which causes yarn build error. See https://github.com/facebook/react/issues/24103
* Switched RulesOfHooks.js to use BigInt. Added test and updated .eslintrc.js to use es2020.
* Added BigInt as readonly global in eslintrc.cjs.js and eslintrc.cjs2015.js
* Added comment to RulesOfHooks.js that gets rid of BigInt eslint error
* Got rid of changes in .eslintrc.js and yarn.lock
* Move global down
Co-authored-by: stephen cyron <stephen.cyron@fdmgroup.com>
Co-authored-by: dan <dan.abramov@gmail.com>
* Add authorization header to artifacts request
CircleCI's artifacts API was updated; it now errors unless you're
logged in. This affects any of our workflows that download
build artifacts.
To fix, I added an authorization header to the request.
* Update sizbot to pull artifacts from public mirror
We can't use the normal download-build script in sizebot because it
depends on the CircleCI artifacts API, which was recently changed to
require authorization. And we can't pass an authorization token
without possibly leaking it to the public, since we run sizebot on
PRs from external contributors. As a temporary workaround, this job
will pull the artifacts from a public mirror that I set up. But we
should find some other solution so we don't have to maintain
the mirror.
* Flight side of server context
* 1 more test
* rm unused function
* flow+prettier
* flow again =)
* duplicate ReactServerContext across packages
* store default value when lazily initializing server context
* .
* better comment
* derp... missing import
* rm optional chaining
* missed feature flag
* React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED ??
* add warning if non ServerContext passed into useServerContext
* pass context in as array of arrays
* make importServerContext nott pollute the global context state
* merge main
* remove useServerContext
* dont rely on object getters in ReactServerContext and disallow JSX
* add symbols to devtools + rename globalServerContextRegistry to just ContextRegistry
* gate test case as experimental
* feedback
* remove unions
* Lint
* fix oopsies (tests/lint/mismatching arguments/signatures
* lint again
* replace-fork
* remove extraneous change
* rebase
* 1 more test
* rm unused function
* flow+prettier
* flow again =)
* duplicate ReactServerContext across packages
* store default value when lazily initializing server context
* .
* better comment
* derp... missing import
* rm optional chaining
* missed feature flag
* React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED ??
* add warning if non ServerContext passed into useServerContext
* pass context in as array of arrays
* make importServerContext nott pollute the global context state
* merge main
* remove useServerContext
* dont rely on object getters in ReactServerContext and disallow JSX
* add symbols to devtools + rename globalServerContextRegistry to just ContextRegistry
* gate test case as experimental
* feedback
* remove unions
* Lint
* fix oopsies (tests/lint/mismatching arguments/signatures
* lint again
* replace-fork
* remove extraneous change
* rebase
* reinline
* rebase
* add back changes lost due to rebase being hard
* emit chunk for provider
* remove case for React provider type
* update type for SomeChunk
* enable flag with experimental
* add missing types
* fix flow type
* missing type
* t: any
* revert extraneous type change
* better type
* better type
* feedback
* change import to type import
* test?
* test?
* remove react-dom
* remove react-native-renderer from react-server-native-relay/package.json
* gate change in FiberNewContext, getComponentNameFromType, use switch statement in FlightServer
* getComponentNameFromTpe: server context type gated and use displayName if available
* fallthrough
* lint....
* POP
* lint
* Implement addEventListener and removeEventListener on Fabric HostComponent
* add files
* re-add CustomEvent
* fix flow
* Need to get CustomEvent from an import since it won't exist on the global scope by default
* yarn prettier-all
* use a mangled name consistently to refer to imperatively registered event handlers
* yarn prettier-all
* fuzzy null check
* fix capture phase event listener logic
* early exit from getEventListeners more often
* make some optimizations to getEventListeners and the bridge plugin
* fix accumulateInto logic
* fix accumulateInto
* Simplifying getListeners at the expense of perf for the non-hot path
* feedback
* fix impl of getListeners to correctly remove function
* pass all args in to event listeners
* Move createRoot/hydrateRoot to /client
We want these APIs ideally to be imported separately from things you
might use in arbitrary components (like flushSync). Those other methods
are "isomorphic" to how the ReactDOM tree is rendered. Similar to hooks.
E.g. importing flushSync into a component that only uses it on the client
should ideally not also pull in the entry client implementation on the
server.
This also creates a nicer parity with /server where the roots are in a
separate entry point.
Unfortunately, I can't quite do this yet because we have some legacy APIs
that we plan on removing (like findDOMNode) and we also haven't implemented
flushSync using a flag like startTransition does yet.
Another problem is that we currently encourage these APIs to be aliased by
/profiling (or unstable_testing). In the future you don't have to alias
them because you can just change your roots to just import those APIs and
they'll still work with the isomorphic forms. Although we might also just
use export conditions for them.
For that all to work, I went with a different strategy for now where the
real API is in / but it comes with a warning if you use it. If you instead
import /client it disables the warning in a wrapper. That means that if you
alias / then import /client that will inturn import the alias and it'll
just work.
In a future breaking changes (likely when we switch to ESM) we can just
remove createRoot/hydrateRoot from / and move away from the aliasing
strategy.
* Update tests to import from react-dom/client
* Fix fixtures
* Update warnings
* Add test for the warning
* Update devtools
* Change order of react-dom, react-dom/client alias
I think the order matters here. The first one takes precedence.
* Require react-dom through client so it can be aliased
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Refactor warnForTextDifference
We're going to fork the behavior of this function between concurrent
roots and legacy roots.
The legacy behavior is to warn in dev when the text mismatches during
hydration. In concurrent roots, we'll log a recoverable error and revert
to client rendering. That means this is no longer a development-only
function — it affects the prod behavior, too.
I haven't changed any behavior in this commit. I only rearranged the
code slightly so that the dev environment check is inside the body
instead of around the function call. I also threaded through an
isConcurrentMode argument.
* Revert to client render on text content mismatch
Expands the behavior of enableClientRenderFallbackOnHydrationMismatch to
check text content, too.
If the text is different from what was rendered on the server, we will
recover the UI by falling back to client rendering, up to the nearest
Suspense boundary.
* Remove object-assign polyfill
We really rely on a more modern environment where this is typically
polyfilled anyway and we don't officially support IE with more extensive
polyfilling anyway. So all environments should have the native version
by now.
* Use shared/assign instead of Object.assign in code
This is so that we have one cached local instance in the bundle.
Ideally we should have a compile do this for us but we already follow
this pattern with hasOwnProperty, isArray, Object.is etc.
* Transform Object.assign to now use shared/assign
We need this to use the shared instance when Object.spread is used.
We only export the source directory so Jest and Rollup can access them
during local development and at build time. The files don't exist in the
public builds, so we don't need the export entry, either.
The unstable-shared-subset.js file is not a public module — it's a
private module that the "react" package maps to when it's accessed from
the "react-server" package.
We originally added it because it was required to make our Rollup
configuration work, because at the time only "public" modules could act
as the entry point for a build artifact — that's why it's prefixed with
"unstable". We've since updated our Rollup config to support private
entry points, so we can remove the extra indirection.
There are several cases where hydration fails, server-rendered HTML is
discarded, and we fall back to client rendering. Whenever this happens,
we will now log an error with onRecoverableError, with a message
explaining why.
In some of these scenarios, this is not the only recoverable error that
is logged. For example, an error during hydration will cause hydration
to fail, which is itself an error. So we end up logging two separate
errors: the original error, and one that explains why hydration failed.
I've made sure that the original error always gets logged first, to
preserve the causal sequence.
Another thing we could do is aggregate the errors with the Error "cause"
feature and AggregateError. Since these are new-ish features in
JavaScript, we'd need a fallback behavior. I'll leave this for a
follow up.
* Remove deprecated folder mapping
Node v16 deprecated the use of trailing "/" to define subpath folder
mappings in the "exports" field of package.json.
The recommendation is to explicitly list all our exports. We already do
that for all our public modules. I believe the only reason we have a
wildcard pattern is because our package.json files are also used at
build time (by Rollup) to resolve internal source modules that don't
appear in the final npm artifact.
Changing trailing "/" to "/*" fixes the warnings. See
https://nodejs.org/api/packages.html#subpath-patterns for more info.
Since the wildcard pattern only exists so our build script has access to
internal at build time, I've scoped the wildcard to "/src/*". Because
our public modules are located outside the "src" directory, this means
deep imports of our modules will no longer work: only packages that are
listed in the "exports" field.
The only two affected packages are react-dom and react. We need to be
sure that all our public modules are still reachable. I audited the
exports by comparing the entries to the "files" field in package.json,
which represents a complete list of the files that are included in the
final release artifact.
At some point, we should add an e2e packaging test to prevent
regressions; for now, we should have decent coverage because in CI we
run our Jest test suite against the release artifacts.
* Remove umd from exports
Our expectation is that if you're using the UMD builds, you're not
loading them through a normal module system like require or import.
Instead you're probably copying the files directly or loading them from
a CDN like unpkg.
Alternative to #23254
Our build script has a custom plugin to resolve internal module forks.
Currently, it uses require.resolve to resolve the path to a real file
on disk.
Instead, I've updated all the forked module paths to match their
location on disk, relative to the project root, to remove the need to
resolve them in the build script's runtime.
The main motivation is because require.resolve doesn't work with ESM
modules, but aside from that, hardcoding the relative paths is more
predictable — the Node module resolution algorithm is complicated, and
we don't really need its features for this purpose.
* Use consistent naming for unstable_testing entry point
* Exclude the testing build from non-experimental builds except at FB
* FB builds shouldn't contribute to whether we include the npm files
* Exclude exports fields if we delete the files entry
* Move test to no longer be internal so we can test against the build
* Update the bundle artifact names since they've now changed
* Gate import since it doesn't exist
* RawEventEmitter: new event perf profiling mechanism outside of Pressability to capture all touch events, and other event types
* sync
* concise notation
* Move event telemetry event emitter call from Plugin to ReactFabricEventEmitter, to reduce reliance on the plugin system and move the emit call further into the core
* Backout changes to ReactNativeEventPluginOrder
* Properly flow typing event emitter, and emit event to two channels: named and catchall
* fix typing for event name string
* fix typing for event name string
* fix flow
* Add more comments about how the event telemetry system works
* Add more comments about how the event telemetry system works
* rename to RawEventTelemetryEventEmitterOffByDefault
* yarn prettier-all
* rename event
* comments
* improve flow types
* renamed file
* [RFC] Add onHydrationError option to hydrateRoot
This is not the final API but I'm pushing it for discussion purposes.
When an error is thrown during hydration, we fallback to client
rendering, without triggering an error boundary. This is good because,
in many cases, the UI will recover and the user won't even notice that
something has gone wrong behind the scenes.
However, we shouldn't recover from these errors silently, because the
underlying cause might be pretty serious. Server-client mismatches are
not supposed to happen, even if UI doesn't break from the users
perspective. Ignoring them could lead to worse problems later. De-opting
from server to client rendering could also be a significant performance
regression, depending on the scope of the UI it affects.
So we need a way to log when hydration errors occur.
This adds a new option for `hydrateRoot` called `onHydrationError`. It's
symmetrical to the server renderer's `onError` option, and serves the
same purpose.
When no option is provided, the default behavior is to schedule a
browser task and rethrow the error. This will trigger the normal browser
behavior for errors, including dispatching an error event. If the app
already has error monitoring, this likely will just work as expected
without additional configuration.
However, we can also expose additional metadata about these errors, like
which Suspense boundaries were affected by the de-opt to client
rendering. (I have not exposed any metadata in this commit; API needs
more design work.)
There are other situations besides hydration where we recover from an
error without surfacing it to the user, or notifying an error boundary.
For example, if an error occurs during a concurrent render, it could be
due to a data race, so we try again synchronously in case that fixes it.
We should probably expose a way to log these types of errors, too. (Also
not implemented in this commit.)
* Log all recoverable errors
This expands the scope of onHydrationError to include all errors that
are not surfaced to the UI (an error boundary). In addition to errors
that occur during hydration, this also includes errors that recoverable
by de-opting to synchronous rendering. Typically (or really, by
definition) these errors are the result of a concurrent data race;
blocking the main thread fixes them by prevents subsequent races.
The logic for de-opting to synchronous rendering already existed. The
only thing that has changed is that we now log the errors instead of
silently proceeding.
The logging API has been renamed from onHydrationError
to onRecoverableError.
* Don't log recoverable errors until commit phase
If the render is interrupted and restarts, we don't want to log the
errors multiple times.
This change only affects errors that are recovered by de-opting to
synchronous rendering; we'll have to do something else for errors
during hydration, since they use a different recovery path.
* Only log hydration error if client render succeeds
Similar to previous step.
When an error occurs during hydration, we only want to log it if falling
back to client rendering _succeeds_. If client rendering fails,
the error will get reported to the nearest error boundary, so there's
no need for a duplicate log.
To implement this, I added a list of errors to the hydration context.
If the Suspense boundary successfully completes, they are added to
the main recoverable errors queue (the one I added in the
previous step.)
* Log error with queueMicrotask instead of Scheduler
If onRecoverableError is not provided, we default to rethrowing the
error in a separate task. Originally, I scheduled the task with
idle priority, but @sebmarkbage made the good point that if there are
multiple errors logs, we want to preserve the original order. So I've
switched it to a microtask. The priority can be lowered in userspace
by scheduling an additional task inside onRecoverableError.
* Only use host config method for default behavior
Redefines the contract of the host config's logRecoverableError method
to be a default implementation for onRecoverableError if a user-provided
one is not provided when the root is created.
* Log with reportError instead of rethrowing
In modern browsers, reportError will dispatch an error event, emulating
an uncaught JavaScript error. We can do this instead of rethrowing
recoverable errors in a microtask, which is nice because it avoids any
subtle ordering issues.
In older browsers and test environments, we'll fall back
to console.error.
* Naming nits
queueRecoverableHydrationErrors -> upgradeHydrationErrorsToRecoverable
Refactor DevTools to record Timeline data (in memory) while profiling. Updated the Profiler UI to import/export Timeline data along with legacy profiler data.
Relates to issue #22529
Numbers in JavaScript can have precision issues due to how they are encoded. This shows up in snapshot tests sometimes with values like 0.0009999999999999992, which makes the tests hard to read and visually diff.
This PR adds a new snapshot serializers which clamps numbers at 3 decimal points (e.g. the above number 0.0009999999999999992 is serialized as 0.001). This new serializer does not impact non-numeric values, integers, and special numbers like NaN and Infinity.
Until now, DEV and PROFILING builds of React recorded Timeline profiling data using the User Timing API. This commit changes things so that React records this data by calling methods on the DevTools hook. (For now, DevTools still records that data using the User Timing API, to match previous behavior.)
This commit is large but most of it is just moving things around:
* New methods have been added to the DevTools hook (in "backend/profilingHooks") for recording the Timeline performance events.
* Reconciler's "ReactFiberDevToolsHook" has been updated to call these new methods (when they're present).
* User Timing method calls in "SchedulingProfiler" have been moved to DevTools "backend/profilingHooks" (to match previous behavior, for now).
* The old reconciler tests, "SchedulingProfiler-test" and "SchedulingProfilerLabels-test", have been moved into DevTools "TimelineProfiler-test" to ensure behavior didn't change unexpectedly.
* Two new methods have been added to the injected renderer interface: injectProfilingHooks() and getLaneLabelMap().
Relates to #22529.
* Add --no-show-signature to "git show" commands.
This fixes errors if the user has configured the following in their ~/.gitconfig:
[log]
showSignature = true
* yarn prettier-all
This lets us test how the new architecture performs without comparing it to
other infra changes related to streaming.
I renamed the streaming one to ReactDOMServerStreaming so the references
in www need to be updated.
I'll open an adhoc sync with just those files.
Another fix to previous commit. The special case for
use-sync-external-store still needs to write out the updated
package.json, because we also use that branch to update the
version field.