-
Notifications
You must be signed in to change notification settings - Fork 49.9k
React server dom vite #31768
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
React server dom vite #31768
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
| }, | ||
| "dependencies": { | ||
| "@jacob-ebey/react-server-dom-vite": "19.0.0-experimental.14", | ||
| "@jacob-ebey/vite-react-server-dom": "0.0.6", |
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.
Ideally it should be possible to install only react-server-dom-vite (from React) and the official vite stuff. At least for the bare minimum. You can always have special stuff in bigger frameworks but just for the core integration. As it is right now you need to install this third party thing.
It also makes it hard for us to make suggestions for how to improve the layering between the packages (and the dependency injection protocol). E.g. we can't change anything in React without also changing this package in lock step.
Can this package (@jacob-ebey/vite-react-server-dom) just be inlined into the React repo?
Either into the fixture for things related to just wiring up the host, or if they're related to the vite plugin itself then it can move into react-server-dom-vite.
For example, all that virtual file and manifest generating stuff seems like it should be living inside react-server-dom-vite rather than every user have to reimplement in different ways.
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 implementation inside react-server-dom-vite can be completely different between development and production if needed. We can compile a version for each.
I believe this is possible one day but we're not there yet. I'm not happy with the protocol for any of the existing bundlers an we're still adding and changing features. There's also certain things like The idea is that also ideally there wouldn't be a need for a plugin author if it was just natively built-in (or official plugin) to Vite like it is in Parcel. So the idea is that if code starts off living in One day I hope we can standardize on a protocol just like how require became a pseudo-standard and it can just be |
|
@sebmarkbage in reply to both comments: I could inline the plugin, but like the webpack version what is the point if it's not the implementation used outside the fixture? Just like the webpack implementation, no one actually uses it. All the different If the "touch points" were exposed as they are here, there is no need or bundler specific packages, and you (react) could simplify and say "RSC is ready for everyone who is willing to implement this API" instead of "RSC is ready for framework authors". Why compile a version for each instead of exposing a generic API that allows me, or I hope I'm not missing something, but the two concepts here are "info to dynamically load something", and "how to dynamically load that thing". That's what I've implemented and hope it wasn't out of naivety. |
|
I'll roll the plugin into here as the next step, but exposing a programatic manifest is the piece I'd like to see as part of core React. It feels very limiting to restrict "how to load things" behind a layer that specific to whoever decided to implement the bundler plugin. |
…hide internal module loading / encoding API behind a more base plugin
…est` to hide internal module loading / encoding API behind a more base plugin" This reverts commit bb66c49.
React server dom vite mini fixture
|
Thanks @hi-ogawa for rolling a more minimal fixture. |
|
Thanks @jacob-ebey for putting this together and thanks React team for quick review! After talking with Jacob, I thought it would help React team if they can see the overall picture of what's currently implemented in framework level (and not Vite core), so I made a minimal example while learning this manifest API and suggested to include it as fixture here. I hope this demonstrates how things are wired together and if you have any suggestion for improvement, I'm interested to hear 🙏 The programatic manifest API Jacob proposed here makes sense to me. Folks in the Vite ecosystem is mostly hacking around
As seen in the minimal fixture, Vite core feature to help RSC is mostly just Vite 6's environment API (and even on Vite 5, currently people are getting around the limitation by managing multiple Vite instances). At this point, we don't have a such blessed official plugin yet and each framework is rolling out an own plugins (which is a part of an entirely separate Vite framework). Even if we eventually have something like that (like we currently have |
|
It's still to unopinionated. We want you to have an opinion about the right way of doing things for Vite. E.g. there's a bunch of little issues here (like sync module invocation and CSS loading) that we can discuss in a follow up or I can even fix myself. There's many things we don't like about the current interface that we want to improve. If there's 8 different ways of doing things for Vite we can't go around having a discussion about it in each one. If it's unopinionated then you don't need us, you can just publish a fork and keep it up to date. The point of landing something here is that it becomes the opinionated "official" way to integrate with Vite and something the React team commits to maintain. We should able to change details here and downstream forks follow. E.g. we change here first all the time and then Next.js forks in the plugin loaders have to scramble to follow. I'm not that rigid on exact interface. It can be built up of building blocks like syntax parsing plugins etc that are defined elsewhere. It needs some coherent opinion about what it should look like coming together. |
|
For the example, we can say that the strategy in |
|
@sebmarkbage If you have the time / energy, I'd appreciate if you'd spend a bit of them to address what's important to you here. As @hi-ogawa mentioned, the Vite ecosystem is pretty "piece things together". CSS loading for example is implemented individually by everyone and does not expect to be standardized. I'm also unsure of what you mean by sync module loading in an inherently async ESM world (unless you mean a module cache for subsequent use?). It probably doesn't help convince you of the interface, or being an appropriate building block in the Vite ecosystem, but here is this same API being used to run in Cloudflare's Workerd environment on top of Vite (interplay between this and other Vite ecosystem plugins): https://github.com/jacob-ebey/cf-react-server-template/blob/482008b8fd9d43cf8ebfbc992c899c275043370b/vite.config.ts#L18 |
|
@jacob-ebey @hi-ogawa Does it make sense to try and aim to have this as an official |
|
cc @yyx990803 who has kindly offered to help collaborate on this. For context, to summarize what @sebmarkbage said above: our goal in having these packages live in the React repo are to collaborate with bundlers to understand the layering, and design a protocol that works across all of them. We're still changing features and refining the protocol for all of the existing bundlers to try and find the right layering. By having the implementation in the React repo, we can make suggestions for how to improve the layering between the packages. If we make updates to the protocol, we can update it in all bundlers in one PR, and versioned together, instead of spread out across many packages. One day we hope we can standardize on a protocol just like how For this to work though, we really need to focus on one way of doing it (since more opinions increases the difficulty) and it needs to all live in the repo. If that doesn't work for ya'll, you can just publish a fork and keep it up to date. It would make collaboration and making suggestions more difficult, but realistically so would trying to do it all here. The benefit of landing something here is that it becomes the opinionated "official" way to integrate with Vite and something the React team commits to maintain along with you. |
|
I'm just going to drop more experimentation here in-case it helps. https://github.com/jacob-ebey/vite-environment-attributes This implements a concept of |
|
For anyone interested, I made an implementation that works today https://github.com/nicobrinkkemper/vite-plugin-react-server. It uses react-server-dom-esm and configures vite/rollup to "just work" at least in the basic scenario's we used to use something like create-react-app. Of course if a vite loader does eventually drop, I'm happy to put that in instead and let you know the results |
|
Update: as of React 19.1, Parcel now has support for RSC in the stable React channel. I'm curious if you've had a chance to look at this @yyx990803? I see two options here:
If we choose (1), I'm happy to push the changed needed. |
|
Some feedback from our side after building Alternative RSC designWe'd like to experiment with alternative RSC designs to address what we perceive to be design issues. In order to experiment with real-world apps, we would like to enable We wonder whether this has been discussed before and where we can share RSC ideas with others. A central place for public discussions around RSC would be helpful. (There was a private Facebook group but it doesn't seem to be active anymore.) Progressive adoption is key for us to experiment in real-world scenarios. Without it, most users will stick with Vite Environment API vs Import QueriesWe are questioning whether (artificially?) splitting the server build into Vite’s Environment API makes a lot of sense for targeting different deployment environments, but we wonder whether it's the right abstraction for RSC. Maybe import queries (e.g. |
I believe our general preference is Option 1. Since @jacob-ebey would probably need some direction, |
|
Sorry for the late follow up... GitHub notifications of old PRs often get buried. To share some context here:
|
|
Thanks everyone for the discussion around Vite RSC integration. In my opinion, Jacob's abstract manifest API should work well for the Vite ecosystem (both now and future), but I understand that the API surface seems unnecessarily general, which can blur Vite-side technical details and hinder collaboration with the React team. I have an idea to reduce the API surface and clarify the need for Vite integration, which is to allow only customizing the async module loading mechanism. (TLDR, my proposed API is But, before diving into that, let me provide some background on some technical details of RSC integration in today's Vite. I'm hoping this clarifies what's minimally needed and desired for the Vite ecosystem in general.
Additionally, the following two constraints are more fundamental to the current Vite bundler architecture, so they are likely not solvable by any design we explore for
However, as Evan said, in the future with Rolldown, Vite will have a full-bundled dev mode, and that can eliminate Given the above context, the available options seem to be either:
Either way, I think this is a great opportunity to start collaborating with the React team, so I would be happy to answer any questions from both the React team and the Vite framework side and help the process. Back to my opinion, I think the first option is already beneficial for the Vite ecosystem today (and it can also be beneficial for the future Rolldown-based Vite). As one idea to reduce and clarify the API surface and to have easier collaboration with the React team, what I propose is |
|
I am entrusting @hi-ogawa and the community with the Vite implementation. Closing this and expect a followup from the Vite team. |
|
Hey @hi-ogawa thanks for jumping in, we're really excited for this collaboration both for the React ecosystem using Vite, and hopefully also for the Vite ecosystem not using React (if directives become more of a standard than a React specific thing). Option 1 seems great, the For the CSS, although it is more of a framework concern, it would be good to show how that's intended to work in the fixture, so CSS can load in parallel to rendering. Some more context in the thread here. Same for async module loading (context, and context). Also linking the prior attempts for Vite, because they have a lot of context too: Do you want to open a PR? |
|
@rickhanlonii Thanks for the pointers. Yes, I'm planning to create a new PR with past PR's reviews in mind. I'm still iterating a bit how to split the concern in
I agree that automatically ssr-ing preload link is desired, but right now I have a slightly different idea for that without going through current "prepare destination" flow (but still somewhat baked in
For now I'm not taking css into account and it's left for the framework (and myself) to explore. For fixture, I'll add simple single css entry point scenario first, then if desired, I can extend that to cover a basic css import collection. |
Summary
This adds a new
react-server-dom-vitepackage implementing the RSC touch points in a way that is suitable for use with the Vite bundler.Differences from other implementations:
Other implementations prescribe a "manifest" format that plugin authors must implement and
react-server-dom-xyzpackages accept to know how to do bundler specific things (__webpack_require__, etc.).Instead, this package implements the second argument to the encode and decode bookends with an API that puts plugin authors in control of encoding and loading references.
This
runtime-manifestAPIs looks like this:An example implementation supporting arbitrary Vite runtimes through the Environments API can be found here: https://github.com/jacob-ebey/vite-plugins/blob/2ffebb24e284a4bb809cc6cbc0fcbc094b136c4a/packages/vite-react-server-dom/src/index.ts#L233
Peeking at the Plugin implementation, you'll notice the different shapes of the
ClientReferenceMetadatabetween development and production, as well as the different implementations ofClientReference'sgetandpreload.This is partially due to Vite's development philosophy, as well as the lack of a global module management system such as the webpack or parcel caches.
Note: I've published an experimental version of this package under
@jacob-ebey/react-server-dom-vitealong with a Vite plugin implementation for experimentation and use in the fixture.Side note: I believe the implementation of a package like this would allow the webpack, parcel, esm, etc. implementations to simplify and focus their concerns on implementing this layer. It would also make switching bundlers / environments more:
reactFunc(node, SWAP_ME())instead ofSWAP_ME(node, ALSO_SWAP_ME).How did you test this change?
I'm implemented a fixture that can be found and ran at
fixtures/flight-vite. I've also implemented basic unit tests that can be found atpackages/react-server-dom-vite/src/__tests__/ReactFlightViteDOM-test.js.