Skip to content

fix(rsc): member expression usage binds unserializable variables#1155

Open
james-elicx wants to merge 2 commits intovitejs:mainfrom
james-elicx:james/binding-member-exprs
Open

fix(rsc): member expression usage binds unserializable variables#1155
james-elicx wants to merge 2 commits intovitejs:mainfrom
james-elicx:james/binding-member-exprs

Conversation

@james-elicx
Copy link

@james-elicx james-elicx commented Mar 21, 2026

Description

Objects that are used in server functions can contain fields that are not serializable for client components. However, the server function may only be accessing specific properties within the object.

This is another interesting bug I found when testing out Payload CMS with Vinext.

When this scenario happens, the member expression for the variable should be bound instead of the variable itself. This would allow a complex object to be passed around, while only accessing serializable fields on it.

For safety, it will fall back to binding the bare variable for computed member expressions and shadowed objects.

As before, regression tests mostly generated by AI, although I did do a couple of extra ones myself for additional cases.

@james-elicx james-elicx changed the title fix: member expression binding unserializable root variable fix(rsc): member expression binding unserializable root variable Mar 21, 2026
@james-elicx james-elicx changed the title fix(rsc): member expression binding unserializable root variable fix(rsc): member expression binding unserializable bare variable Mar 21, 2026
@james-elicx james-elicx changed the title fix(rsc): member expression binding unserializable bare variable fix(rsc): member expression usage binds unserializable variables Mar 21, 2026
Copy link
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this. The expected behavior around this isn't of course documented as React feature, but happy to have this after review. I think Next also had some old PR mentioning whether they go for it or not, so would be nice to check up if there was a rational for and against supporting this.

@hi-ogawa hi-ogawa self-assigned this Mar 22, 2026
@james-elicx
Copy link
Author

It's a massive 4,000 line file so a bit hard to navigate without working in it before, but I believe their binding candidates are represented as this Name struct which has a list of the parts to build up the full member expression.

There's a retain_names_from_declared_idents function which then goes through the Names that were captured and dedupes them to the outermost use (config.cookie.name + config.cookie -> only config.cookie being bound as it's required for both) which I haven't done in this PR and would be a potential future optimisation.

So it seems like they definitely take the approach of binding full member expressions rather than bare variables where possible.

@hi-ogawa
Copy link
Contributor

I think the reference I had in mind was this vercel/next.js#66464. It looked like this was one simplification path which they didn't eventually take. Are the examples brought up there something relevant to this PR?

@hi-ogawa
Copy link
Contributor

hi-ogawa commented Mar 22, 2026

Ah okay, it looks like that's indeed config.cookie.name + config.cookie case.

EDIT: Oh wait, so that's probably fixed in other PR by vercel/next.js#66601.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants