-
Notifications
You must be signed in to change notification settings - Fork 48.6k
Add Experimental Flight Infrastructure #16398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ReactDOM: size: 0.0%, gzip: -0.0% Details of bundled changes.Comparing: 6f86294...9650647 react-dom
react-noop-renderer
react-server
react-flight
Generated by 🚫 dangerJS |
How does colocation work with this? Isn't the mentioned example of
(where e.g. |
Yea, collocated in the sense of two files next to each other. An entangled pair. Not in the same file. The rationale is that currently it's really hard to tell how different parts of a file might be entangled. E.g. which imports are client-only or server-only? is this value visible to the client? Collocating in completely different parts of a file isn't much easier to keep track of. It's not as if it's in the same expression. A big part of this design is just the explainability. It's easy to tell what code is server and which is client this way. |
Can you explain the API a bit? I’ve read the tests and still a bit confused how pieces are supposed to fit together and why host nodes are model output. |
@gaearon No. This is the infra PR, not a project review. :) The host nodes are only there to demonstrate that there is some connection to the "server renderer" format. Not the final implementation. This is just plumbing. |
@@ -0,0 +1,144 @@ | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious, why put this in react-server instead of react-flight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly because both Fizz and Flight depend on ReactServerHostConfig/ReactServerFormatConfig so it lets me avoid hoisting those concerns to a third package. It's quite likely that the two servers would be running in the same machine and interleaved. So you likely want to version them together too.
It gets awkward now that I'm adding a client API too which needs its own package or join react-reconciler
.
It's not that important though since these are all not the encouraged APIs other than for custom builds. The public API is the react-dom
entry points. We don't even own the react-server
npm name so will likely change.
let model = { | ||
title: 'Title', | ||
content: { | ||
__html: <HTML />, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking that I'm following what's happening here: "model" values can render components, which are (at least for now) effectively rendered on the server and sent down as an HTML string (this is the "E.g. a host component tree can be flattened into raw HTML." from your description, right?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea. The HTML component is actually just a Model function. Then that model happens to contains "host" components (leaves) which are flattened into HTML. This will likely need to be much more clever to protect against XSS attacks like #3473 and to allow targeting nested nodes with client components etc.
I could also do return { __html: <div>...</div> }
inside the HTML component since it's just a Model function and can return arbitrary data structures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nice thing about this pattern is that if you have a tree of stateless functional components, the same code can be one shot rendered like this, or client rendered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since it's just a Model function and can return arbitrary data structures
Can you clarify in your current mental model: Is a Model function actually a component (i.e. can I use hooks in it), or are you using <HTML />
here for sugar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Model function can not use hooks. It's not a client-side component so it cannot have effects or state. (We could potentially let it have access to useContext though.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it suspend? If not, how can it fetch any async data?
I know this is just a plumbing PR, but it would be super helpful if you could include a small end-to-end example 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s one possible solution but that’s really not decided. It could be async functions, it could be something else. :)
24e9362
to
9650647
Compare
renderResult(json); | ||
return; | ||
} | ||
json += decoder.decode(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs a second argument {stream: true}
in order to properly handle the case that a chunk boundary splits a codepoint, and then in the if
above, add
json += decoder.decode();
to finish. https://encoding.spec.whatwg.org/#example-end-of-stream
Demonstrates the streaming protocol.
Size changes (stable)ReactDOM: size: n/a, gzip: n/a Details of bundled changes.Comparing: 3497ccc...e5c85fd react-dom
react-noop-renderer
react-server
react-flight
|
Size changes (experimental)Details of bundled changes.Comparing: 3497ccc...e5c85fd react-dom
react-noop-renderer
react-server
react-flight
|
This adds some plumbing for the Flight experiment.
We'll likely need this to (optionally) support a streaming protocol. This is the same as Fizz (streaming server rendering). There is quite a bit of wiring to make that work. This infra creates a build for each environment with zero overhead cost.
We have one build for Node which is the default. We currently have a separate build for a Browser environment (with browser stream support). This is useful for Service Workers or just debugging since the browser debugger is better than Node. We'll likely also have a FB specific one.
ReactServerHostConfig configures the runtime environment and has various overrides.
Additionally, we likely want to special case the encoding format for some parts of the protocol depending on what you're rendering into. E.g. a host component tree can be flattened into raw HTML. Therefore, we want one entry point for each renderer type. Not a single one for the whole project. This entry point is
react-dom/unstable-flight
.ReactServerFormatConfig configures the output format configuration.
Both of these are shared between Fizz and Flight. So they each get the host config and the format config compiled in.
The second two commits show the actually relevant files.
cc @timneutkens