Skip to content
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

[Fax] Support nesting in existing RSC renderers #30736

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

eps1lon
Copy link
Collaborator

@eps1lon eps1lon commented Aug 17, 2024

Summary

This chains the async dispatchers similarly to what we did #28488.

The cache between nested renderers is shared prioritising the one that was first registered during module evaluation (an earlier version cached in both but I couldn't think of a case where we need this behavior).

Parent stacks and Owner stacks currently don't work in onError of react-markup. I'd need to think about this more but it's dev-only.

Test plan

  • Added new test for nesting RSC renderers (ReactNoopFlight + ReactMarkup) which produced the "Currently React only supports one RSC renderer at a time." error initially.

Copy link

vercel bot commented Aug 17, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Sep 4, 2024 2:34pm

@react-sizebot
Copy link

react-sizebot commented Aug 17, 2024

Comparing: d1afcb4...da39328

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 +0.05% 1.82 kB 1.82 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 501.40 kB 501.18 kB = 89.99 kB 89.94 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.05% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 508.52 kB 508.30 kB = 91.16 kB 91.11 kB
facebook-www/ReactDOM-prod.classic.js = 596.16 kB 595.93 kB = 105.69 kB 105.63 kB
facebook-www/ReactDOM-prod.modern.js = 572.44 kB 572.22 kB = 101.88 kB 101.82 kB
oss-experimental/react/cjs/react.react-server.production.js +2.19% 18.66 kB 19.07 kB +1.73% 4.97 kB 5.05 kB
oss-experimental/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable-rc/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable-semver/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react/cjs/react.react-server.production.js +2.19% 18.66 kB 19.07 kB +1.73% 4.97 kB 5.05 kB
oss-stable-rc/react/cjs/react.react-server.production.js +1.47% 13.28 kB 13.47 kB +1.18% 3.66 kB 3.70 kB
oss-stable-semver/react/cjs/react.react-server.production.js +1.47% 13.28 kB 13.47 kB +1.18% 3.66 kB 3.70 kB
oss-stable/react/cjs/react.react-server.production.js +1.47% 13.30 kB 13.49 kB +1.22% 3.68 kB 3.72 kB
oss-experimental/react/cjs/react.react-server.development.js +1.24% 35.85 kB 36.30 kB +1.06% 8.48 kB 8.57 kB
oss-experimental/react/cjs/react.production.js +1.19% 17.97 kB 18.18 kB +1.35% 4.67 kB 4.73 kB
facebook-react-native/react/cjs/React-prod.js +1.14% 18.69 kB 18.91 kB +1.30% 4.86 kB 4.92 kB
facebook-react-native/react/cjs/React-profiling.js +1.12% 19.13 kB 19.34 kB +1.28% 4.94 kB 5.00 kB
facebook-www/React-prod.modern.js +0.96% 22.32 kB 22.54 kB +1.03% 5.82 kB 5.88 kB
facebook-www/React-prod.classic.js +0.96% 22.33 kB 22.54 kB +1.05% 5.82 kB 5.88 kB
facebook-www/React-profiling.modern.js +0.94% 22.76 kB 22.97 kB +1.02% 5.90 kB 5.96 kB
facebook-www/React-profiling.classic.js +0.94% 22.76 kB 22.97 kB +1.02% 5.90 kB 5.96 kB
oss-stable-rc/react/cjs/react.react-server.development.js +0.55% 40.17 kB 40.39 kB +0.47% 9.20 kB 9.24 kB
oss-stable-semver/react/cjs/react.react-server.development.js +0.55% 40.17 kB 40.39 kB +0.47% 9.20 kB 9.24 kB
oss-stable/react/cjs/react.react-server.development.js +0.55% 40.19 kB 40.41 kB +0.49% 9.22 kB 9.26 kB
oss-experimental/react/cjs/react.development.js +0.49% 45.32 kB 45.54 kB +0.60% 10.34 kB 10.40 kB
facebook-react-native/react/cjs/React-dev.js +0.35% 62.58 kB 62.80 kB +0.43% 13.76 kB 13.82 kB
facebook-www/React-dev.modern.js +0.30% 73.36 kB 73.58 kB +0.37% 16.09 kB 16.15 kB
facebook-www/React-dev.classic.js +0.30% 74.22 kB 74.44 kB +0.37% 16.22 kB 16.28 kB
oss-experimental/react-server/cjs/react-server-flight.production.js = 64.64 kB 64.49 kB = 12.54 kB 12.45 kB
oss-stable-rc/react-server/cjs/react-server-flight.production.js = 58.41 kB 58.25 kB = 11.59 kB 11.54 kB
oss-stable-semver/react-server/cjs/react-server-flight.production.js = 58.41 kB 58.25 kB = 11.59 kB 11.54 kB
oss-stable/react-server/cjs/react-server-flight.production.js = 58.41 kB 58.25 kB = 11.59 kB 11.54 kB
oss-experimental/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable-rc/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable-semver/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB
oss-stable/react-suspense-test-utils/cjs/react-suspense-test-utils.js = 1.22 kB 1.06 kB = 0.60 kB 0.54 kB

Generated by 🚫 dangerJS against 35507c5

@sebmarkbage

This comment was marked as resolved.

sebmarkbage

This comment was marked as resolved.

@eps1lon
Copy link
Collaborator Author

eps1lon commented Aug 27, 2024

We should chain the owner too. If there is no owner on the inner one, it should defer to the outer (previous) dispatcher to see if it has one.

From what I can tell they're not just broken at the dispatcher level but also with regards to getCurrentStack. I can take a look at these in a follow-up since they're dev-only and experimentation is otherwise blocked.

@sebmarkbage
Copy link
Collaborator

I can take a look at these in a follow-up since they're dev-only and experimentation is otherwise blocked.

Just keep in mind that this blocks the RSC DevTools stuff and enableOwnerStacks if they end up getting installed in the wrong order.

@@ -452,6 +452,7 @@ export type Dispatcher = {
};

export type AsyncDispatcher = {
getActiveCache: () => Map<Function, mixed> | null,
getCacheForType: <T>(resourceType: () => T) => T,
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's no need for both of these. If we're saying that the implementation detail is a Map<Function> and that is exposed through getActiveCache(), there's not that much getCacheForType can configure and it's unnecessary indirection. getCacheForType can just be a utility function that calls getActiveCache. (Or we can get rid of getCacheForType completely and just have the callers call getActiveCache.) No need to be on the dispatcher anymore.

Copy link
Collaborator

Choose a reason for hiding this comment

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

To preempt "I'll do it in a follow up". Since we know that these dispatchers are messed with by people and we break them we don't want to change this too many times. Even the async cache ones (cc Janka).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Like this f140f36 (#30736)?

Whatever resolves the cache conflict needs to know the previous dispatcher so it made sense to me to just do the resolution inside getActiveCache. I don't know how else to do it if we want getActiveCache to return the actual Map (or null) and resolve conflicts in a utility since that utility needs to know the current and previous dispatcher.

@eps1lon
Copy link
Collaborator Author

eps1lon commented Aug 27, 2024

Just keep in mind that this blocks the RSC DevTools stuff and enableOwnerStacks if they end up getting installed in the wrong order.

Yeah, I'll get it right in this one.


// If both caches are active, reads will prefer the outer cache
// Writes will go into both caches.
const chainedCache: AsyncCache = {
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 a hot path so we shouldn't allocate in it. Instead we should be able to structure it so that we don't need to.

For example if this is the logic we want, then a better approach might be to just have to methods on the dispatcher. One for get and one for set.

However, I wonder if it's not better to just delegate to one cache over another.

It's not also not good that we don't preserve hidden classes here. It should either always be a WeakMap or never a WeakMap. For example if you load a graph first and then do a bunch of renders and then later load react-markup you'd get a bunch of hidden class breakages causing recompilation but also it'd not assume that it might be either WeakMap or this other thing so all lookups would be megamorphic instead of just checking the one.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What if when we start a new request, we check if we're already inside someone else's render (the dispatcher returns a cache) and if so we just use their cache?

It seems reasonable that an inner render shares the cache of an outer render.

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 had the same concerns but couldn't see a way to make it work when chaining at module evaluation time. Deferring to the existing cache if it exists seems doable (ignoring the ownerstack for now which I need to reconcile still): 2ecf3ec (#30736)

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.

4 participants