Commit Graph

98 Commits

Author SHA1 Message Date
Michael H
b4455a6ee6
[react-dom] Include all Node.js APIs in Bun entrypoint for /server (#34193) 2025-10-27 23:06:45 +01:00
Sebastian Markbåge
280ff6fed2
[Flight] Add Web Stream support to the Flight Client in Node (#33473)
This effectively lets us consume Web Streams in a Node build. In fact
the Node entry point is now just adding Node stream APIs.

For the client, this is simple because the configs are not actually
stream type specific. The server is a little trickier.
2025-06-06 17:14:15 -04:00
Sebastian Markbåge
82f3684c63
Revert Node Web Streams (#33472)
Reverts #33457, #33456 and #33442.

There are too many issues with wrappers, lazy init, stateful modules,
duplicate instantiation of async_hooks and duplication of code.

Instead, we'll just do a wrapper polyfill that uses Node Streams
internally.

I kept the client indirection files that I added for consistency with
the server though.
2025-06-06 16:26:36 -04:00
Sebastian Markbåge
ab859e31be
[Flight] Build Node.js Web Streams builds for Turbopack and Parcel (#33457)
Same as #33456 and #33442 but for Turbopack and Parcel.
2025-06-06 11:07:40 -04:00
Sebastian Markbåge
e8d15fa19e
[Flight] Build node-webstreams version of bundled webpack server (#33456)
Follow up to #33442. This is the bundled version.

To keep type check passes from exploding and the maintainance of the
annoying `paths: []` list small, this doesn't add this to flow type
checks. We might miss some config but every combination should already
be covered by other one passes.

I also don't add any jest tests because to test these double export
entry points we need conditional importing to cover builds and
non-builds which turns out to be difficult for the Flight builds so
these aren't covered by any basic build tests.

This approach is what I'm going for, for the other bundlers too.
2025-06-06 11:07:15 -04:00
Sebastian Markbåge
a5110b22f0
[Flight] Add a Node.js Web Streams bundle for unbundled client/server for Webpack (#33442)
Like #33441 but for Flight.

This is just one of the many combinations needed. I'm just starting with
one.
2025-06-05 14:29:02 -04:00
Sebastian Markbåge
93f1668045
[Fizz] Add Node Web Streams bundle for SSR (#33441)
We highly recommend using Node Streams in Node.js because it's much
faster and it is less likely to cause issues when chained in things like
compression algorithms that need explicit flushing which the Web Streams
ecosystem doesn't have a good solution for. However, that said, people
want to be able to use the worse option for various reasons.

The `.edge` builds aren't technically intended for Node.js. A Node.js
environments needs to be patched in various ways to support it. It's
also less optimal since it can't use [Node.js exclusive
features](https://github.com/facebook/react/pull/33388) and have to use
[the lowest common
denominator](https://github.com/facebook/react/pull/27399) such as JS
implementations instead of native.

This adds a Web Streams build of Fizz but exclusively for Node.js so
that in it we can rely on Node.js modules. The main difference compared
to Edge is that SSR now uses `createHash` from the `"crypto"` module and
imports `TextEncoder` from `"util"`. We use `setImmediate` instead of
`setTimeout`.

The public API is just `react-dom/server` which in Node.js automatically
imports `react-dom/server.node` which re-exports the legacy bundle, Node
Streams bundle and Node Web Streams bundle. The main downside is if your
bundler isn't smart to DCE this barrel file.

With Flight the difference is larger but that's a bigger lift.
2025-06-05 10:50:41 -04:00
Sebastian Markbåge
acee65d6d0
[Flight] Track Awaits on I/O as Debug Info (#33388)
This lets us track what data each Server Component depended on. This
will be used by Performance Track and React DevTools.

We use Node.js `async_hooks`. This has a number of downside. It is
Node.js specific so this feature is not available in other runtimes
until something equivalent becomes available. It's [discouraged by
Node.js docs](https://nodejs.org/api/async_hooks.html#async-hooks). It's
also slow which makes this approach only really viable in development
mode. At least with stack traces. However, it's really the only solution
that gives us the data that we need.

The [Diagnostic
Channel](https://nodejs.org/api/diagnostics_channel.html) API is not
sufficient. Not only is many Node.js built-in APIs missing but all
libraries like databases are also missing. Were as `async_hooks` covers
pretty much anything async in the Node.js ecosystem.

However, even if coverage was wider it's not actually showing the
information we want. It's not enough to show the low level I/O that is
happening because that doesn't provide the context. We need the stack
trace in user space code where it was initiated and where it was
awaited. It's also not each low level socket operation that we want to
surface but some higher level concept which can span a sequence of I/O
operations but as far as user space is concerned.

Therefore this solution is anchored on stack traces and ignore listing
to determine what the interesting span is. It is somewhat
Promise-centric (and in particular async/await) because it allows us to
model an abstract span instead of just random I/O. Async/await points
are also especially useful because this allows Async Stacks to show the
full sequence which is not supported by random callbacks. However, if no
Promises are involved we still to our best to show the stack causing
plain I/O callbacks.

Additionally, we don't want to track all possible I/O. For example,
side-effects like logging that doesn't affect the rendering performance
doesn't need to be included. We only want to include things that
actually block the rendering output. We also need to track which data
blocks each component so that we can track which data caused a
particular subtree to suspend.

We can do this using `async_hooks` because we can track the graph of
what resolved what and then spawned what.

To track what suspended what, something has to resolve. Therefore it
needs to run to completion before we can show what it was suspended on.
So something that never resolves, won't be tracked for example.

We use the `async_hooks` in `ReactFlightServerConfigDebugNode` to build
up an `ReactFlightAsyncSequence` graph that collects the stack traces
for basically all I/O and Promises allocated in the whole app. This is
pretty heavy, especially the stack traces, but it's because we don't
know which ones we'll need until they resolve. We don't materialize the
stacks until we need them though.

Once they end up pinging the Flight runtime, we collect which current
executing task that pinged the runtime and then log the sequence that
led up until that runtime into the RSC protocol. Currently we only
include things that weren't already resolved before we started rendering
this task/component, so that we don't log the entire history each time.

Each operation is split into two parts. First a `ReactIOInfo` which
represents an I/O operation and its start/end time. Basically the start
point where it was start. This is basically represents where you called
`new Promise()` or when entering an `async function` which has an
implied Promise. It can be started in a different component than where
it's awaited and it can be awaited in multiple places. Therefore this is
global information and not associated with a specific Component.

The second part is `ReactAsyncInfo`. This represents where this I/O was
`await`:ed or `.then()` called. This is associated with a point in the
tree (usually the Promise that's a direct child of a Component). Since
you can have multiple different I/O awaited in a sequence technically it
forms a dependency graph but to simplify the model these awaits as
flattened into the `ReactDebugInfo` list. Basically it contains each
await in a sequence that affected this part from unblocking.

This means that the same `ReactAsyncInfo` can appear in mutliple
components if they all await the same `ReactIOInfo` but the same Promise
only appears once.

Promises that are only resolved by other Promises or immediately are not
considered here. Only if they're resolved by an I/O operation. We pick
the Promise basically on the border between user space code and ignored
listed code (`node_modules`) to pick the most specific span but abstract
enough to not give too much detail irrelevant to the current audience.
Similarly, the deepest `await` in user space is marked as the relevant
`await` point.

This feature is only available in the `node` builds of React. Not if you
use the `edge` builds inside of Node.js.

---------

Co-authored-by: Sebastian "Sebbie" Silbermann <silbermann.sebastian@gmail.com>
2025-06-03 14:14:40 -04:00
Sebastian Markbåge
130095f76b
[Flight Parcel] Align with more recent changes (#31741)
Follow up to #31725.

I diffed against the Turbopack one to find any unexpected discrepancies.
Some parts are forked enough that it's hard to diff but I think I got
most of it.
2024-12-12 14:39:25 -05:00
Devon Govett
ca587425fe
Implement react-server-dom-parcel (#31725)
This adds a new `react-server-dom-parcel-package`, which is an RSC
integration for the Parcel bundler. It is mostly copied from the
existing webpack/turbopack integrations, with some changes to utilize
Parcel runtime APIs for loading and executing bundles/modules.

See https://github.com/parcel-bundler/parcel/pull/10043 for the Parcel
side of this, which includes the plugin needed to generate client and
server references. https://github.com/parcel-bundler/rsc-examples also
includes examples of various ways to use RSCs with Parcel.

Differences from other integrations:

* Client and server modules are all part of the same graph, and we use
Parcel's
[environments](https://parceljs.org/plugin-system/transformer/#the-environment)
to distinguish them. The server is the Parcel build entry point, and it
imports and renders server components in route handlers. When a `"use
client"` directive is seen, the environment changes and Parcel creates a
new client bundle for the page, combining all client modules together.
CSS from both client and server components are also combined
automatically.
* There is no separate manifest file that needs to be passed around by
the user. A [Runtime](https://parceljs.org/plugin-system/runtime/)
plugin injects client and server references as needed into the relevant
bundles, and registers server action ids using `react-server-dom-parcel`
automatically.
* A special `<Resources>` component is also generated by Parcel to
render the `<script>` and `<link rel="stylesheet">` elements needed for
a page, using the relevant info from the bundle graph.

Note: I've already published a 0.0.x version of this package to npm for
testing purposes but happy to add whoever needs access to it as well.

### Questions

* How to test this in the React repo. I'll have integration tests in
Parcel, but setting up all the different mocks and environments to
simulate that here seems challenging. I could try to copy how
Webpack/Turbopack do it but it's a bit different.
* Where to put TypeScript types. Right now I have some ambient types in
my [example
repo](https://github.com/parcel-bundler/rsc-examples/blob/main/types.d.ts)
but it would be nice for users not to copy and paste these. Can I
include them in the package or do they need to maintained separately in
definitelytyped? I would really prefer not to have to maintain code in
three different repos ideally.

---------

Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
2024-12-11 22:58:51 -05:00
Sebastian Markbåge
156eab2f7b
Fork the "empty" prepareStackTrace case for Server builds (#31427)
We don't actually want the source mapped version of `.stack` from errors
because that would cause us to not be able to associate it with a source
map in the UIs that need it. The strategy in browsers is more correct
where the display is responsible for source maps.

That's why we disable any custom `prepareStackTrace` like the ones added
by `source-map`. We reset it to `undefined`.

However, when running node with `--enable-source-maps` the default for
`prepareStackTrace` which is a V8 feature (but may exist elsewhere too
like Bun) is a source mapped version of the stack. In those environments
we need to reset it to a default implementation that doesn't apply
source maps.

We already did this in Flight using the `ReactFlightStackConfigV8.js`
config. However, we need this more generally in the
`shared/ReactComponentStackFrame` implementation.

We could always set it to the default implementation instead of
`undefined` but that's unnecessary code in browser builds and it might
lead to slightly different results. For safety and code size, this PR
does it with a fork instead.

All builds specific to `node` or `edge` (or `markup` which is a server
feature) gets the default implementation where as everything else (e.g.
browsers) get `undefined` since it's expected that this is not source
mapped. We don't have to do anything about the equivalent in React
DevTools since React DevTools doesn't run on the server.
2024-11-05 15:05:04 -05:00
Sebastian Markbåge
1228a28398
Remove turbopack unbundled/register/loader (#30756)
The unbundled form is just a way to show case a prototype for how an
unbundled version of RSC can work. It's not really intended for every
bundler combination to provide such a configuration.

There's no configuration of Turbopack that supports this mode atm and
possibly never will be since it's more of an integrated server/client
experience.

This removes the unbundled form and node register/loaders from the
turbopack build.
2024-08-21 09:58:31 -04:00
Josh Story
fa6eab5854
[Flight] Implement prerender (#30686)
Prerendering in flight is similar to prerendering in Fizz. Instead of
receiving a result (the stream) immediately a promise is returned which
resolves to the stream when the prerender is complete. The promise will
reject if the flight render fatally errors otherwise it will resolve
when the render is completed or is aborted.
2024-08-15 14:28:28 -07:00
Josh Story
8b08ee08a1
[Flight] reorganize code for forked entrypoints (#30702)
This commit updates the file locations and bulid configurations for
flight in preparation for new static entrypoints. This follows a
structure similar to Fizz which has a unified build but exports methods
from different top level entrypoints. This PR doesn't actually add the
new top level entrypoints however, that will arrive in a later update.
2024-08-14 18:10:40 -07:00
Sebastian Silbermann
e0a0e65412
Move react-html to react-markup (#30688) 2024-08-14 19:22:44 +02:00
Greg Brimble
c0ee8e94b0
Fix typos in Turbopack configuration and in Node.js loader error messages (#30593)
<!--
  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

Just fixing some copy-paste typos.

## How did you test this change?

Untested.
2024-08-05 10:11:39 -04:00
Jan Kassens
fd2b3e13d3
Compiler: unfork prettier config (#30205)
Updates the prettier config to format all `.ts` and `.tsx` files in the
repo using the existing defaults and removing overrides.

The first commit in this PR contains the config changes, the second is
just the result of running `yarn prettier-all`.
2024-07-18 17:00:24 -04:00
Mike Vitousek
05cebffe16 [prettier][eslint] Support sapling in prettier changed files command
Summary: The listChangesFiles module didn't work under sapling; this fixes

ghstack-source-id: 9f685de5e7
Pull Request resolved: https://github.com/facebook/react/pull/30149
2024-06-30 14:22:22 -07:00
Sebastian Markbåge
1e241f9d6c
Add renderToMarkup for Client Components (#30121)
Follow up to #30105.

This supports `renderToMarkup` in a non-RSC environment (not the
`react-server` condition).

This is just a Fizz renderer but it errors at runtime when you use
state, effects or event handlers that would require hydration - like the
RSC version would. (Except RSC can give early errors too.)

To do this I have to move the `react-html` builds to a new `markup`
dimension out of the `dom-legacy` dimension so that we can configure
this differently from `renderToString`/`renderToStaticMarkup`.
Eventually that dimension can go away though if deprecated. That also
helps us avoid dynamic configuration and we can just compile in the
right configuration so the split helps anyway.

One consideration is that if a compiler strips out useEffects or inlines
initial state from useState, then it would not get called an the error
wouldn't happen. Therefore to preserve semantics, a compiler would need
to inject some call that can check the current renderer and whether it
should throw.

There is an argument that it could be useful to not error for these
because it's possible to write components that works with SSR but are
just optionally hydrated. However, there's also an argument that doing
that silently is too easy to lead to mistakes and it's better to error -
especially for the e-mail use case where you can't take it back but you
can replay a queue that had failures. There are other ways to
conditionally branch components intentionally. Besides if you want it to
be silent you can still use renderToString (or better yet
renderToReadableStream).

The primary mechanism is the RSC environment and the client-environment
is really the secondary one that's only there to support legacy
environments. So this also ensures parity with the primary environment.
2024-06-28 09:25:10 -04:00
Sebastian Markbåge
ffec9ec5b5
Add new package with renderToMarkup export (#30105)
Name of the package is tbd (straw: `react-html`). It's a new package
separate from `react-dom` though and can be used as a standalone package
- e.g. also from a React Native app.

```js
import {renderToMarkup} from '...';
const html = await renderToMarkup(<Component />);
```

The idea is that this is a helper for rendering HTML that is not
intended to be hydrated. It's primarily intended to support a subset of
HTML that can be used as embedding and not served as HTML documents from
HTTP. For example as e-mails or in RSS/Atom feeds or other
distributions. It's a successor to `renderToStaticMarkup`.

A few differences:

- This doesn't support "Client Components". It can only use the Server
Components subset. No useEffect, no useState etc. since it will never be
hydrated. Use of those are errors.
- You also can't pass Client References so you can't use components
marked with `"use client"`.
- Unlike `renderToStaticMarkup` this does support async so you can
suspend and use data from these components.
- Unlike `renderToReadableStream` this does not support streaming or
Suspense boundaries and any error rejects the promise. Since there's no
feasible way to "client render" or patch up the document.
- Form Actions are not supported since in an embedded environment
there's no place to post back to across versions. You can render plain
forms with fixed URLs though.
- You can't use any resource preloading like `preload()` from
`react-dom`.

## Implementation

This first version in this PR only supports Server Components since
that's the thing that doesn't have an existing API. Might add a Client
Components version later that errors.

We don't want to maintain a completely separate implementation for this
use case so this uses the `dom-legacy` build dimension to wire up a
build that encapsulates a Flight Server -> Flight Client -> Fizz stream
to render Server Components that then get SSR:ed.

There's no problem to use a Flight Client in a Server Component
environment since it's already supported for Server-to-Server. Both of
these use a bundler config that just errors for Client References though
since we don't need any bundling integration and this is just a
standalone package.

Running Fizz in a Server Component environment is a problem though
because it depends on "react" and it needs the client version.
Therefore, for this build we embed the client version of "react" shared
internals into the build. It doesn't need anything to be able to use
those APIs since you can't call the client APIs anyway.

One unfortunate thing though is that since Flight currently needs to go
to binary and back, we need TextEncoder/TextDecoder to be available but
this shouldn't really be necessary. Also since we use the legacy stream
config, large strings that use byteLengthOfChunk errors atm. This needs
to be fixed before shipping. I'm not sure what would be the best
layering though that isn't unnecessarily burdensome to maintain. Maybe
some kind of pass-through protocol that would also be useful in general
- e.g. when Fizz and Flight are in the same process.

---------

Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
2024-06-27 12:09:40 -04:00
Lauren Tan
49c37048de [prettier] Combine compiler and runtime configs
Merges the existing config to the root one so we can have a single
configuration file. I've tried to keep the compiler config as much as
possible in this PR so that no formatting changes occur.

ghstack-source-id: 8bbfc9f269
Pull Request resolved: https://github.com/facebook/react/pull/30021
2024-06-21 12:05:29 -04:00
Jan Kassens
26f2496093
Remove 2 no longer existing files from inlinedHostConfig (#29027)
Remove 2 no longer existing files from inlinedHostConfig

While looking for `.classic` forks, I noticed these files no longer
exist.
2024-05-14 10:07:00 -04: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](1d5f8d5209/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
Josh Story
cb151849e1
[react-dom] move all client code to react-dom/client (#28271)
This PR reorganizes the `react-dom` entrypoint to only pull in code that
is environment agnostic. Previously if you required anything from this
entrypoint in any environment the entire client reconciler was loaded.
In a prior release we added a server rendering stub which you could
alias in server environments to omit this unecessary code. After landing
this change this entrypoint should not load any environment specific
code.

While a few APIs are truly client (browser) only such as createRoot and
hydrateRoot many of the APIs you import from this package are only
useful in the browser but could concievably be imported in shared code
(components running in Fizz or shared components as part of an RSC app).
To avoid making these require opting into the client bundle we are
keeping them in the `react-dom` entrypoint and changing their
implementation so that in environments where they are not particularly
useful they do something benign and expected.

#### Removed APIs
The following APIs are being removed in the next major. Largely they
have all been deprecated already and are part of legacy rendering modes
where concurrent features of React are not available
* `render`
* `hydrate`
* `findDOMNode`
* `unmountComponentAtNode`
* `unstable_createEventHandle`
* `unstable_renderSubtreeIntoContainer`
* `unstable_runWithPrioirty`

#### moved Client APIs
These APIs were available on both `react-dom` (with a warning) and
`react-dom/client`. After this change they are only available on
`react-dom/client`
* `createRoot`
* `hydrateRoot`

#### retained APIs
These APIs still exist on the `react-dom` entrypoint but have normalized
behavior depending on which renderers are currently in scope
* `flushSync`: will execute the function (if provided) inside the
flushSync implemention of FlightServer, Fizz, and Fiber DOM renderers.
* `unstable_batchedUpdates`: This is a noop in concurrent mode because
it is now the only supported behavior because there is no legacy
rendering mode
* `createPortal`: This just produces an object. It can be called from
anywhere but since you will probably not have a handle on a DOM node to
pass to it it will likely warn in environments other than the browser
* preloading APIS such as `preload`: These methods will execute the
preload across all renderers currently in scope. Since we resolve the
Request object on the server using AsyncLocalStorage or the current
function stack in practice only one renderer should act upon the
preload.

In addition to these changes the server rendering stub now just rexports
everything from `react-dom`. In a future minor we will add a warning
when using the stub and in the next major we will remove the stub
altogether
2024-04-24 08:50:32 -07:00
Jan Kassens
1cd77a4ff7
Remove ReactFlightFB bundles (#28864)
Remove ReactFlightFB bundles
2024-04-18 16:41:04 -04:00
Josh Story
01bb3c5632
[TestUtils] Build limited test-utils (#28782)
We landed a flag to disable test utils in many builds but we need to
fork the entrypoint to make it work with tests properly. This also
removes test-utils implementations from builds that do not support it.
Currently in OSS builds the only thing in test-utils is a reexport of
`act`
2024-04-08 12:27:20 -07:00
Andrew Clark
5d1b15a4f0
Rename "shared subset" to "server" (#27939)
The internal file ReactSharedSubset is what the `react` module resolves
to when imported from a Server Component environment. We gave it this
name because, originally, the idea was that Server Components can access
a subset of the APIs available on the client.

However, since then, we've also added APIs that can _only_ by accessed
on the server and not the client. In other words, it's no longer a
subset, it's a slightly different overlapping set.

So this commit renames ReactSharedSubet to ReactServer and updates all
the references. This does not affect the public API, only our internal
implementation.
2024-01-16 19:58:11 -05:00
Sebastian Markbåge
8b8d265bd9
[Flight] Wire up async_hooks in Node.js DEV for inspecting Promises (#27840)
This wires up the use of `async_hooks` in the Node build (as well as the
Edge build when a global is available) in DEV mode only. This will be
used to track debug info about what suspended during an RSC pass.

Enabled behind a flag for now.
2023-12-15 21:38:01 -05:00
Andrey Lunyov
c17a27ef49
FB-specific builds of Flight Server, Flight Client, and React Shared Subset (#27579)
This PR adds a new FB-specific configuration of Flight. We also need to
bundle a version of ReactSharedSubset that will be used for running
Flight on the server.

This initial implementation does not support server actions yet.

The FB-Flight still uses the text protocol on the server (the flag
`enableBinaryFlight` is set to false). It looks like we need some
changes in Hermes to properly support this binary format.
2023-11-27 18:34:58 -05:00
Andrew Clark
77c4ac2ce8
[useFormState] Allow sync actions (#27571)
Updates useFormState to allow a sync function to be passed as an action.

A form action is almost always async, because it needs to talk to the
server. But since we support client-side actions, too, there's no reason
we can't allow sync actions, too.

I originally chose not to allow them to keep the implementation simpler
but it's not really that much more complicated because we already
support this for actions passed to startTransition. So now it's
consistent: anywhere an action is accepted, a sync client function is a
valid input.
2023-10-31 23:32:31 -04:00
Josh Story
f81c0f1ed9
[Flight] Implement react-server-dom-turbopack (#27315)
stacked on #27314 

Turbopack requires a different module loading strategy than Webpack and
as such this PR implements a new package `react-server-dom-turbopack`
which largely follows the `react-server-dom-webpack` but is implemented
for this new bundler
2023-09-27 10:03:57 -07:00
Josh Story
701ac2e572
[Flight][Float] Preinitialize module imports during SSR (#27314)
Currently when we SSR a Flight response we do not emit any resources for
module imports. This means that when the client hydrates it won't have
already loaded the necessary scripts to satisfy the Imports defined in
the Flight payload which will lead to a delay in hydration completing.

This change updates `react-server-dom-webpack` and
`react-server-dom-esm` to emit async script tags in the head when we
encounter a modules in the flight response.

To support this we need some additional server configuration. We need to
know the path prefix for chunk loading and whether the chunks will load
with CORS or not (and if so with what configuration).
2023-09-27 09:53:31 -07:00
Andrew Clark
2d2f2af29b
Restrict React DOM imports from Server Components (#27382)
Adds a separate entry point for the react-dom package when it's accessed
from a Server Component environment, using the "react-server" export
condition.

When you're inside a Server Component module, you won't be able to
import client-only APIs like useState. This applies to almost all React
DOM exports, except for Float ones like preload.
2023-09-15 14:53:19 -04:00
Sebastian Markbåge
31034b6de7
[Fizz] Split ResponseState/Resources into RenderState/ResumableState (#27268)
This exposes a `resume()` API to go with the `prerender()` (only in
experimental). It doesn't work yet since we don't yet emit the postponed
state so not yet tested.

The main thing this does is rename ResponseState->RenderState and
Resources->ResumableState. We separated out resources into a separate
concept preemptively since it seemed like separate enough but probably
doesn't warrant being a separate concept. The result is that we have a
per RenderState in the Config which is really just temporary state and
things that must be flushed completely in the prerender. Most things
should be ResumableState.

Most options are specified in the `prerender()` and transferred into the
`resume()` but certain options that are unique per request can't be.
Notably `nonce` is special. This means that bootstrap scripts and
external runtime can't use `nonce` in this mode. They need to have a CSP
configured to deal with external scripts, but not inline.

We need to be able to restore state of things that we've already emitted
in the prerender. We could have separate snapshot/restore methods that
does this work when it happens but that means we have to explicitly do
that work. This design is trying to keep to the principle that we just
work with resumable data structures instead so that we're designing for
it with every feature. It also makes restoring faster since it's just
straight into the data structure.

This is not yet a serializable format. That can be done in a follow up.

We also need to vet that each step makes sense. Notably stylesToHoist is
a bit unclear how it'll work.
2023-08-22 15:21:36 -04:00
Josh Story
5623f2acf9
Updating forking implementation to match against more general fork implementations (#27205)
Search for more generic fork files if an exact match does not exist. If
`forks/MyFile.dom.js` exists but `forks/MyFile.dom-node.js` does not
then use it when trying to resolve forks for the `"dom-node"` renderer
in flow, tests, and build

consolidate certain fork files that were identical and make semantic
sense to be generalized
add `dom-browser-esm` bundle and use it for
`react-server-dom-esm/client.browser` build
2023-08-17 15:17:46 -07:00
Sebastian Markbåge
fdc8c81e07
[Flight] Client and Server Reference Creation into Runtime (#27033)
We already did this for Server References on the Client so this brings
us parity with that. This gives us some more flexibility with changing
the runtime implementation without having to affect the loaders.

We can also do more in the runtime such as adding `.bind()` support to
Server References.

I also moved the CommonJS Proxy creation into the runtime helper from
the register so that it can be handled in one place.

This lets us remove the forks from Next.js since the loaders can be
simplified there to just use these helpers.

This PR doesn't change the protocol or shape of the objects. They're
still specific to each bundler but ideally we should probably move this
to shared helpers that can be used by multiple bundler implementations.
2023-07-07 11:09:45 -04:00
Sebastian Markbåge
f181ba8aa6
[Flight] Add bundler-less version of RSC using plain ESM (#26889)
This isn't really meant to be actually used, there are many issues with
this approach, but it shows the capabilities as a proof-of-concept.

It's a new reference implementation package `react-server-dom-esm` as
well as a fixture in `fixtures/flight-esm` (fork of `fixtures/flight`).
This works pretty much the same as pieces we already have in the Webpack
implementation but instead of loading modules using Webpack on the
client it uses native browser ESM.

To really show it off, I don't use any JSX in the fixture and so it also
doesn't use Babel or any compilation of the files.

This works because we don't actually bundle the server in the reference
implementation in the first place. We instead use [Node.js
Loaders](https://nodejs.org/api/esm.html#loaders) to intercept files
that contain `"use client"` and `"use server"` and replace them. There's
a simple check for those exact bytes, and no parsing, so this is very
fast.

Since the client isn't actually bundled, there's no module map needed.
We can just send the file path to the file we want to load in the RSC
payload for client references.

Since the existing reference implementation for Node.js already used ESM
to load modules on the server, that all works the same, including Server
Actions. No bundling.

There is one case that isn't implemented here. Importing a `"use
server"` file from a Client Component. We don't have that implemented in
the Webpack reference implementation neither - only in Next.js atm. In
Webpack it would be implemented as a Webpack loader.

There are a few ways this can be implemented without a bundler:

- We can intercept the request from the browser importing this file in
the HTTP server, and do a quick scan for `"use server"` in the file and
replace it just like we do with loaders in Node.js. This is effectively
how Vite works and likely how anyone using this technique would have to
support JSX anyway.
- We can use native browser "loaders" once that's eventually available
in the same way as in Node.js.
- We can generate import maps for each file and replace it with a
pointer to a placeholder file. This requires scanning these ahead of
time which defeats the purposes.

Another case that's not implemented is the inline `"use server"` closure
in a Server Component. That would require the existing loader to be a
bit smarter but would still only "compile" files that contains those
bytes in the fast path check. This would also happen in the loader that
already exists so wouldn't do anything substantially different than what
we currently have here.
2023-06-03 15:58:24 -04:00
Sebastian Markbåge
5309f10285
Remove Flight Relay DOM/Native (#26828)
The bindings upstream in Relay has been removed so we don't need these
builds anymore. The idea is to revisit an FB integration of Flight but
it wouldn't use the Relay specific bindings. It's a bit unclear how it
would look but likely more like the OSS version so not worth keeping
these around.

The `dom-relay` name also included the FB specific Fizz implementation
of the streaming config so I renamed that to `dom-fb`. There's no Fizz
implementation for Native yet so I just removed `native-relay`.

We created a configurable fork for how to encode the output of Flight
and the Relay implementation encoded it as JSON objects instead of
strings/streams. The new implementation would likely be more stream-like
and just encode it directly as string/binary chunks. So I removed those
indirections so that this can just be declared inline in
ReactFlightServer/Client.
2023-05-17 20:33:25 -04:00
Sebastian Markbåge
60144a04da
Split out Edge and Node implementations of the Flight Client (#26187)
This splits out the Edge and Node implementations of Flight Client into
their own implementations. The Node implementation now takes a Node
Stream as input.

I removed the bundler config from the Browser variant because you're
never supposed to use that in the browser since it's only for SSR.
Similarly, it's required on the server. This also enables generating a
SSR manifest from the Webpack plugin. This is necessary for SSR so that
you can reverse look up what a client module is called on the server.

I also removed the option to pass a callServer from the server. We might
want to add it back in the future but basically, we don't recommend
calling Server Functions from render for initial render because if that
happened client-side it would be a client-side waterfall. If it's never
called in initial render, then it also shouldn't ever happen during SSR.
This might be considered too restrictive.

~This also compiles the unbundled packages as ESM. This isn't strictly
necessary because we only need access to dynamic import to load the
modules but we don't have any other build options that leave
`import(...)` intact, and seems appropriate that this would also be an
ESM module.~ Went with `import(...)` in CJS instead.
2023-02-21 13:18:24 -05:00
Sebastian Markbåge
189f70e17b
Create a bunch of custom webpack vs unbundled node bundles (#26172)
We currently have an awkward set up because the server can be used in
two ways. Either you can have the server code prebundled using Webpack
(what Next.js does in practice) or you can use an unbundled Node.js
server (what the reference implementation does).

The `/client` part of RSC is actually also available on the server when
it's used as a consumer for SSR. This should also be specialized
depending on if that server is Node or Edge and if it's bundled or
unbundled.

Currently we still assume Edge will always be bundled since we don't
have an interceptor for modules there.

I don't think we'll want to support this many combinations of setups for
every bundler but this might be ok for the reference implementation.

This PR doesn't actually change anything yet. It just updates the
plumbing and the entry points that are built and exposed. In follow ups
I'll fork the implementation and add more features.

---------

Co-authored-by: dan <dan.abramov@me.com>
2023-02-16 11:01:52 -05:00
Sebastian Markbåge
01a0c4e12c
Add Edge Server Builds for workerd / edge-light (#26116)
We currently abuse the browser builds for Web streams derived
environments. We already have a special build for Bun but we should also
have one for [other "edge"
runtimes](https://runtime-keys.proposal.wintercg.org/) so that we can
maximally take advantage of the APIs that exist on each platform.

In practice, we currently check for a global property called
`AsyncLocalStorage` in the server browser builds which we shouldn't
really do since browsers likely won't ever have it. Additionally, this
should probably move to an import which we can't add to actual browser
builds where that will be an invalid import. So it has to be a separate
build. That's not done yet in this PR but Vercel will follow
Cloudflare's lead here.

The `deno` key still points to the browser build since there's no
AsyncLocalStorage there but it could use this same or a custom build if
support is added.
2023-02-07 15:10:01 -05:00
Sebastian Markbåge
03a216070d
Rename "dom" fork to "dom-node" and "bun" fork to "dom-bun" (#26117)
The "dom" configuration is actually the node specific configuration. It
just happened to be that this was the mainline variant before so it was
implied but with so many variants, this is less obvious now.

The "bun" configuration is specifically for "bun". There's no "native"
renderer for "bun" yet.
2023-02-06 15:54:14 -05:00
Jan Kassens
6b30832666
Upgrade prettier (#26081)
The old version of prettier we were using didn't support the Flow syntax
to access properties in a type using `SomeType['prop']`. This updates
`prettier` and `rollup-plugin-prettier` to the latest versions.

I added the prettier config `arrowParens: "avoid"` to reduce the diff
size as the default has changed in Prettier 2.0. The largest amount of
changes comes from function expressions now having a space. This doesn't
have an option to preserve the old behavior, so we have to update this.
2023-01-31 08:25:05 -05:00
Colin McDonnell
56ffca8b9e
Add Bun streaming server renderer (#25597)
Add support for Bun server renderer
2022-11-17 13:15:56 -08:00
mofeiZ
1a08f1478d
[ServerRenderer] Move fizz external runtime implementation to react-dom-bindings (#25617)
<!--
  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 debug-test --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
-->

Following
[comment](https://github.com/facebook/react/pull/25437#discussion_r1010944983)
in #25437 , the external runtime implementation should be moved from
`react-dom` to `react-dom-bindings`.

I did have a question here:
I set the entrypoint to `react-dom/unstable_server-external-runtime.js`,
since a.) I was following #25436 as an example and b.)
`react-dom-bindings` was missing a `README.md` and `npm/`. This also
involved adding the external runtime to `package.json`.
However, the external runtime isn't really a `react-dom` entrypoint. Is
this change alright, or should I change the bundling code instead?
## How did you test this change?

<!--
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.
-->
2022-11-03 11:15:29 -04:00
Andrew Clark
9cdf8a99ed
[Codemod] Update copyright header to Meta (#25315)
* Facebook -> Meta in copyright

rg --files | xargs sed -i 's#Copyright (c) Facebook, Inc. and its affiliates.#Copyright (c) Meta Platforms, Inc. and affiliates.#g'

* Manual tweaks
2022-10-18 11:19:24 -04:00
Sebastian Markbåge
3bb71dfd4b
Rename react-server-dom-webpack entry points to /client and /server (#25504) 2022-10-18 10:15:52 -04:00
Andrew Clark
54f0e0f730
Scaffolding for react-dom/unstable_external-server-runtime (#25482)
* Scaffolding for react-dom/unstable_external-server-runtime

Implements a new bundle type for in our build config called
BROWSER_SCRIPT. This is intended for scripts that get delivered straight
to the browser without needing to be processed by a bundler. (And also
doesn't include any extra UMD crap.)

Right now there's only a single use case so I didn't stress about making
it general purpose.

The use case is: a script that loads the Fizz browser runtime, and sets
up a MutationObserver to receive instructions as HTML streams in. This
will be an alternative option to the default Fizz behavior of sending
the runtime down as inline script tags, to accommodate environments
where inline script tags are not allowed.

There's no development version of this bundle because it doesn't contain
any warnings or run any user code.

None of the actual implementation is in this PR; it just sets up the
build infra.

Co-authored-by: Mofei Zhang <feifei0@fb.com>

* Set BUNDLE_SCRIPT's GCC output format to ES5

This removes the automatic 'use strict' directive, which we don't need.

Co-authored-by: Mofei Zhang <feifei0@fb.com>
2022-10-14 23:29:17 -04:00
Josh Story
aa9988e5e6
Server render fork for react-dom (#25436)
Publish an aliasable entry for `react-dom` top level package exports for use in server environments. This is a stub containing only the exports that we expect to retain in the top level once 19 is released
2022-10-10 11:06:22 -07:00
Josh Story
7b25b961df
[Fizz/Float] Float for stylesheet resources (#25243)
* [Fizz/Float] Float for stylesheet resources

This commit implements Float in Fizz and on the Client. The initial set of supported APIs is roughly

1. Convert certain stylesheets into style Resources when opting in with precedence prop
2. Emit preloads for stylesheets and explicit preload tags
3. Dedupe all Resources by href
4. Implement ReactDOM.preload() to allow for imperative preloading
5. Implement ReactDOM.preinit() to allow for imperative preinitialization

Currently supports
1. style Resources (link rel "stylesheet")
2. font Resources (preload as "font")

later updates will include support for scripts and modules
2022-09-30 16:14:04 -07:00