Automatically inject CSS resources into RSC stream #10067
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This removes the need to manually render a
<Resources />
component at each bundle group boundary (e.g. entry pages and dynamic imports). In practice this could be error-prone because where you imported@parcel/runtime-rsc
from would change the behavior. That meant you couldn't move the Resources component into a common component, e.g. a layout, because it would potentially result in different resources than the actual page.Instead, this injects the equivalent of
Resources
automatically. It works by generating a proxy module that replaces the resolution of dependencies that resolve to a different bundle group. This is basically a React-specific version of what the JS runtime does for dynamic imports.The goal is to inject
<link rel="stylesheet">
elements as siblings of whatever is rendered from the module. This way it will not only be loaded as a side effect on the client, but also rendered by React during SSR. This means you can use dynamic import to choose which components to render conditionally (e.g. based on data), and only the necessary code will be sent to the client. Not only that, since the components needed are discovered during SSR, there are no waterfalls on the client.To do this, the runtime attempts to detect if a function is rendered as a React component (and not just called). It uses a Proxy to watch for accesses of
Component.$$typeof
andComponent.prototype.isReactComponent
which React reads prior to calling the function. If these are accessed, we return a fragment containing both the resources and the original element.We also use React DOM's
preinit
function to load CSS eagerly, as soon as a dynamic import is called. We track dependencies created insideReact.lazy
and skip waiting for them for the dynamic import promise to resolve. In this case, they will be rendered into the React tree and React will suspend until they are ready. This allows React to start rendering earlier if the CSS takes longer than the JS to load.