Commit Graph
19463 Commits
Author SHA1 Message Date
Jack Pope 59fe6c3ac1 Remove RTR from StrictEffectsMode-test (#28387)
## Summary

Cleaning up internal usage of ReactTestRenderer

## How did you test this change?

`yarn test
packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js`
2024-02-21 15:17:52 -05:00
Sebastian Markbåge c0274063f0 [Flight] Prefix Replayed Console Logs with a Badge (#28403)
Builds on top of #28384.

This prefixes each log with a badge similar to how we badge built-ins
like "ForwardRef" and "Memo" in the React DevTools. The idea is that we
can add such badges in DevTools for Server Components too to carry on
the consistency.

This puts the "environment" name in the badge which defaults to
"Server". So you know which source it is coming from.

We try to use the same styling as the React DevTools. We use light-dark
mode where available to support the two different color styles, but if
it's not available I use a fixed background so that it's always readable
even in dark mode.

In Terminals, instead of hard coding colors that might not look good
with some themes, I use the ANSI color code to flip
background/foreground colors in that case.

In earlier commits I had it on the end of the line similar to the
DevTools badges but for multiline I found it better to prefix it. We
could try various options tough.

In most cases we can use both ANSI and the `%c` CSS color specifier,
because node will only use ANSI and hide the other. Chrome supports both
but the color overrides ANSI if it comes later (and Chrome doesn't
support color inverting anyway). Safari/Firefox prints the ANSI, so it
can only use CSS colors.

Therefore in browser builds I exclude ANSI.

On the server I support both so if you use Chrome inspector on the
server, you get nice colors on both terminal and in the inspector.

Since Bun uses WebKit inspector and it prints the ANSI we can't safely
emit both there. However, we also can't emit just the color specifier
because then it prints in the terminal.
https://github.com/oven-sh/bun/issues/9021 So we just use a plain string
prefix for now with a bracket until that's fixed.

Screen shots:

<img width="758" alt="Screenshot 2024-02-21 at 12 56 02 AM"
src="https://github.com/facebook/react/assets/63648/4f887ffe-fffe-4402-bf2a-b7890986d60c">
<img width="759" alt="Screenshot 2024-02-21 at 12 56 24 AM"
src="https://github.com/facebook/react/assets/63648/f32d432f-f738-4872-a700-ea0a78e6c745">
<img width="514" alt="Screenshot 2024-02-21 at 12 57 10 AM"
src="https://github.com/facebook/react/assets/63648/205d2e82-75b7-4e2b-9d9c-aa9e2cbedf39">
<img width="489" alt="Screenshot 2024-02-21 at 12 57 34 AM"
src="https://github.com/facebook/react/assets/63648/ea52d1e4-b9fa-431d-ae9e-ccb87631f399">
<img width="516" alt="Screenshot 2024-02-21 at 12 58 23 AM"
src="https://github.com/facebook/react/assets/63648/52b50fac-bec0-471d-a457-1a10d8df9172">
<img width="956" alt="Screenshot 2024-02-21 at 12 58 56 AM"
src="https://github.com/facebook/react/assets/63648/0096ed61-5eff-4aa9-8a8a-2204e754bd1f">
2024-02-21 14:59:08 -05:00
Sebastian Markbåge 9a5b6bd84f [Flight] Instrument the Console in the RSC Environment and Replay Logs on the Client (#28384)
When developing in an RSC environment, you should be able to work in a
single environment as if it was a unified environment. With thrown
errors we already serialize them and then rethrow them on the client.

Since by default we log them via onError both in Flight and Fizz, you
can get the same log in the RSC runtime, the SSR runtime and on the
client.

With console logs made in SSR renders, you typically replay the same
code during hydration on the client. So for example warnings already
show up both in the SSR logs and on the client (although not guaranteed
to be the same). You could just spend your time in the client and you'd
be fine.

Previously, RSC logs would not be replayed because they don't hydrate.
So it's easy to miss warnings for example.

With this approach, we replay RSC logs both during SSR so they end up in
the SSR logs and on the client. That way you can just stay in the
browser window during normal development cycles. You shouldn't have to
care if your component is a server or client component when working on
logical things or iterating on a product.

With this change, you probably should mostly ignore the Flight log
stream and just look at the client or maybe the SSR one. Unless you're
digging into something specific. In particular if you just naively run
both Flight and Fizz in the same terminal you get duplicates. I like to
run out fixtures `yarn dev:region` and `yarn dev:global` in two separate
terminals.

Console logs may contain complex objects which can be inspected. Ideally
a DevTools inspector could reach into the RSC server and remotely
inspect objects using the remote inspection protocol. That way complex
objects can be loaded on demand as you expand into them. However, that
is a complex environment to set up and the server might not even be
alive anymore by the time you inspect the objects. Therefore, I do a
best effort to serialize the objects using the RSC protocol but limit
the depth that can be rendered.

This feature is only own in dev mode since it can be expensive.

In a follow up, I'll give the logs a special styling treatment to
clearly differentiate them from logs coming from the client. As well as
deal with stacks.
2024-02-21 14:47:55 -05:00
Noah Lemen 41b3c31bcb remove RTR from ReactCacheOld-test (#28409)
## Summary

swaps `react-test-renderer` for `react-noop-rendererer` in
ReactCacheOld-test

## How did you test this change?

`yarn test-www ReactCacheOld`
2024-02-21 13:31:43 -05:00
Andrew Clark dc30644ca7 Convert string ref props to callback props (#28398)
When enableRefAsProp is on, we should always use the props as the source
of truth for refs. Not a field on the fiber.

In the case of string refs, this presents a problem, because string refs
are not passed around internally as strings; they are converted to
callback refs. The ref used by the reconciler is not the same as the one
the user provided.

But since this is a deprecated feature anyway, what we can do is clone
the props object and replace it with the internal callback ref. Then we
can continue to use the props object as the source of truth.

This means the internal callback ref will leak into userspace. The
receiving component will receive a callback ref even though the parent
passed a string. Which is weird, but again, this is a deprecated
feature, and we're only leaving it around behind a flag so that Meta can
keep using string refs temporarily while they finish migrating their
codebase.
2024-02-21 11:41:29 -05:00
bubucuo ddd736d258 refactor: remove dead types of fiber (#28405)
The properties `firstEffect` and `lastEffect` of the Fiber are currently
not being used and are considered to be dead code, and can be removed.
2024-02-21 11:17:21 +00:00
dan 353ecd0516 Remove JSX propTypes validation (#28328)
This removes the remaining `propTypes` validation calls, making
declaring `propTypes` a no-op. In other words, React itself will no
longer validate the `propTypes` that you declare on your components.

In general, our recommendation is to use static type checking (e.g.
TypeScript). If you'd like to still run propTypes checks, you can do so
manually, same as you'd do outside React:

```js
import checkPropTypes from 'prop-types/checkPropTypes';

function Button(props) {
  checkPropTypes(Button.propTypes, prop, 'prop', Button.name)
  // ...
}
```

This could be automated as a Babel plugin if you want to keep these
checks implicit. (We will not be providing such a plugin, but someone in
community might be interested in building or maintaining one.)
2024-02-21 11:15:51 +00:00
Sebastian Markbåge 4ea424e63d Capitalize the default Flight environment (#28402)
It's cleaner and more in line with how we style other badges like "Memo"
and "ForwardRef" in DevTools.
2024-02-20 22:30:23 -05:00
Jack Pope 3b260007ed Remove RTR from ReactCreateRef-test (#28386)
## Summary

Cleaning up internal usage of ReactTestRenderer

## How did you test this change?

`yarn test packages/react/src/__tests__/ReactCreateRef-test.js`
2024-02-20 17:49:51 -05:00
Jack Pope 0778f61321 Remove RTR usage from useSubscription-test (#28388)
## Summary

Cleaning up internal usage of ReactTestRenderer

## How did you test this change?

`yarn test
packages/use-subscription/src/__tests__/useSubscription-test.js`
2024-02-20 17:49:26 -05:00
Sebastian Silbermann cefc1c66c1 Remove unused ReactTestUtils from ReactDOMServerIntegration tests (#28379) 2024-02-20 22:49:34 +01:00
Masato Nakamura 51c9146072 Bump actions/checkout (#28383) 2024-02-20 22:46:43 +01:00
Jack Pope 90a0ae1015 Remove RTR from ReactSuspense-test (#28390)
## Summary

Cleaning up internal usage of ReactTestRenderer

## How did you test this change?

`yarn test
packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js`
2024-02-20 15:40:16 -05:00
bubucuo 49441e342f refactor: remove dead code of fiber (#28389)
The `nextEffect` property of the `fiber` is currently not being used and
has become dead code. It can be safely removed.
2024-02-20 14:31:15 -05:00
Sebastian Markbåge 8f012266dc Rename default FlightClientConfigs to FlightClientStreamConfig (#28382)
Since this is more about specifically the streaming protocol and I'll
add other dimensions that don't map 1:1.

E.g. some configs need to be the same across all servers.
2024-02-20 14:24:08 -05:00
Andrew Clark fa2f82addc Pass ref as normal prop (#28348)
Depends on:

- #28317 
- #28320 

---

Changes the behavior of the JSX runtime to pass through `ref` as a
normal prop, rather than plucking it from the props object and storing
on the element.

This is a breaking change since it changes the type of the receiving
component. However, most code is unaffected since it's unlikely that a
component would have attempted to access a `ref` prop, since it was not
possible to get a reference to one.

`forwardRef` _will_ still pluck `ref` from the props object, though,
since it's extremely common for users to spread the props object onto
the inner component and pass `ref` as a differently named prop. This is
for maximum compatibility with existing code — the real impact of this
change is that `forwardRef` is no longer required.

Currently, refs are resolved during child reconciliation and stored on
the fiber. As a result of this change, we can move ref resolution to
happen only much later, and only for components that actually use them.
Then we can remove the `ref` field from the Fiber type. I have not yet
done that in this step, though.
2024-02-20 14:17:41 -05:00
Sebastian Silbermann a515d753ba Annotate legacy mode tests in ReactDOMInput (#28333) 2024-02-20 16:52:49 +01:00
Sebastian Silbermann 1deda7690f Remove ReactTestUtils from ReactDOMComponent (#28334) 2024-02-20 16:52:30 +01:00
Sebastian Silbermann 48ca0e8298 Remove ReactTestUtils from ReactUpdates (#28378) 2024-02-20 16:52:11 +01:00
Sebastian Silbermann 7b196be091 Remove ReactTestUtils from ReactDOM-test (#28377) 2024-02-20 16:51:44 +01:00
Sebastian Silbermann 3c9560b29e Remove ReactTestUtils from ReactComponentLifeCycle (#28376) 2024-02-20 16:51:10 +01:00
Sebastian Silbermann e68431c89f Remove ReactTestUtils from ReactJSXTransformIntegration (#28338) 2024-02-20 16:50:52 +01:00
Sebastian Silbermann 7ab84fb116 Remove usage of ReactTestUtils from ReactFunctionComponent (#28331) 2024-02-20 16:50:34 +01:00
Sebastian Silbermann b559f5fefe Remove ReactTestUtils from refs-test (#28336) 2024-02-20 16:50:17 +01:00
Andrew Clark 5fb2c93f39 Combine createElement and JSX modules (#28320)
Depends on:

- #28317 

---

There's a ton of overlap between the createElement implementation and
the JSX implementation, so I combined them into a single module.

In the actual build output, the shared code between JSX and
createElement will get duplicated anyway, because react/jsx-runtime and
react (where createElement lives) are separate, flat build artifacts.

So this is more about code organization — with a few key exceptions, the
implementations of createElement and jsx are highly coupled.
2024-02-19 22:45:18 -05:00
Andrew Clark ec160f32c2 Combine ReactJSXElementValidator with main module (#28317)
There are too many layers to the JSX runtime implementation. I think
basically everything should be implemented in a single file, so that's
what I'm going to do.

As a first step, this deletes ReactJSXElementValidator and moves all the
code into ReactJSXElement. I can already see how this will help us
remove more indirections in the future.

Next I'm going to do start moving the `createElement` runtime into this
module as well, since there's a lot of duplicated code.
2024-02-19 22:14:29 -05:00
Andrew Clark c820097716 Move all markRef calls into begin phase (#28375)
Certain fiber types may have a ref attached to them. The main ones are
HostComponent and ClassComponent. During the render phase, we check if a
ref was passed to it, and if so, we schedule a Ref effect: `markRef`.

Currently, we're not consistent about whether we call `markRef` in the
begin phase or the complete phase. For some fiber types, I found that
`markRef` was called in both phases, causing redundant work.

After some investigation, I don't believe it's necessary to call
`markRef` in both the begin phase and the complete phase, as long as you
don't bail out before calling `markRef`.

I though that maybe it had to do with the
`attemptEarlyBailoutIfNoScheduledUpdates` branch, which is a fast path
that skips the regular begin phase if no new props, state, or context
were passed. But if the props haven't changed (referentially — the
`memo` and `shouldComponentUpdate` checks happen later), then it follows
that the ref couldn't have changed either. This is true even in the old
`createElement` runtime where `ref` is stored on the element instead of
as a prop, because there's no way to pass a new ref to an element
without also passing new props. You might argue this is a leaky
assumption, but since we're shifting ref to be just a regular prop
anyway, I think it's the correct way to think about it going forward.

I think the pattern of calling `markRef` in the complete phase may have
been left over from an earlier iteration of the implementation before
the bailout logic was structured like it is today.

So, I removed all the `markRef` calls from the complete phase. In the
case of ScopeComponent, which had no corresponding call in the begin
phase, I added one.

We already had a test that asserted that a ref is reattached even if the
component bails out, but I added some new ones to be extra safe.

The reason I'm changing this this is because I'm working on a different
change to move the ref handling logic in `coerceRef` to happen in render
phase of the component that accepts the ref, instead of during the
parent's reconciliation.
2024-02-19 21:06:43 -05:00
Sebastian Markbåge 2e84e16299 [Flight] Better error message if you pass a function as a child to a client component (#28367)
Similar to #28362 but if you pass it to a client component.
2024-02-19 12:36:16 -05:00
Sebastian Markbåge 65a0e2b25e [Flight] Warn if this argument is passed to .bind of a Server Reference (#28380)
This won't ever be serialized and is likely just a mistake.

This should be covered by the "use server" compiler since it ensures
that something that accepts a "this" won't be allowed to compile and if
it doesn't accept it, TypeScript should ideally forbid it to be passed.

So maybe this is unnecessary.
2024-02-19 11:50:13 -05:00
Sebastian Markbåge 017397d7d3 Recover from SSR error in Flight fixture (#28368)
If an error happens before the shell, we need to handle it. In this case
we choose the strategy of rendering a blank document and client
rendering the app. Which will intentionally have a hydration mismatch.
2024-02-19 11:50:04 -05:00
Sebastian Markbåge 9444c51c7e [Flight] Allow a Server Reference to be registered twice (#28343)
It's possible for the same function instance to appear more than once in
the same graph or even the same file.

Currently this errors on trying to reconfigure the property but it
really doesn't matter which one wins. First or last.

Regardless there will be an entry point generated that can get them.
2024-02-19 11:49:38 -05:00
Sebastian Markbåge c323f8290c Encode better error messages when part of the context is a client reference (#28355)
Alternative to #28354.

If a client reference is one of the props being describes as part of
another error, we call toString on it, which errors.

We should error explicitly when a Symbol prop is extracted.

However, pragmatically I added the toString symbol tag even though we
don't know what the real tostring will be but we also lie about the
typeof.

We can however in addition to this give it a different description
because describing this property as an object isn't quite right.

We probably could extract the export name but that's kind of renderer
specific and I just added this shared module to Fizz which doesn't have
that which is unfortunate an consequence.

For default exports we don't have a good name of what the alias was in
the receiver. Could maybe call it "default" but for now I just call it
"client".
2024-02-19 11:49:25 -05:00
Sebastian Silbermann 59831c98cf Improve stack trace when gated test fails (#28374) 2024-02-18 18:17:02 +01:00
Sebastian Markbåge c1fd2a91b1 Include the function name for context on invalid function child (#28362)
Also warn for symbols.

It's weird because for objects we throw a hard error but functions we do
a dev only check. Mainly because we have an object branch anyway.

In the object branch we have some built-ins that have bad errors like
forwardRef and memo but since they're going to become functions later, I
didn't bother updating those. Once they're functions those names will be
part of this.
2024-02-17 16:41:59 -05:00
Sebastian Silbermann fef30c2e04 Fix crash running yarn flags --sort flag (#28344) 2024-02-17 15:28:35 +01:00
Sebastian Silbermann 62a9c7db18 Annotate legacy mode test in ReactDOMSingletonComponents (#28339)
These are mainly regression tests for legacy root.
2024-02-17 15:28:18 +01:00
Sebastian Markbåge 6a44f352ec Consume the RSC stream twice in the Flight fixture (#28353)
We have an unresolved conflict where the Flight client wants to execute
inside Fizz to emit side-effects like preloads (which can be early) into
that stream. However, the FormState API requires the state to be passed
at the root, so if you're getting that through the RSC payload it's a
Catch 22.

#27314 used a hack to mutate the form state array to fill it in later,
but that doesn't actually work because it's not always an array. It's
sometimes null like if there wasn't a POST. This lead to a bunch of
hydration errors - which doesn't have the best error message for this
case neither. It probably should error with something that specifies
that it's form state.

This fixes it by teeing the stream into two streams and consuming it
with two Flight clients. One to read the form state and one to emit
side-effects and read the root.
2024-02-16 18:25:09 -05:00
Joe Savona d6406d8360 Validate hook calls in object methods
Adds some test cases for hook calls in object methods. Initially we didn't catch 
these because InferTypes doesn't actually visit ObjectMethod bodies. Once we fix 
that we correctly reject these examples.
2024-02-16 11:27:52 -08:00
Joe Savona 9c419dfd80 Disallow calling hooks in functions
> Don’t call Hooks inside loops, conditions, or nested functions 

Per https://react.dev/warnings/invalid-hook-call-warning#breaking-rules-of-hooks 
it is invalid to call hooks inside function expressions. We now validate this by 
default, i'll verify internally before landing. 

Note the validation is somewhat more conservative and we only disallow known 
hook calls here, this seems like a reasonable tradeoff but i'm open to 
suggestions. We could reuse the same known/potential hook mechanism here but it 
would take some more refactoring.
2024-02-16 11:00:56 -08:00
Joe Savona a4234bcfbf infer mode only compiles component/hook decls
Forks the logic from Program.ts, letting us customize what
gets compiled.
2024-02-17 17:37:00 -08:00
Joe Savona ca3d16c5ef Enable hook syntax support
Updates the compiler to understand Flow hook syntax. Like component syntax, in 
infer mode hooks are compiled by default unless opted out. 

Looking ahead, i can imagine splitting up our compilation modes as follows: 

* Annotations: opt-in explicitly 

* Declarations: annotations + component/hook declarations 

* Infer: annotations, component/hook declarations, + component/hook-like 
functions 

This also suggest an alternative annotation strategy: "use react" (or "use 
component" / "use hook") as a general way to tell the compiler that a function 
is intended for React. Then opting out of memoization could do "use 
react(nomemo)".
2024-02-17 17:31:47 -08:00
Joe Savona 1e3f9130f3 Rewrite reactive scopes to computed with lambda
Updates LowerReactiveScopes to rewrite to a ReactiveFunctionValue
(ReactiveFunction-based) instead of a FunctionExpression (HIR-based). This lets
us include terminals and even nested reactive scopes in the result.
2024-02-16 14:59:01 -08:00
Joe Savona 191064b55c Add ReactiveFunctionValue variant
Per the previous PR, we don't have a way to rewrite an arbitrary subset of a
ReactiveFunction into a function expression, since FunctionExpression's contents
is still in HIR.

While long-term our plan is to move to HIR everywhere, this PR adds a stopgap of
adding a ReactiveFunctionValue variant of ReactiveValue. As a reminder,
ReactiveValue is a union of (HIR) InstructionValue | SequenceExpression |
LogicalExpression | ConditionalExpression.

For now i did a first stab at the visitors and transforms with the idea that:

* By default, visitors/transforms _don't_ look into these function expressions,
since we didn't previously traverse into (HIR-based) FunctionExpression either

* But there is a visitor/transform method that you can override if you need to.
2024-02-16 14:59:00 -08:00
Joe Savona 03874a29b3 Repro for needing function body rewriting in ReactiveFunction phase
Adds an example demonstrating why we need the ability to rewrite parts of a
ReactiveFunction into a function expression. Here, the reactive scope needs to
contain an `if` terminal, but we can't put a ReactiveIfTerminal inside a
function expression, since that expects HIR.

There are two main paths forward:

* Use HIR everywhere. I wrote this up and we're all agreed, it's just a bunch of
work.

* Add an alternative FunctionExpression variant to ReactiveFunction

For now i'm going to take the second route.
2024-02-16 14:58:59 -08:00
Sathya Gunasekaran 770ca4ab3e [Babel] Add support for "use memo"
We want to start moving away from "Forget", so this PR adds support "use memo" 
and "use no memo" 

I've left "use forget" and "use no forget" directives unchanged for now, as we 
need to migrate existing users first and then come back and delete support for 
these directives.
2024-02-19 17:48:49 +00:00
Jack Pope ef72271c2d Add useModernStrictMode as dynamic flag on www (#28346)
## Summary

Preparing modern strict mode rollout with dynamic feature flag

## How did you test this change?

![Screenshot 2024-02-15 at 10 09
49 AM](https://github.com/facebook/react/assets/8965173/9e90efc2-3578-4e63-ae2c-63d4a4e194b3)
2024-02-16 11:21:35 -05:00
Josh Story a9cc32511a stash the component stack on the thrown value and reuse (#25790)
ErrorBoundaries are currently not fully composable. The reason is if you
decide your boundary cannot handle a particular error and rethrow it to
higher boundary the React runtime does not understand that this throw is
a forward and it recreates the component stack from the Boundary
position. This loses fidelity and is especially bad if the boundary is
limited it what it handles and high up in the component tree.

This implementation uses a WeakMap to store component stacks for values
that are objects. If an error is rethrown from an ErrorBoundary the
stack will be pulled from the map if it exists. This doesn't work for
thrown primitives but this is uncommon and stashing the stack on the
primitive also wouldn't work
2024-02-15 20:44:44 -08:00
Sebastian Markbåge 2ba1b78569 Downgrade pmmmwh/react-refresh-webpack-plugin in the Flight fixture (#28352)
The newer version triggers an error due to require() not being compiled.

This was upgraded in #27328. I'm not sure why that was needed. Maybe it
was just because it was allowed by the caret and something else upgraded
but I haven't been able to make it work with the newer version. So I'll
just pin it.
2024-02-15 22:23:30 -05:00
dan fea900e454 Remove non-JSX propTypes checks (#28326)
Removes all `propTypes` validation called from outside the JSX
factories. Haven't touched JSX.

Tests that verify related behavior are stripped down to the
non-`propTypes` logic.
2024-02-16 00:35:22 +00:00
Jan Kassens 530f2c293d Add test fixture showing invalid location
Add test fixture showing invalid location 

The error should be on the node mutating the output, not in the read location.
2024-02-15 19:00:21 -05:00