Automatically inject CSS resources into RSC stream#10067
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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-rscfrom 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
Resourcesautomatically. 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.$$typeofandComponent.prototype.isReactComponentwhich 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
preinitfunction to load CSS eagerly, as soon as a dynamic import is called. We track dependencies created insideReact.lazyand 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.