-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
[Flight] Add bundler-less version of RSC using plain ESM #26889
Conversation
I'm currently using
Are those issues specific to the The general question should be: How strongly would you suggest to avoid using |
It’s not so much that you can’t use it, after all the |
Btw we’re happy to host a Vite version upstream without hacks if a reasonably reusable and compatible version that follows the patterns of the others. |
That makes sense. (that's something I'm interested in.)
It would be great! I'd first explore if |
I have been working on something. I didn't know if the react team is down for an integration there but ill assemble the pieces and put out a PR if the interest is there |
const action = (await import(filepath))[name]; | ||
// Validate that this is actually a function we intended to expose and | ||
// not the client trying to invoke arbitrary functions. In a real app, | ||
// you'd have a manifest verifying this before even importing it. |
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 would require a bundler, right? Just to confirm. Or does the loader do this somehow
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.
It's pretty simple because it'll have been tagged as a server reference by the loader. So verifying is trivial. The decodeReply/decodeAction also has this issue atm.
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 part I'm missing is, importing a file calls its top-level side effects, so isn't this a possible vector if the filename is arbitrary?
RejectedThenable, | ||
} from 'shared/ReactTypes'; | ||
|
||
export type SSRManifest = string; // Module root path |
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.
woah
|
||
let stashedGetSource: null | GetSourceFunction = null; | ||
let stashedResolve: null | ResolveFunction = null; | ||
|
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.
Are all of these exports needed or is some targeting older Nodes? Should we start dropping those?
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.
Some are targeting older Node yea.
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.
very cool
This isn't really meant to be actually used, there are many issues with this approach, but it shows the capabilities as a proof-of-concept. It's a new reference implementation package `react-server-dom-esm` as well as a fixture in `fixtures/flight-esm` (fork of `fixtures/flight`). This works pretty much the same as pieces we already have in the Webpack implementation but instead of loading modules using Webpack on the client it uses native browser ESM. To really show it off, I don't use any JSX in the fixture and so it also doesn't use Babel or any compilation of the files. This works because we don't actually bundle the server in the reference implementation in the first place. We instead use [Node.js Loaders](https://nodejs.org/api/esm.html#loaders) to intercept files that contain `"use client"` and `"use server"` and replace them. There's a simple check for those exact bytes, and no parsing, so this is very fast. Since the client isn't actually bundled, there's no module map needed. We can just send the file path to the file we want to load in the RSC payload for client references. Since the existing reference implementation for Node.js already used ESM to load modules on the server, that all works the same, including Server Actions. No bundling. There is one case that isn't implemented here. Importing a `"use server"` file from a Client Component. We don't have that implemented in the Webpack reference implementation neither - only in Next.js atm. In Webpack it would be implemented as a Webpack loader. There are a few ways this can be implemented without a bundler: - We can intercept the request from the browser importing this file in the HTTP server, and do a quick scan for `"use server"` in the file and replace it just like we do with loaders in Node.js. This is effectively how Vite works and likely how anyone using this technique would have to support JSX anyway. - We can use native browser "loaders" once that's eventually available in the same way as in Node.js. - We can generate import maps for each file and replace it with a pointer to a placeholder file. This requires scanning these ahead of time which defeats the purposes. Another case that's not implemented is the inline `"use server"` closure in a Server Component. That would require the existing loader to be a bit smarter but would still only "compile" files that contains those bytes in the fast path check. This would also happen in the loader that already exists so wouldn't do anything substantially different than what we currently have here. DiffTrain build for [f181ba8](f181ba8)
Could you please publish (btw, found this: https://www.npmjs.com/package/@jacob-ebey/react-server-dom-esm ) |
This PR updates the vendored react dependencies using `pnpm sync-react` ### React upstream changes - facebook/react#27028 - facebook/react#27027 - facebook/react#27019 - facebook/react#26954 - facebook/react#26987 - facebook/react#26985 - facebook/react#26933 - facebook/react#26625 - facebook/react#27011 - facebook/react#27008 - facebook/react#26997 - facebook/react#26989 - facebook/react#26955 - facebook/react#26963 - facebook/react#26983 - facebook/react#26914 - facebook/react#26951 - facebook/react#26977 - facebook/react#26958 - facebook/react#26940 - facebook/react#26939 - facebook/react#26887 - facebook/react#26947 - facebook/react#26945 - facebook/react#26942 - facebook/react#26938 - facebook/react#26844 - facebook/react#25510 - facebook/react#26932 - facebook/react#26896 - facebook/react#26913 - facebook/react#26888 - facebook/react#26827 - facebook/react#26889 - facebook/react#26877 - facebook/react#26873 - facebook/react#26880 - facebook/react#26842 - facebook/react#26858 - facebook/react#26754 - facebook/react#26753 - facebook/react#26881 ### Related Closes #49409 (by facebook/react#26977) fix NEXT-1189 Co-authored-by: Shu Ding <g@shud.in>
Fixes #49409 ### React upstream changes - facebook/react#27045 - facebook/react#27051 - facebook/react#27032 - facebook/react#27031 - facebook/react#27029 - facebook/react#27028 - facebook/react#27027 - facebook/react#27019 - facebook/react#26954 - facebook/react#26987 - facebook/react#26985 - facebook/react#26933 - facebook/react#26625 - facebook/react#27011 - facebook/react#27008 - facebook/react#26997 - facebook/react#26989 - facebook/react#26955 - facebook/react#26963 - facebook/react#26983 - facebook/react#26914 - facebook/react#26951 - facebook/react#26977 - facebook/react#26958 - facebook/react#26940 - facebook/react#26939 - facebook/react#26887 - facebook/react#26947 - facebook/react#26945 - facebook/react#26942 - facebook/react#26938 - facebook/react#26844 - facebook/react#25510 - facebook/react#26932 - facebook/react#26896 - facebook/react#26913 - facebook/react#26888 - facebook/react#26827 - facebook/react#26889 - facebook/react#26877 - facebook/react#26873 - facebook/react#26880 - facebook/react#26842 - facebook/react#26858 - facebook/react#26754 - facebook/react#26753 - facebook/react#26881 --------- Co-authored-by: Jiachi Liu <inbox@huozhi.im>
This PR updates the vendored react dependencies using `pnpm sync-react` ### React upstream changes - facebook/react#27028 - facebook/react#27027 - facebook/react#27019 - facebook/react#26954 - facebook/react#26987 - facebook/react#26985 - facebook/react#26933 - facebook/react#26625 - facebook/react#27011 - facebook/react#27008 - facebook/react#26997 - facebook/react#26989 - facebook/react#26955 - facebook/react#26963 - facebook/react#26983 - facebook/react#26914 - facebook/react#26951 - facebook/react#26977 - facebook/react#26958 - facebook/react#26940 - facebook/react#26939 - facebook/react#26887 - facebook/react#26947 - facebook/react#26945 - facebook/react#26942 - facebook/react#26938 - facebook/react#26844 - facebook/react#25510 - facebook/react#26932 - facebook/react#26896 - facebook/react#26913 - facebook/react#26888 - facebook/react#26827 - facebook/react#26889 - facebook/react#26877 - facebook/react#26873 - facebook/react#26880 - facebook/react#26842 - facebook/react#26858 - facebook/react#26754 - facebook/react#26753 - facebook/react#26881 ### Related Closes #49409 (by facebook/react#26977) fix NEXT-1189 Co-authored-by: Shu Ding <g@shud.in>
) This isn't really meant to be actually used, there are many issues with this approach, but it shows the capabilities as a proof-of-concept. It's a new reference implementation package `react-server-dom-esm` as well as a fixture in `fixtures/flight-esm` (fork of `fixtures/flight`). This works pretty much the same as pieces we already have in the Webpack implementation but instead of loading modules using Webpack on the client it uses native browser ESM. To really show it off, I don't use any JSX in the fixture and so it also doesn't use Babel or any compilation of the files. This works because we don't actually bundle the server in the reference implementation in the first place. We instead use [Node.js Loaders](https://nodejs.org/api/esm.html#loaders) to intercept files that contain `"use client"` and `"use server"` and replace them. There's a simple check for those exact bytes, and no parsing, so this is very fast. Since the client isn't actually bundled, there's no module map needed. We can just send the file path to the file we want to load in the RSC payload for client references. Since the existing reference implementation for Node.js already used ESM to load modules on the server, that all works the same, including Server Actions. No bundling. There is one case that isn't implemented here. Importing a `"use server"` file from a Client Component. We don't have that implemented in the Webpack reference implementation neither - only in Next.js atm. In Webpack it would be implemented as a Webpack loader. There are a few ways this can be implemented without a bundler: - We can intercept the request from the browser importing this file in the HTTP server, and do a quick scan for `"use server"` in the file and replace it just like we do with loaders in Node.js. This is effectively how Vite works and likely how anyone using this technique would have to support JSX anyway. - We can use native browser "loaders" once that's eventually available in the same way as in Node.js. - We can generate import maps for each file and replace it with a pointer to a placeholder file. This requires scanning these ahead of time which defeats the purposes. Another case that's not implemented is the inline `"use server"` closure in a Server Component. That would require the existing loader to be a bit smarter but would still only "compile" files that contains those bytes in the fast path check. This would also happen in the loader that already exists so wouldn't do anything substantially different than what we currently have here.
This isn't really meant to be actually used, there are many issues with this approach, but it shows the capabilities as a proof-of-concept. It's a new reference implementation package `react-server-dom-esm` as well as a fixture in `fixtures/flight-esm` (fork of `fixtures/flight`). This works pretty much the same as pieces we already have in the Webpack implementation but instead of loading modules using Webpack on the client it uses native browser ESM. To really show it off, I don't use any JSX in the fixture and so it also doesn't use Babel or any compilation of the files. This works because we don't actually bundle the server in the reference implementation in the first place. We instead use [Node.js Loaders](https://nodejs.org/api/esm.html#loaders) to intercept files that contain `"use client"` and `"use server"` and replace them. There's a simple check for those exact bytes, and no parsing, so this is very fast. Since the client isn't actually bundled, there's no module map needed. We can just send the file path to the file we want to load in the RSC payload for client references. Since the existing reference implementation for Node.js already used ESM to load modules on the server, that all works the same, including Server Actions. No bundling. There is one case that isn't implemented here. Importing a `"use server"` file from a Client Component. We don't have that implemented in the Webpack reference implementation neither - only in Next.js atm. In Webpack it would be implemented as a Webpack loader. There are a few ways this can be implemented without a bundler: - We can intercept the request from the browser importing this file in the HTTP server, and do a quick scan for `"use server"` in the file and replace it just like we do with loaders in Node.js. This is effectively how Vite works and likely how anyone using this technique would have to support JSX anyway. - We can use native browser "loaders" once that's eventually available in the same way as in Node.js. - We can generate import maps for each file and replace it with a pointer to a placeholder file. This requires scanning these ahead of time which defeats the purposes. Another case that's not implemented is the inline `"use server"` closure in a Server Component. That would require the existing loader to be a bit smarter but would still only "compile" files that contains those bytes in the fast path check. This would also happen in the loader that already exists so wouldn't do anything substantially different than what we currently have here. DiffTrain build for commit f181ba8.
This isn't really meant to be actually used, there are many issues with this approach, but it shows the capabilities as a proof-of-concept.
It's a new reference implementation package
react-server-dom-esm
as well as a fixture infixtures/flight-esm
(fork offixtures/flight
). This works pretty much the same as pieces we already have in the Webpack implementation but instead of loading modules using Webpack on the client it uses native browser ESM.To really show it off, I don't use any JSX in the fixture and so it also doesn't use Babel or any compilation of the files.
This works because we don't actually bundle the server in the reference implementation in the first place. We instead use Node.js Loaders to intercept files that contain
"use client"
and"use server"
and replace them. There's a simple check for those exact bytes, and no parsing, so this is very fast.Since the client isn't actually bundled, there's no module map needed. We can just send the file path to the file we want to load in the RSC payload for client references.
Since the existing reference implementation for Node.js already used ESM to load modules on the server, that all works the same, including Server Actions. No bundling.
There is one case that isn't implemented here. Importing a
"use server"
file from a Client Component. We don't have that implemented in the Webpack reference implementation neither - only in Next.js atm. In Webpack it would be implemented as a Webpack loader.There are a few ways this can be implemented without a bundler:
"use server"
in the file and replace it just like we do with loaders in Node.js. This is effectively how Vite works and likely how anyone using this technique would have to support JSX anyway.Another case that's not implemented is the inline
"use server"
closure in a Server Component. That would require the existing loader to be a bit smarter but would still only "compile" files that contains those bytes in the fast path check. This would also happen in the loader that already exists so wouldn't do anything substantially different than what we currently have here.