-
Notifications
You must be signed in to change notification settings - Fork 46.8k
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
[Float] stylesheet hoisting #24886
[Float] stylesheet hoisting #24886
Conversation
if (completedRootSegment !== null) { | ||
if (request.pendingRootTasks === 0) { | ||
// Flush the prelude if it exists | ||
const prelude = request.prelude; | ||
for (i = 0; i < prelude.length; i++) { | ||
// we expect the prelude to be tiny and will ignore backpressure | ||
writeChunk(destination, prelude[i]); | ||
} | ||
prelude.length = 0; | ||
|
||
// Flush resources | ||
writeResources(destination, request.resources); |
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.
If we have a completedRootSegment
it is safe to flush the prelude (we should consider barring use of the prelude after the root segment has flushed. This currently can't / doesn't happen but a future change could alter that)
Once we have flushed the prelude we can flush resources and then the segment.
} else { | ||
writeResources(destination, request.resources); |
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.
This maybe needs to be tuned up.
At the moment, if we flush before starting work we call writeResources which happens to be empty but we don't actually know that this is safe b/c writeResources might have it's own writable content that isn't related to the number of resources that exist. For now this works by coincidence.
Typically though the flushing will happen after we've done work and thus we'll only get here if we've completed writing the root in which case we can writeResources at any time and simply want them to be near the top so the browser (or other host) receives them first
fdea36b
to
8fe566f
Compare
This change implements Float for a minimal use case of hoisting stylesheet resources to the head and ensuring the flush in the appropriate spot in the stream. Subsequent commits will add support for client stylesheet hoisting and Flight resources. While there is some additional buildout of Float capabilities in general the public APIs have all been removed. The intent with this first implementation is to opt in <link rel="stylesheet"> use the more useful semantics of resources
Resources are implemented as a new fiber type HostResource which expect ref counting and hoisting semantics. Currently only react-dom supports this and it is only enabled if the `enableFloat` flag is true. When encountering a resource we don't append it to the parent host component like usual. In the commit phase the resource is "acquired" and if necessary a domElement is created and inserted into the Document head. If a HostResource fiber is deleted the resource is "released" and if that was the last referrer to that resource is is removed from the document. Hydration poses a special challenge. We want to skip over resources in hydration because they may not have a matching element during render. This will become more prevalent when Float apis like `preinit(...)` are available. However if the resource exists because of a component rendering we should ideally opt into ref counting semnatics. The current approach is to consume hydratable resources in commit (if any are acquired we opt into ref counting mode) and if there are any remaining we assume they are static resources and hoist them permanently.
This is a pared down PR with stylesheet hoisting for Flight / Fizz / Client.