Stacked on #34625.
This is a nice way to step through the timeline and simulate the visuals
on screen as you do it. It's also convenient to step through one at a
time, especially with the forwards button.
However, the secondary purpose of this is that it helps anchor the UI
visually as something like a timeline like in a video so that the
timeline itself becomes more identifiable.
https://github.com/user-attachments/assets/cb367c8e-9efb-4a00-a58e-4579be20beb8
The settings dialog appears on all tabs and should be reachable from
Suspense tab too. It's a bit weird because it's not contextual to the
tab and it shows you whatever your last settings tab was opened. Maybe
it should default to opening to the current tab's settings?
There aren't any Suspense specific settings yet but there definitely
will be. We could move the "Show all" into settings but it might be
frequently that you want to check why something isn't suspending a
Suspense boundary or test SSR streaming.
However, the general settings still apply to the Suspense tab. E.g.
switching dark/light mode.
<img width="857" height="233" alt="Screenshot 2025-09-27 at 12 35 05 PM"
src="https://github.com/user-attachments/assets/4a38e94f-2074-4dce-906b-9a1c40bccb9b"
/>
When forcing suspense/error we're doing that by scheduling a sync update
on the fiber. Resuspending a Suspense boundary can only happen sync
update so that makes sense. Erroring also forces a sync commit. This
means that no View Transitions fire.
However, unsuspending (and dismissing an error dialog) can be async so
the reveal should be able to be async.
This adds another hook for scheduling using the Retry lane. That way
when you play through a reveal sequence of Suspense boundaries (like
playing through the timeline), it'll run the animations that would've
ran during a loading sequence.
It's possible for the children to overflow the bounding rect of the root
in general when they overflow in the DOM. However even when it doesn't
overflow in the DOM, the bounding rect of the root can shrink while the
content is suspended. In fact, it's very likely.
Originally I thought we didn't need to consider this recursively because
document scrolling takes absolute positioned content into account but
because we're using nested overflow scrolling, we have to manually
compute this.
One thing that always bothered me is that the collapse buttons on either
side of the toolbar looks like left/right buttons which would conflict
with some steps buttons I plan to add. Another issue is that we'll need
to add more tool buttons to the top and probably eventually a Search
field. Ideally this whole section should line up vertically with the
height of the title row.
I also realized that all UIs that have some kind of timeline control
(and play/pause/skip) do that in the bottom below the content. E.g.
music players and video players all do that. We're better off playing
into that structure since that's the UI analogy we're going for here.
Makes it clearer what the weird timeline is for.
By moving it to the bottom it also frees up the top for the collapse
buttons and more controls.
__Horizontal__
<img width="794" height="809" alt="Screenshot 2025-09-26 at 3 40 35 PM"
src="https://github.com/user-attachments/assets/dacad9c4-d52f-4b66-9585-5cc74f230e6f"
/>
__Vertical__
<img width="570" height="812" alt="Screenshot 2025-09-26 at 3 40 53 PM"
src="https://github.com/user-attachments/assets/db225413-849e-46f1-b764-8fbd08b395c4"
/>
As titled. This adds dev-only debugging information to Fizz / Flight
that could be used for tracking Promise's stack traces in "suspended by"
section of DevTools.
Bumps `useEffectEvent` from `@experimental` to `@canary`. Removes the
`experimental_` prefix from the export.
## TODO
- [ ] Update useEffectEvent reference page and Canary badging in docs:
https://github.com/reactjs/react.dev/pull/8025
Tracks the environment names of the I/O in each SuspenseNode and sent it
to the front end when the suspenders change.
In the front end, every child boundary should really be treated as it
has all environment names of the parents too since they're blocked by
the parent too. We could do this tracking on backend but if there's ever
one added on the root would need to be send for every child.
This lets us highlight which subtrees are blocked by content on the
server.
---------
Co-authored-by: Sebastian "Sebbie" Silbermann <silbermann.sebastian@gmail.com>
When there are no named Activities we should hide the tree side panel
(and the button to show it). Since it's not implemented yet there are
never any ones so it's always hidden.
In Fizz and Fiber we emit hints for suspensey images and CSS as soon as
we discover them during render. At the beginning of the stream. This
adds a similar capability when a Host Component is known to be a Host
Component during the Flight render.
The client doesn't know that these resources are in the payload until it
parses that particular component which is lazy. So they need to be
hoisted with hints. We detect when these are rendered during Flight and
add them as hints. That allows you to consume a Flight payload to
preload prefetched content without having to render it.
`<link rel="preload">` can be hoisted more or less as is.
`<link rel="stylesheet">` we preload but we don't actually insert them
anywhere until they're rendered. We do these even for non-suspensey
stylesheets since we know that when they're rendered they're going to
start loading even if they're not immediately used. They're never lazy.
`<img src>` we only preload if they follow the suspensey image pattern
since otherwise they may be more lazy e.g. by if they're in the
viewport. We also skip if they're known to be inside `<picture>`. Same
as Fizz. Ideally this would preload the other `<source>` but it's
tricky.
The downside of this is that you might conditionally render something in
only one branch given a client component. However, in that case you're
already eagerly fetching the server component's data in that branch so
it's not too much of a stretch that you want to eagerly fetch the
corresponding resources as well. If you wanted it to be lazy, you
should've done a lazy fetch of the RSC.
We don't collect hints when any of these are wrapped in a Client
Component. In those cases you might want to add your own preload to a
wrapper Shared Component.
Everything is skipped if it's known to be inside `<noscript>`.
Note that the format context is approximate (see #34601) so it's
possible for these hints to overfetch or underfetch if you try to trick
it. E.g. by rendering Server Components inside a Client Component that
renders `<noscript>`.
---------
Co-authored-by: Josh Story <josh.c.story@gmail.com>
There was a bug in the Compiler Playground related to the "Show
Internals" toggle due to a useEffect that was causing the tab names to
flicker from a rerender. Rewritten instead with a `<Suspense>` boundary
+ `use`.
Flight doesn't have any semantically sound notion of a parent context.
That's why we removed Server Context. Each root can really start
anywhere in the tree when you refetch subtrees. Additionally when you
dedupe elements they can end up in multiple different parent contexts.
However, we do have a DEV only version of this with debugTask being
tracked for the nearest parent element to track the context of
properties inside of it.
To apply certain DOM specific hints and optimizations when you render
host components we need some information of the context. This is usually
very local so doesn't suffer from the likelihood that you refetch in the
middle. We'll also only use this information for optimistic hints and
not hard semantics so getting it wrong isn't terrible.
```
<picture>
<img />
</picture>
<noscript>
<p>
<img />
</p>
</noscript>
```
For example, in these cases we should exclude preloading the image but
we have to know if that's the scope we're in.
We can easily get this wrong if they're split or even if they're wrapped
in client components that we don't know about like:
```
<NoScript>
<p>
<img />
</p>
</NoScript>
```
However, getting it wrong in either direction is not the end of the
world. It's about covering the common cases well.
We should favor outlining a boundary if it contains Suspensey CSS or
Suspensey Images since then we can load that content separately and not
block the main content. This also allows us to animate the reveal.
For example this should be able to animate the reveal even though the
actual HTML content isn't large in this case it's worth outlining so
that the JS runtime can choose to animate this reveal.
```js
<ViewTransition>
<Suspense>
<img src="..." />
</Suspense>
</ViewTransition>
```
For Suspensey Images, in Fizz, we currently only implement the suspensey
semantics when a View Transition is running. Therefore the outlining
only applies if it appears inside a Suspense boundary which might
animate. Otherwise there's no point in outlining. It is also only if the
Suspense boundary itself might animate its appear and not just any
ViewTransition. So the effect is very conservative.
For CSS it applies even without ViewTransition though, since it can help
unblock the main content faster.
This PR ensures that server components are reliably included in the
DevTools component tree, even if debug info is received delayed, e.g.
when using a debug channel. The fix consists of three parts:
- We must not unset the debug chunk before all debug info entries are
resolved.
- We must ensure that the "RSC Stream" IO debug info entry is pushed
last, after all other entries were resolved.
- We need to transfer the debug info from blocked element chunks onto
the lazy node and the element.
Ideally, we wouldn't even create a lazy node for blocked elements that
are at the root of the JSON payload, because that would basically wrap a
lazy in a lazy. This optimization that ensures that everything around
the blocked element can proceed is only needed for nested elements.
However, we also need it for resolving deduped references in blocked
root elements, unless we adapt that logic, which would be a bigger lift.
When reloading the Flight fixture, the component tree is now displayed
deterministically. Previously, it would sometimes omit synchronous
server components.
<img width="306" height="565" alt="complete"
src="https://github.com/user-attachments/assets/db61aa10-1816-43e6-9903-0e585190cdf1"
/>
---------
Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
We previously always generated import statements for any modules that
had to be required, notably the `import {c} from
'react/compiler-runtime'` for the memo cache function. However, this
obviously doesn't work when the source is using commonjs. Now we check
the sourceType of the module and generate require() statements if the
source type is 'script'.
I initially explored using
https://babeljs.io/docs/babel-helper-module-imports, but the API design
was unfortunately not flexible enough for our use-case. Specifically,
our pipeline is as follows:
* Compile individual functions. Generate candidate imports,
pre-allocating the local names for those imports.
* If the file is compiled successfully, actually add the imports to the
program.
Ie we need to pre-allocate identifier names for the imports before we
add them to the program — but that isn't supported by
babel-helper-module-imports. So instead we generate our own require()
calls if the sourceType is script.
@eps1lon flagged this case. Inlined useCallback has an extra LoadLocal
indirection which caused us not to add a name. While I was there I added
some extra checks to make sure we don't generate names for a given node
twice (just in case).
Stacked on #34546.
Same as #34538 but for gestures.
Includes various fixes.
This shows how it ends with a Transition when you release in the
committed state. Note how the Animation of the Gesture continues until
the Transition is done so that the handoff is seamless.
<img width="853" height="134" alt="Screenshot 2025-09-20 at 7 37 29 PM"
src="https://github.com/user-attachments/assets/6192a033-4bec-43b9-884b-77e3a6f00da6"
/>
This helper weirdly doesn't include the sync lane.
Everywhere we use it we have to check the sync lane separately. We can
simplify things by simply including the sync lane.
This fixes a lack of optimization because we should not check the store
consistency for a `flushSync` render.
d91d28c8ba/packages/react-reconciler/src/ReactFiberHooks.js (L1691-L1693)
If there is a large owner stack, we could potentially spam multiple
fetch requests for the same source map. This adds a simple deduplication
logic, based on URL.
Also, this adds a timeout of 60 seconds to all fetch requests initiated
by fileFetcher content script.
The root instance doesn't have a canonical property so we were not
returning a public instance that we can call compareDocumentPosition on
when a Fragment had no other host parent in Fabric. In this case we need
to get the ReactNativeElement from the ReactNativeDocument.
I've also added test coverage for this case in DOM for consistency,
though it was already working there because we use DOM elements as root.
This same test will be copied to RN using Fantom.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
Added more tests for the compiler playground with the addition of the
new config editor and "Show Internals" button. Added testing to check
for incomplete store params in the URL, toggle functionality, and
correct errors showing for syntax/validation errors in the config
overrides.
Stacked on #34538.
Track the Task of the first ViewTransition that we detected as
animating. Use this as the Task as "Starting Animation", "Animating"
etc. That way you can see which ViewTransition spawned the Animation.
Although it's likely to be multiple.
<img width="757" height="393" alt="Screenshot 2025-09-19 at 10 19 18 PM"
src="https://github.com/user-attachments/assets/a6cdcb89-bd02-40ec-b3c3-11121c29e892"
/>
Stacked on #34522.
<img width="1025" height="200" alt="Screenshot 2025-09-19 at 6 37 28 PM"
src="https://github.com/user-attachments/assets/f25900f6-6503-48b1-876d-bd6697a29c6f"
/>
We already cover the time between "Starting Animation" and "Remaining
Effects" as "Animating". However, if the effects are forced then we can
still be animating after that. This fills in that gap.
This also fills in the gap if another render starts before the animation
finishes on the same track. It'll mark the blank space between the
previous render finishing and the next render starting as "Animating".
This should correspond roughly to the native "Animations" track.
Stacked on #34511.
We currently log all Suspended Commit as "Suspended on Images or CSS"
but it can really be other reasons too now. Like waiting on the previous
View Transition. This allows the host config configure this reason.
Now when one animation starts before another one finishes we log that as
"Waiting for the previous Animation".
<img width="592" height="257" alt="Screenshot 2025-09-17 at 11 53 45 PM"
src="https://github.com/user-attachments/assets/817af8b5-37ae-46d8-bfd1-cd3fc637f3f3"
/>
Triggering the "(Runtime) Publish Prereleases Manual" workflow with a
short git sha doesn't work. It needs the full sha. We might be able to
make it work with the short sha as well, but for now we can at least
document the restriction.
If we are referencing a lazy value that isn't explicitly lazy ($L...)
it's because we added it around an element that was blocked to be able
to defer things inside.
However, once that is unblocked we can start unwrap it and just use the
inner element instead for any future reference. The race condition is
still there since it's a race condition whether we added the wrapper in
the first place.
This just makes it consistent with unwrapping of the rest of the path.
If we don't handle Lazy types specifically in `renderDebugModel`, all of
their properties will be emitted using `renderDebugModel` as well. This
also includes its `_debugInfo` property, if the Lazy comes from the
Flight client. That array might contain objects that are deduped, and
resolving those references in the client can cause runtime errors, e.g.:
```
TypeError: Cannot read properties of undefined (reading '$$typeof')
```
This happened specifically when an "RSC stream" debug info entry, coming
from the Flight client through IO tracking, was emitted and its
`debugTask` property was deduped, which couldn't be resolved in the
client.
To avoid actually initializing a lazy causing a side-effect, we make
some assumptions about the structure of its payload, and only emit
resolved or rejected values, otherwise we emit a halted chunk.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
Made many small changes to the compiler playground to improve user
experience. Removed any "Loading" indicators that would flash in before
a component would finish loading in. Additionally, before users would
see the "Show Internals" button toggling from false to true if they had
set it at true previously. I was able to refactor the URL/local storage
loading so that the `Store` would be fully initialized before the
components would load in.
Attempted to integrate `<Activity>` into showing/hiding these different
editors, but the current state of [monaco
editors](https://github.com/suren-atoyan/monaco-react) does not allow
for this. I created an issue for them to address:
https://github.com/suren-atoyan/monaco-react/issues/753
Added a debounce to the config editor so every key type wouldn't cause
the output panel to respond instantly. Users can type for 500 ms before
an error is thrown at them.
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
## How did you test this change?
Here is what loading the page would look like before (not sure why its
so blurry):
https://github.com/user-attachments/assets/58f4281a-cc02-4141-b9b5-f70d6ace12a2
Here is how it looks now:
https://github.com/user-attachments/assets/40535165-fc7c-44fb-9282-9c7fa76e7d53
Here is the debouncing:
https://github.com/user-attachments/assets/e4ab29e4-1afd-4249-beca-671fb6542f5e
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
Stacked on #34510.
The "Commit" phase for a View Transition starts before the snapshot
phase (before mutation) and then stretches into the async gap of
`startViewTransition`, encompasses the mutation phase inside of its
update callback and finally the layout phase.
However, between the mutation phase and the layout phase we may suspend
the start of the view transition on fonts and/or images. In that case we
now split the Commit phase into first one before we suspend and then we
log "Waiting for Images and/or Fonts" and then another Commit phase
around the layout effects.
<img width="897" height="119" alt="Screenshot 2025-09-16 at 11 37 26 PM"
src="https://github.com/user-attachments/assets/0fe21388-bb48-4456-a594-62227d12d9b7"
/>