-
Notifications
You must be signed in to change notification settings - Fork 47.3k
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
Implement react-server-dom-parcel #31725
Conversation
# Conflicts: # scripts/rollup/bundles.js # scripts/rollup/validate/eslintrc.umd.js
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
export function preloadModule<T>( | ||
metadata: ClientReference<T>, | ||
): null | Thenable<any> { | ||
return Promise.all(metadata.bundles.map(url => parcelRequire.load(url))); |
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.
Is it possible that this will ever be empty? Such as if it's a module that's part of the core runtime or something? If so, it could be good to return null in that case.
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.
At the moment I don't think it's possible, but could be in the future I think, e.g. if the bundler knows that everything needed will already be available on the page. I'll add that condition.
It would be good to have something like the
You can put them for this package on DefinitelyTyped potentially. However, you might also want to publish a wrapper library that either depends on |
Copy/pasting https://github.com/parcel-bundler/rsc-examples/tree/main into the fixtures repo might be enough? |
nonce: ?string, | ||
metadata: ClientReferenceMetadata, | ||
) { | ||
return; |
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.
By not implementing this, the thing you lose out on is the ability to emit early loading of the modules during SSR. So it would have to wait until hydration to kick off loading the bundles that will later be needed.
It's a little convoluted the way that's wired up in the other packages to only do that for SSR and not in the browser.
But the key is that you just need some way to provide the absolute URL that the browser would load.
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 <Resources>
component we have inserts scripts and stylesheets needed by the page based on dependencies in the module graph, so I thought this wasn't needed at first. But thinking about it more, in theory there could be bundles that are discovered conditionally during render (e.g. if a component does a dynamic import()
). I can add something similar to what the other packages are doing.
Looks like this only supports preloading JS and not CSS though? So in the case where resources were discovered during render, we'd preload the JS but the CSS would only be discovered during hydration. Or am I missing something?
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.
Actually I think we need to find a way to render a <link>
element in the tree during render for dynamic imports. Otherwise there will be FOUC before hydration. This can be done manually by rendering <Resources>
inside each dynamically imported component. I guess that would solve the issue for JS too. Would be cool if this could happen automatically 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.
@sebmarkbage I think I could potentially generate a proxy module when you use dynamic import()
inside a server component (either for another server component or a client component), and emit wrappers that would insert the necessary <link>
elements.
I think this can't be done in prepareDestinationForModule
since that only knows about client components, and not about css needed for server components (when there are no client components). And it should suspend on the css to avoid FOUC (I think preinit does not?).
The hard part is knowing what is a valid component that should be wrapped by the proxy. We wouldn't want to unintentionally change the return type of a non-component function by wrapping it with extra JSX elements.
Should there be a way of annotating server component exports with their resources so that stylesheets can be inserted automatically? Manually adding <Resources>
in every component that you dynamic import()
might be hard to remember.
id: metadata[ID], | ||
name: metadata[NAME], | ||
bundles: metadata[BUNDLES], | ||
}; |
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.
Is there a reason this isn't just an identity function returning the same type of object?
* @flow | ||
*/ | ||
|
||
export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; |
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.
These have changed names now but nbd. I'll take a pass over to make sure all changes are caught up once we land.
…b/main/examples/server/ This allows us to test using the local build.
Until react-bot is added as an owner.
I pushed a fixture that just copies the SSR example from https://github.com/parcel-bundler/rsc-examples/tree/main/examples/server
EDIT: Got it working but I think there's a way to mess up the parcel-cache so I sometimes get into a broken state. |
These get overridden anyway.
89773da
to
2a8dcc4
Compare
This runs watch and NODE_ENV=development.
I'm going to merge since this is in a good enough to iterate on. Fixture seems to be working. |
One thing that could be better is the source mapping. RSC wires up source mapping using It's supposed to return the URL of the source map for that server file from the client. This could maybe be left to a user space option but it would be even better if it was built-in somehow. |
I was wondering if I should do that. Is the plan for these bundler integrations published by React to follow semver or always be internal with the intent that they should be wrapped by something higher level?
Yeah I meant to look into this. I think we can add something to Parcel's dev server, which is also used for HMR. |
Follow up to #31725. I diffed against the Turbopack one to find any unexpected discrepancies. Some parts are forked enough that it's hard to diff but I think I got most of it.
Followup to #31725 This implements `prepareDestinationForModule` in the Parcel Flight client. On the Parcel side, the `<Resources>` component now only inserts `<link>` elements for stylesheets (along with a bootstrap script when needed), and React is responsible for inserting scripts. This ensures that components that are conditionally dynamic imported during render are also preloaded. CSS must be added to the RSC tree using `<Resources>` to avoid FOUC. This must be manually rendered in both the top-level page, and in any component that is dynamic imported. It would be nice if there was a way for React to automatically insert CSS as well, but unfortunately `prepareDestinationForModule` only knows about client components and not CSS for server components. Perhaps there could be a way we could annotate components at code splitting boundaries with the resources they need? More thoughts in this thread: #31725 (comment)
This adds a new
react-server-dom-parcel-package
, which is an RSC integration for the Parcel bundler. It is mostly copied from the existing webpack/turbopack integrations, with some changes to utilize Parcel runtime APIs for loading and executing bundles/modules.See parcel-bundler/parcel#10043 for the Parcel side of this, which includes the plugin needed to generate client and server references. https://github.com/parcel-bundler/rsc-examples also includes examples of various ways to use RSCs with Parcel.
Differences from other integrations:
"use client"
directive is seen, the environment changes and Parcel creates a new client bundle for the page, combining all client modules together. CSS from both client and server components are also combined automatically.react-server-dom-parcel
automatically.<Resources>
component is also generated by Parcel to render the<script>
and<link rel="stylesheet">
elements needed for a page, using the relevant info from the bundle graph.Note: I've already published a 0.0.x version of this package to npm for testing purposes but happy to add whoever needs access to it as well.
Questions