feat(rsc): support custom server function directives#1246
Conversation
79377ac to
c44f424
Compare
205122e to
1aabe31
Compare
1aabe31 to
142fb07
Compare
commit: |
There was a problem hiding this comment.
Can you explain higher level motivation (than implementation explanation)? From a quick look, I cannot tell things like:
- whether this includes some fixes in existing
transformswrap/hoist and thus existing builtin"use server"support. - whether new plugin
vitePluginServerFunctionDirectivesneeds to be inside rsc plugin. for example, if we land changes intransforms/*, then can you buildvitePluginServerFunctionDirectivesoutside based on the exported transform utils? - whether
vitePluginServerFunctionDirectiveshas some new mechanism compared to current builtin"use server"support that also benefit for builtinuse serverto have.
Yeah, there's some improvements to how object & class methods and named expressions are treated, which the 'use server' directive will benefit from. The other part is how certain forms that can't be hoisted safely are handled and tracking metadata about parameters, which is mainly for custom directives to use. I can break those out into separate PRs if needed.
I believe we may be able to, however, the more I was looking at some of the 'use cache' directive stuff we were having to do as I started fixing bugs, the more it felt like we were touching more and more on the internals of how the plugin processes directives. By that, I'm referring to:
It felt a lot to me like we began implementing our own generic approach to register custom directives rather than there being an API for one, and in the process, attaching onto everything the RSC plugin was already doing internally.
The 'use server' directive could actually be changed to route through this new plugin as well. I was originally going to do that and have one single way for people to register custom directives that was also used for registering the 'use server' directive by default. The way this works was based on how that directive works as its starting point. Couldn't help but feel a tad risky without proving the new approach works well before doing that... |
5586d70 to
e539c58
Compare
|
Thanks for the prereleases :) Exposed a couple of issues when integrating which codex has worked though. Changes pushed to allow importing an additional runtime for the wrap callback to use, and adding the (opt-in) ability to allow cached RSC values containing server references to be replayed/re-rendered by frameworks by preserving them, and also fixing some issues with references across environments. You can see what the framework side of this might look like in https://github.com/cloudflare/vinext/pull/1871/changes Sorry about that. |
|
+1 to @hi-ogawa's question about whether We maintain a long-developed RSC framework (router + RSC runtime on In our model, Agreeing with @hi-ogawa's direction to land the These two would let frameworks that don't model |
|
Hi @ivogt, thanks for the feedback :)
for what it's worth, our initial implementation for 'use cache' is full of bugs, missing functionality, and poorly done - i wouldn't use it as an example 😅. This PR came from when I was looking at fixing some of our issues.
This API is intended to be for directives that should be server functions that can also be called from client components, hence the naming - similiar to how the 'use server' directive would create functions that you can call from other environments. https://react.dev/reference/rsc/server-functions It sounds like you're not using server functions in your use case, so this feature would not necessarily be something that you would use, unless your functions are intended to be callable from the client. From the sounds of it, your use case is similar to something like React's Please let me know if I'm mistaken in my understanding of what you're doing though. |
|
Thanks for the detailed reply. One precision so we're on the same page: we do use server functions heavily, for actions, via the built-in On the So nothing for |
Sorry, I’m not sure I fully understand the last part. I’m not proposing to remove the existing exports - i agree they should stay available as removing them would be a breaking change. When you say "without needing this in-core", do you mean that "server-local" directives like yours shouldn't need to use the new API? Or are you suggesting that the RSC plugin shouldn’t include an API for custom directives that create server references? I would probs agree that server-local ones shouldn't need this sort of thing, but im less clear on the argument for the latter, as this API would be bringing together handling of manifests, proxies, arg binding, encryption, normalization, serialization, etc., into one shared approach. |
|
I think I might have over-worried earlier — I thought that landing this pr it would change how server actions "use server" (e.g. getNormalizedId and serverReferenceMetaMap shape) get handled for us. It seems like it doesn't. Also that "use cache" (by adding the registerServerReference(...)) would effectively get baked into the plugin so we couldn't keep our own transform. But the Appreciate you walking through it. One genuinely useful flag while you're in the shared transforms: |
The types for
In fact, I think this could potentially be an improvement by honouring the public types. There are cases where the plugin may not be able to statically analyse the value of a variable as a function. Take factory functions that return callbacks as an example - there's a decent chance they might not be statically analysed as resulting the value of the variable being a function. I haven't tested whether they are or not, but the public types would allow you to have better control over that scenario if it's accurately returning undefined. |
Summary
Adds an experimental
serverFunctionDirectivesAPI for framework directives such as Next.js-style"use cache".This is additive to the existing
rsc:use-serverimplementation:vitePluginUseServertransform remains in placevitePluginUseServeris preserving custom manifest metadata during cleanup and merging custom export names when a module also has"use server"API
Reused functionality
The custom-directive plugin delegates to the same transform helpers used by
"use server"for:It also supports object methods, static class methods, destructured exports, named re-exports, stable custom hoist names, stateful regular expressions, and export filtering before async validation.