Skip to content

Conversation

@unstubbable
Copy link
Collaborator

@unstubbable unstubbable commented Feb 6, 2025

This PR includes a reduced test case of vercel/next.js#75726:

function Server() {
  const shared = {id: 42};
  const map = new Map([[42, shared]]);

  return <ClientComponent shared={shared} map={map} />;
}

This is serialized into the following RSC payload which the Flight Client was not able to resolve, because two chunks are blocked on each other:

1:I["0",[],"*"]
2:[[42,"$0:props:shared"]]
0:["$","$L1",null,{"shared":{"id":42},"map":"$Q2"}]

We can fix this by storing intermediary values (only elements for now) on the initializing chunk. When the fulfill listener in waitForReference is called with a lazy element that has a blocked chunk, which is not the current chunk, we can peek into the intermediary value of the referenced chunk to resolve a reference for a different chunk that's still blocked.

fixes vercel/next.js#72104

@react-sizebot
Copy link

react-sizebot commented Feb 6, 2025

Comparing: 93b58361d9c9632acdda76eb8a1a582d1ff9701a...b573e1c23e14671c93abc34effac2e465f31808f

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 515.48 kB 515.48 kB = 92.04 kB 92.04 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 558.52 kB 558.52 kB = 99.27 kB 99.27 kB
facebook-www/ReactDOM-prod.classic.js = 636.88 kB 636.88 kB = 111.92 kB 111.92 kB
facebook-www/ReactDOM-prod.modern.js = 627.20 kB 627.20 kB = 110.34 kB 110.34 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js +1.14% 82.03 kB 82.96 kB +1.36% 17.22 kB 17.46 kB
oss-stable/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js +1.14% 82.03 kB 82.96 kB +1.36% 17.22 kB 17.46 kB
oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js +1.13% 82.76 kB 83.70 kB +1.36% 17.34 kB 17.57 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js +1.13% 50.22 kB 50.78 kB +1.08% 10.17 kB 10.28 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js +1.13% 50.22 kB 50.78 kB +1.08% 10.17 kB 10.28 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js +1.13% 50.43 kB 51.00 kB +1.07% 10.29 kB 10.40 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js +1.13% 50.43 kB 51.00 kB +1.07% 10.29 kB 10.40 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js +1.12% 50.76 kB 51.33 kB +1.03% 10.26 kB 10.37 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js +1.12% 50.98 kB 51.54 kB +0.99% 10.39 kB 10.49 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js +1.09% 52.34 kB 52.91 kB +1.01% 10.68 kB 10.79 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js +1.09% 52.34 kB 52.91 kB +1.01% 10.68 kB 10.79 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js +1.08% 52.77 kB 53.34 kB +1.03% 10.79 kB 10.90 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js +1.08% 52.77 kB 53.34 kB +1.03% 10.79 kB 10.90 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js +1.08% 52.89 kB 53.46 kB +0.93% 10.78 kB 10.88 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js +1.07% 53.32 kB 53.89 kB +0.94% 10.88 kB 10.99 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js +1.06% 53.61 kB 54.18 kB +0.94% 11.03 kB 11.14 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js +1.06% 53.61 kB 54.18 kB +0.94% 11.03 kB 11.14 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js +1.05% 54.15 kB 54.72 kB +0.94% 11.12 kB 11.23 kB
oss-stable-semver/react-client/cjs/react-client-flight.production.js +1.05% 57.18 kB 57.78 kB +1.13% 10.65 kB 10.77 kB
oss-stable/react-client/cjs/react-client-flight.production.js +1.05% 57.20 kB 57.80 kB +1.11% 10.68 kB 10.79 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js +1.05% 54.35 kB 54.92 kB +0.92% 11.15 kB 11.26 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js +1.05% 54.35 kB 54.92 kB +0.92% 11.15 kB 11.26 kB
oss-experimental/react-client/cjs/react-client-flight.production.js +1.04% 57.66 kB 58.26 kB +1.04% 10.75 kB 10.87 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js +1.04% 54.89 kB 55.46 kB +0.92% 11.24 kB 11.34 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js +1.03% 55.14 kB 55.71 kB +0.93% 11.34 kB 11.45 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js +1.03% 55.14 kB 55.71 kB +0.93% 11.34 kB 11.45 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js +1.02% 55.69 kB 56.26 kB +0.90% 11.43 kB 11.54 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js +1.00% 56.68 kB 57.25 kB +0.95% 11.61 kB 11.72 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js +1.00% 56.68 kB 57.25 kB +0.95% 11.61 kB 11.72 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js +0.99% 57.22 kB 57.79 kB +0.88% 11.70 kB 11.80 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js +0.98% 58.17 kB 58.74 kB +0.89% 11.92 kB 12.03 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js +0.98% 58.17 kB 58.74 kB +0.89% 11.92 kB 12.03 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js +0.98% 58.26 kB 58.83 kB +0.89% 11.95 kB 12.05 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js +0.98% 58.26 kB 58.83 kB +0.89% 11.95 kB 12.05 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js +0.97% 58.72 kB 59.29 kB +0.87% 12.01 kB 12.11 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js +0.97% 58.80 kB 59.37 kB +0.85% 12.03 kB 12.14 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.production.js +0.96% 59.19 kB 59.76 kB +0.89% 11.90 kB 12.01 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.production.js +0.96% 59.19 kB 59.76 kB +0.89% 11.90 kB 12.01 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.production.js +0.95% 59.72 kB 60.29 kB +0.88% 12.00 kB 12.10 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js +0.94% 60.37 kB 60.94 kB +0.87% 12.14 kB 12.25 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js +0.94% 60.37 kB 60.94 kB +0.87% 12.14 kB 12.25 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js +0.93% 60.89 kB 61.46 kB +0.86% 12.23 kB 12.34 kB
oss-stable-semver/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.76% 123.44 kB 124.37 kB +0.87% 28.59 kB 28.84 kB
oss-stable/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.76% 123.46 kB 124.40 kB +0.86% 28.61 kB 28.86 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.72% 88.25 kB 88.89 kB +0.71% 16.82 kB 16.94 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.72% 88.30 kB 88.94 kB +0.69% 16.84 kB 16.96 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.72% 88.61 kB 89.25 kB +0.72% 16.77 kB 16.89 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.72% 88.66 kB 89.30 kB +0.71% 16.79 kB 16.91 kB
oss-stable-semver/react-client/cjs/react-client-flight.development.js +0.71% 89.60 kB 90.24 kB +0.79% 16.41 kB 16.54 kB
oss-stable/react-client/cjs/react-client-flight.development.js +0.71% 89.63 kB 90.27 kB +0.79% 16.44 kB 16.57 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.71% 90.44 kB 91.07 kB +0.70% 17.20 kB 17.32 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.71% 90.49 kB 91.12 kB +0.70% 17.23 kB 17.35 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.70% 90.99 kB 91.63 kB +0.68% 17.33 kB 17.45 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.70% 91.04 kB 91.68 kB +0.67% 17.36 kB 17.47 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.70% 91.45 kB 92.08 kB +0.70% 17.39 kB 17.51 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.70% 91.45 kB 92.08 kB +0.70% 17.39 kB 17.51 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.69% 91.96 kB 92.60 kB +0.69% 17.40 kB 17.52 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.69% 91.96 kB 92.60 kB +0.69% 17.40 kB 17.52 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.69% 93.25 kB 93.89 kB +0.68% 17.74 kB 17.86 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.69% 93.25 kB 93.89 kB +0.68% 17.74 kB 17.86 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.68% 94.60 kB 95.24 kB +0.68% 17.86 kB 17.98 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.68% 94.60 kB 95.24 kB +0.68% 17.86 kB 17.98 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.66% 96.34 kB 96.98 kB +0.66% 18.20 kB 18.32 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.66% 96.34 kB 96.98 kB +0.66% 18.20 kB 18.32 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.66% 96.43 kB 97.07 kB +0.66% 18.24 kB 18.36 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.66% 96.43 kB 97.07 kB +0.66% 18.24 kB 18.36 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.development.js +0.66% 97.34 kB 97.98 kB +0.66% 18.13 kB 18.25 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.development.js +0.66% 97.34 kB 97.98 kB +0.66% 18.13 kB 18.25 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.65% 98.67 kB 99.31 kB +0.66% 18.38 kB 18.51 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.65% 98.67 kB 99.31 kB +0.66% 18.38 kB 18.51 kB
oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.53% 145.49 kB 146.26 kB +0.54% 34.12 kB 34.30 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.48% 105.31 kB 105.82 kB +0.46% 20.12 kB 20.22 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.48% 105.66 kB 106.17 kB +0.42% 20.06 kB 20.15 kB
oss-experimental/react-client/cjs/react-client-flight.development.js +0.48% 106.63 kB 107.14 kB +0.49% 19.85 kB 19.94 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.47% 107.49 kB 108.00 kB +0.44% 20.51 kB 20.60 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.47% 108.05 kB 108.56 kB +0.47% 20.64 kB 20.74 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.47% 108.89 kB 109.40 kB +0.43% 20.82 kB 20.91 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.46% 109.41 kB 109.91 kB +0.43% 20.83 kB 20.92 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.46% 110.69 kB 111.20 kB +0.42% 21.19 kB 21.28 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.45% 112.04 kB 112.55 kB +0.42% 21.31 kB 21.40 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.45% 113.79 kB 114.30 kB +0.39% 21.66 kB 21.75 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.45% 113.88 kB 114.39 kB +0.39% 21.70 kB 21.79 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.development.js +0.44% 114.79 kB 115.30 kB +0.41% 21.57 kB 21.66 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.44% 116.12 kB 116.63 kB +0.41% 21.83 kB 21.92 kB

