Commit Graph

16771 Commits

Author SHA1 Message Date
Andrew Clark c3345638cb Support useFormStatus in progressively-enhanced forms (#29019)
Before this change, `useFormStatus` is only activated if a form is
submitted by an action function (either `<form action={actionFn}>` or
`<button formAction={actionFn}>`).

After this change, `useFormStatus` will also be activated if you call
`startTransition(actionFn)` inside a submit event handler that is
`preventDefault`-ed.

This is the last missing piece for implementing a custom `action` prop
that is progressively enhanced using `onSubmit` while maintaining the
same behavior as built-in form actions.

Here's the basic recipe for implementing a progressively-enhanced form
action. This would typically be implemented in your UI component
library, not regular application code:

```js
import {requestFormReset} from 'react-dom';

// To implement progressive enhancement, pass both a form action *and* a
// submit event handler. The action is used for submissions that happen
// before hydration, and the submit handler is used for submissions that
// happen after.
<form
  action={action}
  onSubmit={(event) => {
    // After hydration, we upgrade the form with additional client-
    // only behavior.
    event.preventDefault();

    // Manually dispatch the action.
    startTransition(async () => {
      // (Optional) Reset any uncontrolled inputs once the action is
      // complete, like built-in form actions do.
      requestFormReset(event.target);

      // ...Do extra action-y stuff in here, like setting a custom
      // optimistic state...

      // Call the user-provided action
      const formData = new FormData(event.target);
      await action(formData);
    });
  }}
/>
```
2024-05-09 13:16:08 -04:00
Sebastian Markbåge 151cce3740 Track Stack of JSX Calls (#29032)
This is the first step to experimenting with a new type of stack traces
behind the `enableOwnerStacks` flag - in DEV only.

The idea is to generate stacks that are more like if the JSX was a
direct call even though it's actually a lazy call. Not only can you see
which exact JSX call line number generated the erroring component but if
that's inside an abstraction function, which function called that
function and if it's a component, which component generated that
component. For this to make sense it really need to be the "owner" stack
rather than the parent stack like we do for other component stacks. On
one hand it has more precise information but on the other hand it also
loses context. For most types of problems the owner stack is the most
useful though since it tells you which component rendered this
component.

The problem with the platform in its current state is that there's two
ways to deal with stacks:

1) `new Error().stack` 
2) `console.createTask()`

The nice thing about `new Error().stack` is that we can extract the
frames and piece them together in whatever way we want. That is great
for constructing custom UIs like error dialogs. Unfortunately, we can't
take custom stacks and set them in the native UIs like Chrome DevTools.

The nice thing about `console.createTask()` is that the resulting stacks
are natively integrated into the Chrome DevTools in the console and the
breakpoint debugger. They also automatically follow source mapping and
ignoreLists. The downside is that there's no way to extract the async
stack outside the native UI itself so this information cannot be used
for custom UIs like errors dialogs. It also means we can't collect this
on the server and then pass it to the client for server components.

The solution here is that we use both techniques and collect both an
`Error` object and a `Task` object for every JSX call.

The main concern about this approach is the performance so that's the
main thing to test. It's certainly too slow for production but it might
also be too slow even for DEV.

This first PR doesn't actually use the stacks yet. It just collects them
as the first step. The next step is to start utilizing this information
in error printing etc.

