Skip to content

Bug: Flight (RSC) examples are not accessible #28589

Open
@kettanaito

Description

Thank you for featuring a few flight examples on the barebones of RSC! They have been tremendously helpful to me in understanding the model.

That being said, I find myself lost in them. I know it's not an issue per se but I'd be thankful if you consider this feedback and maybe even improve on the examples as the result of it.

Feedback

My feedback comes down to a few random questions and a few fundamental questions to the RSC model and how to get the right image of it in my head. Please note I'm mainly focusing on understanding the internals of RSC (ala I want to build an RSC rendering/serving pipeline from scratch).

Random questions

1. Why do this request forwarding?

const promiseForData = request(
{
host: '127.0.0.1',
port: 3001,
method: req.method,
path: '/',
headers: proxiedHeaders,
},
req
);

Why not split endpoints and have them clear:

  • This returns the initial HTML;
  • This returns whichever Server Action data is passed to the server component.

Putting it all in a single request handler makes the example significantly harder to grasp. I get it, these are not educational materials but a bit of documentation and structuring would go a long way.

2. Why are "global" and "region" server implementations so dramatically different?

I thought those represented the target of your deployment but they straight changed the approach to rendering completely.

They also run in different contexts:

  • "global" runs with the "--condition react-server" condition.
  • "region" does not.

I get it, they rely on different packages but I fail to see how those implementations co-exist (do they co-exist? Is it like "deploy region.js when building APP_1, and deploy global.js when building APP_2?). Are those two different ways to implement RSC or one inseparable whole split into two parts?

They have to because some actually render the HTML while others just return serialized components from the endpoints. How am I supposed to combine the two? Run two servers...?

3. How does this code compile?

import {createFromFetch, encodeReply} from 'react-server-dom-esm/client';

That package has no source on NPM. There's an issue open about it (#27197). An oversight? Would pretty much like to have an ESM version of the binding because others imply I'm using a compiler (webpack/turbopack), which I'm not.

I think the ESM example is actually the one I'm the most interested in because it doesn't need a compiler.

4. Why does only the "region" server of the ESM example import the action?

const action = (await import(filepath))[name];

Is this logic not applicable to other examples, like when using webpack or turobpack? Do the compilers extract and save the actions in the manifest json? A little bit of documentation on this would be fantastic (I will touch on it at the end).

5. How does this even run?

<script src="../../build/oss-experimental/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.development.js"></script>

The bundle it points to contains __webpack_require__ expressions, which will fail in the browser:

https://www.unpkg.com/react-server-dom-webpack@18.3.0-canary-a870b2d54-20240314/umd/react-server-dom-webpack-client.browser.development.js

I feel like this index.html is missing some setup around and does not illustrate the example in isolation (relies on webpack anyway?).

6. Why do examples use babel?

I suspect it's to transform JSX to React.createElement() calls but I'd love to read a bit more about when that transformation happens. I see some examples use a custom --loader for Node.js. Is that related? Do you use that loader to pass imported things through Babel?

This may be the answer to the question I have regarding custom components as those will not render using react-dom or any other packages:

import { renderToPipeableStream } from 'react-dom/server'

function Button() {
  return <button>Hi</button>
}

renderToPipeableStream(React.createElement(Button.type, Button.props, Button.props.children))
// Error!

7. Is there a place for a more developer-friendly API?

Imagine I want to build a tool on top of the RSC protocol. Do you really have to implement those server endpoints by myself? Analyze text/x-component, decode the Server Actions? What happens if React changes how those behave? This looks like it would benefit greatly from a higher-level public API.

Fundamental questions

  1. Can we please collaborate and come up with a series of diagrams that explain the underlying implementation of RSC incrementally? Things like: okay, there are 2/3/4 parts to an RSC:
  • Server part, where you have a GET / endpoint that takes a component and pipes its render stream to the response to return the initial, non-interactive HTML from the server.
  • Server part, were you also have a GET / for some reason but now it uses a different DOM binding that doesn't return an HTML but instead some serialized representation of the component tree (i.e. 0:[$, "<button>", ...]).
  • Server part, where you have a POST / endpoint that resolves any Server Actions.
  • Some other part, that takes the serialized representation of the component tree, feeds it another DOM binding to then hydrate the Root.

This would be gold. I'm convinced this will be useful to anybody getting to use RSC. Please, let's do this and not be shy on technical details (that's why I mentioned "incrementally" so anyone can drop off at the level they feel comfortable).

I know @kentcdodds is working on the RSC workshop on EpicWeb.dev and I think he'd be over the moon to have a set of such diagrams to show to his students. I know they'd be tremendously helpful to me as I'm trying to wrap my head around testing all this.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions