* 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.
Usually the build script updates transitive React dependencies so that
they refer to the corresponding release version.
For use-sync-external-store, though, we also want to support older
versions of React, too. So the normal behavior of the build script
isn't sufficient.
For now, to unblock, I hardcoded a special case, but we should consider
a better way to handle this in the future.
Checks that if one React package depends on another, the current
version satisfies the given dependency range.
That way we don't forget to bump dependencies when we release a
new version.
This change adds a new "react-dom/unstable_testing" entry point but I believe its contents will exactly match "react-dom/index" for the stable build. (The experimental build will have the added new selector APIs.)
* Move useSyncExternalStore shim to a nested entrypoint
Also renames `useSyncExternalStoreExtra` to
`useSyncExternalStoreWithSelector`.
- 'use-sync-external-store/shim' -> A shim for `useSyncExternalStore`
that works in React 16 and 17 (any release that supports hooks). The
module will first check if the built-in React API exists, before
falling back to the shim.
- 'use-sync-external-store/with-selector' -> An extended version of
`useSyncExternalStore` that also supports `selector` and `isEqual`
options. It does _not_ shim `use-sync-external-store`; it composes the
built-in React API. **Use this if you only support 18+.**
- 'use-sync-external-store/shim/with-selector' -> Same API, but it
composes `use-sync-external-store/shim` instead. **Use this for
compatibility with 16 and 17.**
- 'use-sync-external-store' -> Re-exports React's built-in API. Not
meant to be used. It will warn and direct users to either the shim or
the built-in API.
* Upgrade useSyncExternalStore to alpha channel
* Output FIXME during build for unminified errors
The invariant Babel transform used to output a FIXME comment if it
could not find a matching error code. This could happen if there were
a configuration mistake that caused an unminified message to
slip through.
Linting the compiled bundles is the most reliable way to do it because
there's not a one-to-one mapping between source modules and bundles. For
example, the same source module may appear in multiple bundles, some
which are minified and others which aren't.
This updates the transform to output the same messages for Error calls.
The source lint rule is still useful for catching mistakes during
development, to prompt you to update the error codes map before pushing
the PR to CI.
* Don't run error transform in development
We used to run the error transform in both production and development,
because in development it was used to convert `invariant` calls into
throw statements.
Now that don't use `invariant` anymore, we only have to run the
transform for production builds.
* Add ! to FIXME comment so Closure doesn't strip it
Don't love this solution because Closure could change this heuristic,
or we could switch to a differnt compiler that doesn't support it. But
it works.
Could add a bundle that contains an unminified error solely for the
purpose of testing it, but that seems like overkill.
* Alternate extract-errors that scrapes artifacts
The build script outputs a special FIXME comment when it fails to minify
an error message. CI will detect these comments and fail the workflow.
The comments also include the expected error message. So I added an
alternate extract-errors that scrapes unminified messages from the
build artifacts and updates `codes.json`.
This is nice because it works on partial builds. And you can also run it
after the fact, instead of needing build all over again.
* Disable error minification in more bundles
Not worth it because the number of errors does not outweight the size
of the formatProdErrorMessage runtime.
* Run extract-errors script in CI
The lint_build job already checks for unminified errors, but the output
isn't super helpful.
Instead I've added a new job that runs the extract-errors script and
fails the build if `codes.json` changes. It also outputs the expected
diff so you can easily see which messages were missing from the map.
* Replace old extract-errors script with new one
Deletes the old extract-errors in favor of extract-errors2
This is an initial, partial implementation of a cleanup mechanism for the experimental Cache API. The idea is that consumers of the Cache API can register to be informed when a given Cache instance is no longer needed so that they can perform associated cleanup tasks to free resources stored in the cache. A canonical example would be cancelling pending network requests.
An overview of the high-level changes:
* Changes the `Cache` type from a Map of cache instances to be an object with the original Map of instances, a reference count (to count roughly "active references" to the cache instances - more below), and an AbortController.
* Adds a new public API, `unstable_getCacheSignal(): AbortSignal`, which is callable during render. It returns an AbortSignal tied to the lifetime of the cache - developers can listen for the 'abort' event on the signal, which React now triggers when a given cache instance is no longer referenced.
* Note that `AbortSignal` is a web standard that is supported by other platform APIs; for example a signal can be passed to `fetch()` to trigger cancellation of an HTTP request.
* Implements the above - triggering the 'abort' event - by handling passive mount/unmount for HostRoot and CacheComponent fiber nodes.
Cases handled:
* Aborted transitions: we clean up a new cache created for an aborted transition
* Suspense: we retain a fresh cache instance until a suspended tree resolves
For follow-ups:
* When a subsequent cache refresh is issued before a previous refresh completes, the refreshes are queued. Fresh cache instances for previous refreshes in the queue should be cleared, retaining only the most recent cache. I plan to address this in a follow-up PR.
* If a refresh is cancelled, the fresh cache should be cleaned up.