For RSC we pass the stack along across over the wire. This can be
concatenated on the client following the owner path to create an owner
stack leading back into the server. We'll later use this information to
restore fake frames on the client for native integration. Since this
information quickly gets pretty heavy if we include all frames, we strip
out the top frame. We also strip out everything below the functions that
call into user space in the Flight runtime. To do this we need to figure
out the frames that represents calling out into user space. The
resulting stack is typically just the one frame inside the owner
component's JSX callsite. I also eagerly strip out things we expect to
be ignoreList:ed anyway - such as `node_modules` and Node.js internals.
2024-05-09 12:23:05 -04:00
Jon Jensen 04b058868c Upgrade jest and jsdom (#29026)
## Summary

This brings:
 - jest* up from 29.4.2 -> 29.7.0
 - jsdom up from 20.0.0 -> 22.1.0

While the latest version of jest-dom-environment still wants
`jsdom@^20.0.0`, it can safely use at least up to `jsdom@22.1.0`. See
https://github.com/jestjs/jest/pull/13825#issuecomment-1564015010 for
details.

Upgrading to latest versions lets us improve some WheelEvent tests and
will make it possible to test a much simpler FormData construction
approach (see #29018)

## How did you test this change?

Ran `yarn test` and `yarn test --prod` successfully
2024-05-08 13:57:25 -04:00
Jan Kassens b1d4096396 Facebook: merge react index.classic.fb and index.modern.fb (#29025)
Facebook: merge react index.classic.fb and index.modern.fb

These export the same.

NOTE: The 2 builds are still different based on flags and other forked
files.
2024-05-08 13:37:47 -04:00
Jan Kassens 6946ebe620 Cleanup enableServerComponentKeys flag (#28743)
Cleanup enableServerComponentKeys flag

Flag is `true` everywhere but RN where it doesn't apply.
2024-05-08 10:52:49 -04:00
Ruslan Lesiutin 1717ab0171 React DevTools 5.1.0 -> 5.2.0 (#29022)
Full list of changes (not a public changelog):
* fix[react-devtools/ci]: fix configurations for e2e testing
([hoxyq](https://github.com/hoxyq) in
[#29016](https://github.com/facebook/react/pull/29016))
* feat[react-devtools]: display forget badge for components in profiling
session ([hoxyq](https://github.com/hoxyq) in
[#29014](https://github.com/facebook/react/pull/29014))
* fix[react-devtools]: add backwards compat with legacy element type
symbol ([hoxyq](https://github.com/hoxyq) in
[#28982](https://github.com/facebook/react/pull/28982))
* Expose "view source" options to Fusebox integration
([motiz88](https://github.com/motiz88) in
[#28973](https://github.com/facebook/react/pull/28973))
* Enable inspected element context menu in Fusebox
([motiz88](https://github.com/motiz88) in
[#28972](https://github.com/facebook/react/pull/28972))
* Check in `frontend.d.ts` for react-devtools-fusebox, include in build
output ([motiz88](https://github.com/motiz88) in
[#28970](https://github.com/facebook/react/pull/28970))
* Devtools: Fix build-for-devtools
([eps1lon](https://github.com/eps1lon) in
[#28976](https://github.com/facebook/react/pull/28976))
* Move useMemoCache hook to react/compiler-runtime
([kassens](https://github.com/kassens) in
[#28954](https://github.com/facebook/react/pull/28954))
* warn -> error for Test Renderer deprecation
([acdlite](https://github.com/acdlite) in
[#28904](https://github.com/facebook/react/pull/28904))
* [react-dom] move all client code to `react-dom/client`
([gnoff](https://github.com/gnoff) in
[#28271](https://github.com/facebook/react/pull/28271))
* Rename the react.element symbol to react.transitional.element
([sebmarkbage](https://github.com/sebmarkbage) in
[#28813](https://github.com/facebook/react/pull/28813))
* Rename Forget badge ([jbonta](https://github.com/jbonta) in
[#28858](https://github.com/facebook/react/pull/28858))
* Devtools: Add support for useFormStatus
([eps1lon](https://github.com/eps1lon) in
[#28413](https://github.com/facebook/react/pull/28413))
2024-05-08 13:26:14 +01:00
Ruslan Lesiutin 0e6ea6991e fix[react-devtools/InspectedElementView.css]: dont draw bottom border for empty badge list (#29023)
Forward fix to https://github.com/facebook/react/pull/29014, the bug was
discovered while testing v5.2.0.
2024-05-08 13:16:27 +01:00
Dmytro Rykun b37e4b4e61 Clean up fastAddProperties and make it more correct (#29015)
## Summary

This PR makes some fixes to the `fastAddProperties` function:
- Use `if (!attributeConfig)` instead of `if (attributeConfig ===
undefined)` to account for `null`.
- If a prop has an Object `attributeConfig` with a `diff` function
defined on it, treat it as an atomic value to keep the semantics of
`diffProperties`.

## How did you test this change?

Build and run RNTester app.
2024-05-08 13:10:04 +01:00
Ruslan Lesiutin e150a32425 fix[react-devtools/ci]: fix configurations for e2e testing (#29016)
This should fix failing DevTools e2e tests on `main`.

With these changes, running tests locally successfully passes all cases.
2024-05-08 12:04:51 +01:00
Sebastian Markbåge ec15267a00 [Flight Reply] Resolve outlined models async in Reply just like in Flight Client (#28988)
This is the same change as #28780 but for the Flight Reply receiver.

While it's not possible to create an "async module" reference in this
case - resolving a server reference can still be async if loading it
requires loading chunks like in a new server instance.

Since extracting a typed array from a Blob is async, that's also a case
where a dependency can be async.
2024-05-07 22:19:59 -04:00
Sebastian Markbåge 6bac4f2f31 [Fizz] Fallback to client replaying actions if we're trying to serialize a Blob (#28987)
This follows the same principle as in #28611.

We cannot serialize Blobs of a form data into HTML because you can't
initialize a file input to some value. However the serialization of
state in an Action can contain blobs. In this case we do error but
outside the try/catch that recovers to error to client replaying instead
of MPA mode. This errors earlier to ensure that this works.

Testing this is a bit annoying because JSDOM doesn't have any of the
Blob methods but the Blob needs to be compatible with FormData and the
FormData needs to be compatible with `<form>` nodes in these tests. So I
polyfilled those in JSDOM with some hacks.

A possible future enhancement would be to encode these blobs in a base64
mode instead and have some way to receive them on the server. It's just
a matter of layering this. I think the RSC layer's `FORM_DATA`
implementation can pass some flag to encode as base64 and then have
decodeAction include some way to parse them. That way this case would
work in MPA mode too.
2024-05-07 21:53:10 -04:00
Sebastian Markbåge 826bf4e51e [Flight Reply] Encode binary streams as a single collapsed Blob (#28986)
Based on #28893.

For other streams we encode each chunk as a separate form field which is
a bit bloated. Especially for binary chunks since they also have an
indirection. We need some way to encode the chunks as separate anyway.
This way the streaming using busboy actually allows each chunk to stream
in over the network one at a time.

For binary streams the actual chunking is not important. The chunks can
be split and recombined in whatever size chunk makes sense.

Since we buffer the entire content anyway we can combine the chunks to
be consecutive. This PR does that with binary streams and also combine
them into a single Blob. That way there's no extra overhead when passing
through a binary stream.

Ideally, we'd be able to just use the stream from that one Blob but
Node.js doesn't return byob streams from Blob. Additionally, we don't
actually stream the content of Blobs due to the layering with busboy
atm. We could do that for binary streams in particular by replacing the
File layering with a stream and resolving each chunk as it comes in.
That could be a follow up.

If we stop buffering in the future, this set up still allows us to split
them and send other form fields in between while blocked since the
protocol is still the same.
2024-05-07 21:52:55 -04:00
Ruslan Lesiutin e7d213dfb0 feat[react-devtools]: display forget badge for components in profiling session (#29014)
# Summary
- `compiledWithForget` field for nodes is now propagated from the
backend to frontend profiler stores
- Corresponding node with such field will have a `` prefix displayed
before its displayName
<img width="1728" alt="Screenshot 2024-05-07 at 15 05 37"
src="https://github.com/facebook/react/assets/28902667/fe044d40-52cb-4169-867d-5a2d72e3275b">

- Badges are now displayed on the right panel when some fiber is
selected in a specific commit
<img width="1728" alt="Screenshot 2024-05-07 at 15 05 50"
src="https://github.com/facebook/react/assets/28902667/297ba5ca-404d-4172-b9bf-bfed7978afe5">

- Badges are also displayed when user hovers over some node in the tree
<img width="1728" alt="Screenshot 2024-05-07 at 15 25 22"
src="https://github.com/facebook/react/assets/28902667/bee47884-61d1-46b6-a483-717fc148893a">
2024-05-07 16:39:01 +01:00
Ruslan Lesiutin c32ff0f4f1 fix[react-devtools]: add backwards compat with legacy element type symbol (#28982)
Follow-up to https://github.com/facebook/react/pull/28813.

RDT is using `typeOf` from `react-is` to determine the element display
name, I've forked an implementation of this method, but will be using
legacy element symbol.
2024-05-07 16:38:43 +01:00
Sebastian Silbermann 0fc9c84e63 Allow specifying timeout in tests via third argument (#29006) 2024-05-07 17:15:39 +02:00
Moti Zilberman afe54bfcbf [DevTools] Expose "view source" options to Fusebox integration (#28973)
## Summary

Exposes the APIs needed by React Native DevTools (Fusebox) to implement
the "view element source" and "view attribute source" features.

## How did you test this change?

1. `yarn build` in `react-devtools-fusebox`
2. Copy artifacts to rn-chrome-devtools-frontend
3. Write some additional glue code to implement
`viewElementSourceFunction` in our CDT fork.
4. Test the feature manually.


https://github.com/facebook/react/assets/2246565/12667018-100a-4b3f-957a-06c07f2af41a
2024-05-07 16:06:36 +01:00
Dmytro Rykun 7039834262 Create Fabric-specific version of ReactNativeAttributesPayload (#28841)
## Summary

This PR introduces Fabric-only version of
`ReactNativeAttributesPayload`. It is a copy-paste of
`ReactNativeAttributesPayload.js`, and is called
`ReactNativeAttributesPayloadFabric.js`.
The idea behind this change is that certain optimizations in prop
diffing may actually be a regression on the old architecture. For
example, removing custom diffing may result in larger updateProps
payloads. Which is, I guess, fine with JSI, but might be a problem with
the bridge.

## How did you test this change?

There should be no runtime effect of this change.
2024-05-07 11:53:36 +01:00
Jan Kassens b498834eab Set enableUseMemoCacheHook to true everywhere (#28964)
Set enableUseMemoCacheHook to true everywhere for the next major releases.
2024-05-06 14:20:08 -04:00
Timothy Yung 9b1300209e Setup Wave 2 of Feature Flags for React Native (#28990)
## Summary

Sets up dynamic feature flags for `disableStringRefs`, `enableFastJSX`,
and `enableRefAsProp` in React Native (at Meta).

## How did you test this change?

```
$ yarn test
$ yarn flow fabric
```
2024-05-06 10:30:40 -07:00
Jack Pope 5d29478716 Add FB build for ReactReconcilerConstants (#29003)
In order to integrate the `react-reconciler` build created in #28880
with third party libraries, we need to have matching
`react-reconciler/constants` to go with it.
2024-05-06 11:32:43 -04:00
Timothy Yung 46abd7b1de Update compiled-rn destination paths to vendor/react (#28989)
I'm changing the destination paths in fbsource from `vendor/*` to
`vendor/react/*`.
2024-05-03 15:46:43 -07:00
Sebastian Markbåge ec9400dc41 [Flight Reply] Encode ReadableStream and AsyncIterables (#28893)
Same as #28847 but in the other direction.

Like other promises, this doesn't actually stream in the outgoing
direction. It buffers until the stream is done. This is mainly due to
our protocol remains compatible with Safari's lack of outgoing streams
until recently.

However, the stream chunks are encoded as separate fields and so does
support the busboy streaming on the receiving side.
2024-05-03 17:23:55 -04:00
Sebastian Markbåge 5fcfd71638 Use undici polyfill for tests in old Node versions (#28887)
We currently don't test FormData / File dependent features in CI because
we use an old Node.js version in CI. We should probably upgrade to 18
since that's really the minimum version that supports all the features
out of the box.

JSDOM is not a faithful/compatible implementation of these APIs. The
recommended way to use Flight together with FormData/Blob/File in older
Node.js versions, is to polyfill using the `undici` library.

However, even in these versions the Blob implementation isn't quite
faithful so the Reply client needs a slight tweak for multi-byte typed
arrays.
2024-05-03 16:29:09 -04:00
Sebastian Markbåge d5c303427e [Flight] Track Owner on AsyncLocalStorage When Available (#28807)
Stacked on #28798.

Add another AsyncLocalStorage to the FlightServerConfig. This context
tracks data on a per component level. Currently the only thing we track
is the owner in DEV.

AsyncLocalStorage around each component comes with a performance cost so
we only do it DEV. It's not generally a particularly safe operation
because you can't necessarily associate side-effects with a component
based on execution scope. It can be a lazy initializer or cache():ed
code etc. We also don't support string refs anymore for a reason.

However, it's good enough for optional dev only information like the
owner.
2024-05-03 16:29:00 -04:00
Jan Kassens 0a0a3af75a Bundle config: inline internal hook wrapper (#28978)
Bundle config: inline internal hook wrapper

Instead of reading this wrapper from 2 files for "start" and "end" and
then string modifying the templates, just inline them like the other
wrappers in this file.
2024-05-03 14:08:10 -04:00
Jon Janzen 38cd73b25b Stop committing resources to an external repo (#28963)
This has been integrated into this repo (`builds/facebook-fbsource`) so
we no longer need the extra repo
2024-05-03 11:01:53 -07:00
Moti Zilberman e3fbb51db6 [DevTools] Enable inspected element context menu in Fusebox (#28972)
## Summary

Enables the inspected element context menu in React Native DevTools
(Fusebox).

## How did you test this change?

1. `yarn build` in `react-devtools-fusebox`
2. Copy artifacts to rn-chrome-devtools-frontend
3. Manually test the context menu


https://github.com/facebook/react/assets/2246565/b35cc20f-8d67-43b0-b863-7731e10fffac

NOTE: The serialised values sometimes expose React internals (e.g. Hook
data structures instead of just the values), but that seems to be a
problem equally on web, so I'm going for native<->web parity here.
2024-05-03 17:33:21 +01:00
Moti Zilberman 8f7dd5592b [DevTools] Check in frontend.d.ts for react-devtools-fusebox, include in build output (#28970)
## Summary

The `react-devtools-fusebox` private package is used in the React Native
DevTools (Fusebox) frontend by checking build artifacts into RN's
[fork]([`facebookexperimental/rn-chrome-devtools-frontend`](https://github.com/facebookexperimental/rn-chrome-devtools-frontend))
of the Chrome DevTools (CDT) repo - see
https://github.com/facebookexperimental/rn-chrome-devtools-frontend/pull/22.

Currently, the CDT fork also includes a [manually written TypeScript
definition
file](https://github.com/facebookexperimental/rn-chrome-devtools-frontend/blob/1d5f8d5209ac49de97aec16732169d47bf525474/front_end/third_party/react-devtools/package/frontend.d.ts)
which describes `react-devtools-fusebox`'s API. This PR moves that file
into the React repo, next to the implementation of
`react-devtools-fusebox`, so we can update it atomically with changes to
the package.

As this is the first bit of TypeScript in this repo, the PR adds minimal
support for formatting `.d.ts` files with Prettier. It also opts out
`react-devtools-fusebox/dist/` from linting/formatting as a drive-by
fix.

For now, we'll just maintain the `.d.ts` file manually, but we could
consider leveraging
[`flow-api-translator`](https://www.npmjs.com/package/flow-api-translator)
to auto-generate it in the future.

## How did you test this change?

Build `react-devtools-fusebox`, observe that `dist/frontend.d.ts`
exists.
2024-05-03 17:32:41 +01:00
Jack Pope 1beb73de0f Add flag to test fast jsx (#28816)
Following #28768, add a path to testing Fast JSX on www.

We want to measure the impact of Fast JSX and enable a path to testing
before string refs are completely removed in www (which is a work in
progress).

Without `disableStringRefs`, we need to copy any object with a `ref` key
so we can pass it through `coerceStringRef()` and copy it into the
object. This de-opt path is what is gated behind
`enableFastJSXWithStringRefs`.

The additional checks should have no perf impact in OSS as the flags
remain true there and the build output is not changed. For www, I've
benchmarked the addition of the boolean checks with values cached at
module scope. There is no significant change observed from our
benchmarks and any latency will apply to test and control branches
evenly. This added experiment complexity is temporary. We should be able
to clean it up, along with the flag checks for `enableRefAsProp` and
`disableStringRefs` shortly.
2024-05-03 10:47:13 -04:00
Timothy Yung 1d618a9cf3 Enable Wave 1 of Feature Flags for React Native (#28977) 2024-05-02 20:01:30 -07:00
Sebastian Silbermann f5f2799a8d DevTools: Fix inspecting components with multiple reads of the same Context in React 17 (#28974) 2024-05-02 22:08:41 +02:00
Sebastian Silbermann 14f71db6b6 Devtools: Fix build-for-devtools (#28976) 2024-05-02 21:58:51 +02:00
Sebastian Silbermann c44e9d1557 Devtools: Streamline getting extension from branch (#28975) 2024-05-02 21:47:18 +02:00
Dmytro Rykun 73bcdfbae5 Introduce a faster version of the addProperties function (#28969)
## Summary

This PR introduces a faster version of the `addProperties` function.
This new function is basically the `diffProperties` with `prevProps` set
to `null`, propagated constants, and all the unreachable code paths
collapsed.

## How did you test this change?

I've tested this change with [the benchmark
app](https://github.com/react-native-community/RNNewArchitectureApp/tree/new-architecture-benchmarks)
and got ~4.4% improvement in the view creation time.
2024-05-02 17:10:13 +01:00
Josh Story c7b1ae5a9e [Tooling] Update critical artifact list (#28966)
When a React PR is opened CI will report large size changes. But for
critical packages like react-dom it reports always. In React 19 we moved
the build for react-dom the client reconciler from react-dom to
react-dom/client

This change adds react-dom-client artifacts for stable and oss channels
since that is originally what was being tracked. But since
react-dom/client always imports react-dom I left the original react-dom
packages as critical as well. They are small but it would be good to
keep an eye on them
2024-05-02 07:39:10 -07:00
Juan Pinilla 29d3c83f0a ReactDOM: Fix missing form data when the submitter is outside the form (#28056) 2024-05-02 13:06:28 +02:00
Jan Kassens 4508873393 Move useMemoCache hook to react/compiler-runtime (#28954)
Move useMemoCache hook to react/compiler-runtime

For Meta-internal purposes, we keep the export on `react` itself to
reduce churn.
2024-04-30 12:00:22 -04:00
Pieter De Baets d779eba4b3 [react-native] Add unit test to ReactNativeAttributePayload (#28955)
## Summary

I'm looking at cleaning up some unnecessary manual property flattening
in React Native and wanted to verify this behaviour is working as
expected, where properties from nested objects will always overwrite
properties from the base object.

## How did you test this change?

Unit tests
2024-04-29 19:57:32 -07:00
Sebastian Silbermann 190cc990e0 Import correct prod version of jsx-dev-runtime for react-server (#28939) 2024-04-27 22:25:25 +02:00
Alex Yang 8090457c77 fix: add react-server condition for react/jsx-dev-runtime (#28921) 2024-04-27 21:45:52 +02:00
Ricky 4ddff7355f Add changelog for 18.3.1 (#28932) 2024-04-26 16:03:03 -04:00
Ricky 95e610da13 Add changelog for 18.3 (#28929)
Fixes https://github.com/facebook/react/issues/28924
2024-04-26 12:45:08 -04:00
Ricky c4083616a2 Create React 19 issue template 2024-04-25 15:32:31 -04:00
Josh Story 94eed63c49 (Land #28798) Move Current Owner (and Cache) to an Async Dispatcher (#28912)
Rebasing and landing https://github.com/facebook/react/pull/28798

This PR was approved already but held back to give time for the sync.
Rebased and landing here without pushing to seb's remote to avoid
possibility of lost updates

---------

Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
2024-04-25 10:40:40 -07:00
Andrew Clark f8a8eac86b Update canary channel label to "beta" (#28905)
During the beta period, canaries will be published as
`19.0.0-beta-<COMMIT_SHA>-<DATE>`. They will also be tagged as `beta`
when published to npm.
2024-04-25 13:14:33 -04:00
Sebastian Silbermann 82d8129e58 Reconciler: Change commitUpdate signature to account for unused updatePayload parameter (#28909) 2024-04-25 19:14:06 +02:00
Andrew Clark d285b3acba Go back to shared refs instance object (#28911)
It turns out we already made refs writable in #25696, which has been in
canary for over a year. The approach in that PR also has the benefit of
being slightly more perf sensitive because it still uses a shared object
until the fiber is mounted. So let's just go back to that.
2024-04-25 13:03:21 -04:00
Jan Kassens ed71a3ad29 Support ref cleanup function for imperative handle refs (#28910)
Support ref cleanup function for imperative handle refs
2024-04-25 12:51:41 -04:00
Jack Pope cf5ab8b8b2 Add descriptions of new methods to the react-reconciler readme (#28750)
Add new reconciler methods since last breaking change to the README
based on usage and comments.

---------

Co-authored-by: Josh Story <josh.c.story@gmail.com>
2024-04-25 09:37:55 -04:00
Andrew Clark c516cefc7d warn -> error for Test Renderer deprecation (#28904)
We use `console.error` for deprecations. `console.warn` is for less
critical issues, like performance anti-patterns.
2024-04-24 14:54:39 -04:00