Add code frame to snap errors
This should make it easier (possible) to see if errors point at the right lines.
No idea why I had to add 1 to the column, you'd think it's all babel-standard
(whatever it is) and there wouldn't be off by one errors, but I'm not quite in
the mood to debug babel issues more then necessary right now...
This caused a build error when Forget was used in an Expo app as the
react-forget-runtime package was itself being compiled with Forget. This broke
Metro as metro serializes modules to iifes, but the import syntax that was
injected by the useMemoCachePolyfill flag was left behind
In practice I don't think the runtime package needs to ever be compiled by
Forget, so this PR opts out the whole file. This would also prevent builds from
breaking if someone decided to use the "all" compilation mode.
Test plan: Ran the expo app and verified that it now builds with no errors
Currently we only allow adding the directive to function bodies, but there may
be cases where we want to always opt out an entire module from being compiled by
Forget
The `reference` that is passed into `registerServerReference` can be a
plain function. It does not need to have the three additonal properties
of a `ServerRefeference`. In fact, adding these properties (plus `bind`)
is precisely what `registerServerReference` does.
Same as #28327 but for Fizz.
One thing that's weird about this recoverable error is that we don't
send the regular stack for it, just the component stack it seems. This
is missing some potential information and if we move toward integrated
since stacks it would be one thing.
A labeled block will generally end with an implicit break out of the label.
However, if there are no _explicit_ breaks to the label, we'll end up with a
ReactiveFunction along the lines of:
```
bb1: {
...instructions with no explicit `break bb1`...
(implicit) break;
}
```
The `PruneUnusedLabels` pass removes such unused labels, inlining the content of
label terminal into the surrounding block. However, we weren't pruning the
`break`! This wasn't a problem in practice since codegen, and future passes,
would just ignore this. But it's more correct to go and find these unnecessary
implicit breaks and prune them, which this PR does.
Again, this shouldn't have any impact other than producing cleaner
ReactiveFunction data during debugging.
Also deals with symbols. Alternative to #28312.
We currently always normalize rejections or thrown values into `Error`
objects. Partly because in prod it'll be an error object and you
shouldn't fork behavior on knowing the value outside a digest. We might
want to even make the message always opaque to avoid being tempted and
then discover in prod that it doesn't work.
However, we do include the message in DEV.
If this is a non-Error object we don't know what the properties mean.
Ofc, we don't want to include too much information in the rendered
string, so we use the general `describeObjectForErrorMessage` helper.
Unfortunately it's pretty conservative about emitting values so it's
likely to exclude any embedded string atm. Could potentially expand it a
bit.
We could in theory try to serialize as much as possible and re-throw the
actual object to allow for inspection to be expanded inside devtools
which is what I plan on for consoles, but since we're normalizing to an
Error this is in conflict with that approach.
Continuing on my quest to clean up our feature flags, the logic for merging
consecutive feature flags is stable. Let's remove
`@enableMergeConsecutiveScopes` since this is enabled everywhere.
Some components stop being components over time and are used as regular
functions instead, but they may have lingering hook calls. Those hook calls make
it so the capitalized function calling them do not error (they appear to be a
function to existing eslint rules), but they are nonetheless unsafe to memoize.
This diff adds a conservative option to bail out on all capitalized function
calls.
There are a handful of known-non-component capitalized functions, like
`Boolean`, `String`, and `Number`. This diff also adds the ability to supply
capitalized function names that should not be considered in this analysis.
I added three tests:
1. Ensure an error occurs in the obvious case
2. Ensure an error occurs when the value is aliased simply
3. Ensure the allowlist works
This is my first commit so please go hard on me. I was unsure about where this
code should live, so please nitpick.
In preparation for https://github.com/facebook/react/pull/28207.
These tests aren't actually testing propTypes, they just use them to
verify we can display a meaningful component name. We've mostly moved
away from warnings that display component names directly in favor of
component stacks. So let's just replace these with tests asserting the
component names show up in stacks.
Part of https://github.com/facebook/react/pull/28207, this is easy to
land in isolation.
The approach I'm taking is slightly different — instead of leaving
validation on for legacy context, I disable the validation (it's
DEV-only) and leave just the parts that drive the runtime logic. I.e.
`contexTypes` and `childContextTypes` *values* are now ignored, the keys
are used just like before.
This option was added defensively but it's not needed. There's no cost
to including it always.
I suspect this optional was added mainly to avoid needing to update
tests. That's not a reason to have an unnecessary public API though.
We have a praxis for dealing with source location in tests to avoid them
failing tests. I also ported them to inline snapshots so that additions
to the protocol isn't such a pain.
All our sources are considered third party and should be hidden in stack
traces unless expanded. Our internals aren't actionable anyway.
This doesn't really do much without tooling that actually forwards this
to new generated source maps, in which case they probably just add them
to ignorelist anyway.
Previously, `<Context>` was equivalent to `<Context.Consumer>`. However,
since the introduction of Hooks, the `<Context.Consumer>` API is rarely
used. The goal here is to make the common case cleaner:
```js
const ThemeContext = createContext('light')
function App() {
return (
<ThemeContext value="dark">
...
</ThemeContext>
)
}
function Button() {
const theme = use(ThemeContext)
// ...
}
```
This is technically a breaking change, but we've been warning about
rendering `<Context>` directly for several years by now, so it's
unlikely much code in the wild depends on the old behavior. [Proof that
it warns today (check
console).](https://codesandbox.io/p/sandbox/peaceful-nobel-pdxtfl)
---
**The relevant commit is 5696782b428a5ace96e66c1857e13249b6c07958.** It
switches `createContext` implementation so that `Context.Provider ===
Context`.
The main assumption that changed is that a Provider's fiber type is now
the context itself (rather than an intermediate object). Whereas a
Consumer's fiber type is now always an intermediate object (rather than
it being sometimes the context itself and sometimes an intermediate
object).
My methodology was to start with the relevant symbols, work tags, and
types, and work my way backwards to all usages.
This might break tooling that depends on inspecting React's internal
fields. I've added DevTools support in the second commit. This didn't
need explicit versioning—the structure tells us enough.
There are three parts to an RSC set up:
- React
- Bundler
- Endpoints
Most customizability is in the bundler configs. We deal with those as
custom builds.
To create a full set up, you need to also configure ways to expose end
points for example to call a Server Action. That's typically not
something the bundler is responsible for even though it's responsible
for gathering the end points that needs generation. Exposing which
endpoints to generate is a responsibility for the bundler.
Typically a meta-framework is responsible for generating the end points.
There's two ways to "call" a Server Action. Through JS and through a
Form. Through JS we expose the `callServer` callback so that the
framework can call the end point.
Forms by default POST back to the current page with an action serialized
into form data, which we have a decoder helper for. However, this is not
something that React is really opinionated about just like we're not
opinionated about the protocol used by callServer.
This exposes an option to configure the encoding of the form props.
`encodeFormAction` is to the SSR is what `callServer` is to the Browser.
Alternative to #28295.
Instead of stashing all of the Usables eagerly, we can extract them by
replaying the render when we need them like we do with any other hook.
We already had an implementation of `use()` but it wasn't quite
complete.
These can also include further DebugInfo on them such as what Server
Component rendered the Promise or async debug info. This is nice just to
see which use() calls were made in the side-panel but it can also be
used to gather everything that might have suspended.
Together with https://github.com/facebook/react/pull/28286 we cover the
case when a Promise was used a child and if it was unwrapped with use().
Notably we don't cover a Promise that was thrown (although we do support
that in a Server Component which maybe we shouldn't). Throwing a Promise
isn't officially supported though and that use case should move to the
use() Hook.
The pattern of conditionally suspending based on cache also isn't really
supported with the use() pattern. You should always call use() if you
previously called use() with the same input. This also ensures that we
can track what might have suspended rather than what actually did.
One limitation of this strategy is that it's hard to find all the places
something might suspend in a tree without rerendering all the fibers
again. So we might need to still add something to the tree to indicate
which Fibers may have further debug info / thenables.
That way we can use it for debug information like component stacks and
DevTools. I used an extra stack argument in Child Fiber to track this as
it's flowing down since it's not just elements where we have this info
readily available but parent arrays and lazy can merge this into the
Fiber too. It's not great that this is a dev-only argument and I could
track it globally but seems more likely to make mistakes.
It is possible for the same debug info to appear for multiple child
fibers like when it's attached to a fragment or a lazy that resolves to
a fragment at the root. The object identity could be used in these
scenarios to infer if that's really one server component that's a parent
of all children or if each child has a server component with the same
name.
This is effectively a public API because you can use it to stash
information on Promises from a third-party service - not just Server
Components. I started outline the types for this for some things I was
planning to add but it's not final.
I was also planning on storing it from `use(thenable)` for when you
suspend on a Promise. However, I realized that there's no Hook instance
for those to stash it on. So it might need a separate data structure to
stash the previous pass over of `use()` that resets each render.
No tests yet since I didn't want to test internals but it'll be covered
once we have debugging features like component stacks.
This pains me because `React.Children` is really already
pseudo-deprecated.
`React.Children` takes any children that `React.Node` takes. We now
support Lazy and Thenable in this position elsewhere, but it errors in
`React.Children`.
This becomes an issue with async Server Components which can resolve
into a Lazy and in the future Lazy will just become Thenables. Which
causes this to error.
There are a few different semantics we could have:
1) Error like we already do (#28280). `React.Children` is about
introspecting children. It was always sketchy because you can't
introspect inside an abstraction anyway. With Server Components we fold
away the components so you can actually introspect inside of them kind
of but what they do is an implementation detail and you should be able
to turn it into a Client Component at any point. The type of an Element
passing the boundary actually reduces to `React.Node`.
2) Suspend and unwrap the Node (this PR). If we assume that Children is
called inside of render, then throwing a Promise if it's not already
loaded or unwrapping would treat it as if it wasn't there. Just like if
you rendered it in React. This lets you introspect what's inside which
isn't really something you should be able to do. This isn't compatible
with deprecating throwing-a-Promise and enable static compilation like
`use()` does. We'd have to deprecate `React.Children` before doing that
which we might anyway.
3) Wrap in a Fragment. If a Server Component was instead a Client
Component, you couldn't introspect through it anyway. Another
alternative might be to let it pass through but then it wouldn't be
given a flat key. We could also wrap it in a Fragment that is keyed.
That way you're always seeing an element. The issue with this solution
is that it wouldn't see the key of the Server Component since that gets
forwarded to the child that is yet to resolve. The nice thing about that
strategy is it doesn't depend on throw-a-Promise but it might not be
keyed correctly when things move.
A Flight Server can be a consumer of a stream from another Server. In
this case the meta data is attached to debugInfo properties on lazy,
Promises, Arrays or Elements that might in turn get forwarded to the
next stream. In this case we want to forward this debug information to
the client in the stream.
I also added a DEV only `environmentName` option to the Flight Server.
This lets you name the server that is producing the debug info so that
you can trace the origin of where that component is executing. This
defaults to `"server"`. DevTools could use this for badges or different
colors.
The hook guards are incompatible with using a forget-runtime. Specifically,
forget-runtime needs to make a call to `useState()` or some other hook to attach
data to the fiber, but all the builtin hooks are overridden to disallow calling
them outside of explicit boundaries. We'd either have to wrap the useMemoCache
call in a push/pop to allow it to call other hooks, or as in this PR, just move
it outside the enforcement.
These validations needs to be able to transitively check for violations within
function expressions, without immediately erroring. So the inner "-Impl" helpers
return a Result. But the outer, exported validate functions don't need to return
a Result, especially since TS has no Rust-style enforcement that return values
are actually used. Unwrapping within the validation means the caller can't
forget to do so and inadvertently silence the errors.
I had split this up from the main validation since function validation was less
precise; now that previous PRs fix the false positives we can remove this extra
flag.
This pass doesn't really make sense in light of
`@enableTransitivelyFreezeFunctionExpressions`. The original idea of
ValidateFrozenLambdas was that trying to pass a "mutable" lambda to a frozen
value was invalid. But since then we've realized that the better heuristic is
that freezing a lambda is transitive.
Rewrites the validation to not rely on the mutable range of functions to
determine whether they are called or not, since the range can be extended for
other reasons (they happen to reference a mutable value that is mutated later,
even though the function isn't called during render).
Instead we use the same approach as validateNoSetStateInRender, explicitly
tracking references to function expressions that access refs, and checking if
those function expressions appear to be called. This can have false negatives,
as with the setState validation, but catches lots of obviously incorrect code
without false positives.
Fixes T178003134. Previously we did not check whether values reassigned during a
destructuring assignment were context variables. This would either miscompile,
or as of my fix earlier in #2579, would fail validation. Specifically, this
happened on AssignmentEpression with an object/array pattern lvalue, where the
pattern contained an identifier that is a context variable.
This is now fixed: we track whether the outermost assignment is a normal
assignment or destructuring, and force destructuring to a temporary whenever the
identifier is a context variable. We apply the same logic to variable
declarations that are destructuring to a context variable.
---
I recall adding the navigator override because some React library file had done
an unconditional access, but this doesn't seem to be the case anymore.
Regardless, newer versions of nodejs comes with a global `navigator` [see
thread](https://github.com/nodejs/node/issues/39540) that error on writes
Turn this on
Edited: ope, nvm
<details>
Looks like there's still an outstanding issue with this. The original PR
turned off a strict effects test, which causes a stray
`componentWillUnmount` to fire.
https://github.com/facebook/react/commit/5d1ce651393524639a3b4b1e861a0413a4d25629#diff-19df471970763c4790c2cc0811fd2726cc6a891b0e1d5dedbf6d0599240c127aR70
Before:
```js
expect(log).toEqual([
'constructor',
'constructor',
'getDerivedStateFromProps',
'getDerivedStateFromProps',
'render',
'render',
'componentDidMount',
]);
```
After:
```js
expect(log).toEqual([
'constructor',
'constructor',
'getDerivedStateFromProps',
'getDerivedStateFromProps',
'render',
'render',
'componentDidMount',
'componentWillUnmount',
'componentDidMount',
]);
```
So there's a bug somewhere
</details>
Fixes the one case discovered in the previous PR; for AssignmentExpression we
correctly lowered the store instruction to a local/context, but then always used
a `LoadLocal` to read the result back.
The load instruction appears like it might be dangling - i think what was
happening is that DCE cleaned up the unused LoadLocal whereas it leaves the
LoadContext alone. But this works for now, we can always clean up the extra
instruction later since this case isn't too common.
Validates that all references to a variable (pre-SSA) are consistently "local"
references or "context" references. Ie, if a variable is declared as
DeclareContext, any accesses must be eg LoadContext or StoreContext, not
LoadLocal/StoreLocal. This will help with the issue from #2577 (assuming that we
know a variable _is_ a context variable) but also provides a more precise
bailout for an existing case with destructuring assignment to a context
variable.