Generated by 🚫 dangerJS against 438f110

unstubbable added a commit to unstubbable/react that referenced this pull request Feb 6, 2025
unstubbable added a commit to unstubbable/react that referenced this pull request Feb 7, 2025
@unstubbable unstubbable changed the title Add failing test for client component props deduping [Flight] Resolve deduped references when chunks are blocked on each other Feb 9, 2025
@unstubbable unstubbable marked this pull request as ready for review February 9, 2025 21:14
@unstubbable unstubbable force-pushed the client-component-props-deduping branch from 414c443 to ecb5a8a Compare February 9, 2025 22:59
@unstubbable unstubbable marked this pull request as draft February 9, 2025 23:02
@unstubbable unstubbable marked this pull request as ready for review February 9, 2025 23:04
reason: null | Array<(mixed) => mixed>,
intermediaryValue?: mixed,
_response: Response,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not "Profiling-only" anymore. I'm not sure this is actually reliable enough. It's more of a hack for profiling which is optional if it works or not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we can keep _children profiling-only. It was not necessary for this fix to remove the two guards around initializingChunk._children. I reverted that.

function createFromJSONCallback(response: Response) {
// $FlowFixMe[missing-this-annot]
return function (key: string, value: JSONValue) {
isParsingRootModel = key === '';
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can't assume that an empty string key is the root since it may also be on nested objects. What's the implication of that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm, we were already using the check here:

// If this is the root object for a model reference, where `handler.value`
// is a stale `null`, the resolved value can be used directly.
if (key === '' && handler.value === null) {
handler.value = mappedValue;
}

But I guess you're right, it could also be an explicit empty key in some object.

unstubbable added a commit to sebmarkbage/react that referenced this pull request Jun 29, 2025
sebmarkbage pushed a commit to sebmarkbage/react that referenced this pull request Jun 29, 2025
sebmarkbage added a commit to sebmarkbage/react that referenced this pull request Jun 29, 2025
Stacked on facebook#33666.

If we ever get a future reference to a cycle and that reference gets
eagerly parsed before the target has loaded then we can end up with a
cycle that never gets resolved. That's because our cycle resolution only
works if the cyclic future reference is created synchronously within the
parsing path of the child.

I haven't been able to construct a normal scenario where this would
break. So this doesn't fail any tests. However, I can construct it with
debug info since those are eagerly evaluated. It's also a prerequisite
if the debug data can come out of order, like if it's on a different
stream.

The fix here is to make all the internal dependencies in the "listener"
list into introspectable objects instead of closures. That way we can
traverse the list of dependencies of a blocked reference to see if it
ends up in a cycle and therefore skip the reference.

It would be nice to address this once and for all to be more resilient
to server changes, but I'm not sure if it's worth this complexity and
the extra CPU cost of tracing the dependencies. Especially if it's just
for debug data.

closes facebook#32316
fixes vercel/next.js#72104

---------

Co-authored-by: Hendrik Liebau <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Specific data/props case causes infinite loading

5 participants