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

[Fiber][Float] Error when a host fiber changes "flavor" #29693

Merged
merged 1 commit into from
Jun 3, 2024

Conversation

gnoff
Copy link
Collaborator

@gnoff gnoff commented May 31, 2024

Host Components can exist as four semantic types

  1. regular Components (Vanilla obv)
  2. singleton Components
  3. hoistable components
  4. resources

Each of these component types have their own rules related to mounting and reconciliation however they are not direclty modeled as their own unique fiber type. This is partly for code size but also because reconciling the inner type of these components would be in a very hot path in fiber creation and reconciliation and it's just not practical to do this logic check here.

Right now we have three Fiber types used to implement these 4 concepts but we probably need to reconsider the model and think of Host Components as a single fiber type with an inner implementation. Once we do this we can regularize things like transitioning between a resource and a regular component or a singleton and a hoistable instance. The cases where these transitions happen today aren't particularly common but they can be observed and currently the handling of these transitions is incomplete at best and buggy at worst. The most egregious case is the link type. This can be a regular component (stylesheet without precedence) a hoistable component (non stylesheet link tags) or a resource (stylesheet with a precedence) and if you have a single jsx slot that tries to reconcile transitions between these types it just doesn't work well.

This commit adds an error for when a Hoistable goes from Instance to Resource. Currently this is only possible for <link> elements going to and from stylesheets with precedence. Hopefully we'll be able to remove this error and implement as an inner type before we encounter new categories for the Hoistable types

detecting type shifting to and from regular components is harder to do efficiently because we don't want to reevaluate the type on every update for host components which is currently not required and would add overhead to a very hot path

singletons can't really type shift in their one practical implementation (DOM) so they are only a problem in theroy not practice

Copy link

vercel bot commented May 31, 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 May 31, 2024 10:40pm

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels May 31, 2024
@gnoff gnoff force-pushed the error-on-hoistable-change branch from 1ad9eae to 9543a7d Compare May 31, 2024 17:56
@gnoff gnoff requested a review from sebmarkbage May 31, 2024 17:56
@react-sizebot
Copy link

react-sizebot commented May 31, 2024

Comparing: adbec0c...82a61ff

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.66 kB 6.66 kB +0.11% 1.82 kB 1.82 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 496.48 kB 496.28 kB +0.06% 88.87 kB 88.92 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.67 kB 6.67 kB +0.16% 1.82 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 501.30 kB 501.10 kB +0.05% 89.56 kB 89.61 kB
facebook-www/ReactDOM-prod.classic.js = 593.97 kB 593.77 kB +0.03% 104.48 kB 104.52 kB
facebook-www/ReactDOM-prod.modern.js = 570.35 kB 570.16 kB +0.03% 100.88 kB 100.92 kB
test_utils/ReactAllWarnings.js Deleted 63.65 kB 0.00 kB Deleted 15.90 kB 0.00 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-dom/cjs/react-dom-client.development.js +0.25% 1,300.34 kB 1,303.57 kB +0.22% 289.43 kB 290.05 kB
oss-stable/react-dom/cjs/react-dom-client.development.js +0.25% 1,300.37 kB 1,303.60 kB +0.22% 289.45 kB 290.08 kB
oss-experimental/react-dom/cjs/react-dom-client.development.js +0.25% 1,315.34 kB 1,318.57 kB +0.21% 292.72 kB 293.33 kB
oss-stable-semver/react-dom/cjs/react-dom-profiling.development.js +0.24% 1,319.02 kB 1,322.25 kB +0.21% 292.83 kB 293.43 kB
oss-stable/react-dom/cjs/react-dom-profiling.development.js +0.24% 1,319.04 kB 1,322.27 kB +0.21% 292.85 kB 293.46 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js +0.24% 1,333.46 kB 1,336.68 kB +0.20% 297.08 kB 297.68 kB
oss-experimental/react-dom/cjs/react-dom-profiling.development.js +0.24% 1,334.02 kB 1,337.25 kB +0.21% 296.05 kB 296.66 kB
facebook-www/ReactDOM-dev.modern.js +0.23% 1,424.52 kB 1,427.75 kB +0.19% 312.25 kB 312.85 kB
facebook-www/ReactDOMTesting-dev.modern.js +0.22% 1,442.52 kB 1,445.75 kB +0.19% 316.59 kB 317.19 kB
facebook-www/ReactDOM-dev.classic.js +0.22% 1,465.06 kB 1,468.29 kB +0.19% 319.99 kB 320.61 kB
facebook-www/ReactDOMTesting-dev.classic.js +0.22% 1,483.06 kB 1,486.29 kB +0.19% 324.34 kB 324.95 kB
test_utils/ReactAllWarnings.js Deleted 63.65 kB 0.00 kB Deleted 15.90 kB 0.00 kB

Generated by 🚫 dangerJS against 82a61ff

(resource === null && current.memoizedState)
) {
throw new Error(
'Expected HostHoistable to not change between Instance and Resource type. Try adding a key to this component so that when its props change a new instance is mounted.',
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 public error message likely to be hit by an end user yet it includes three Fiber internal terminologies.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah so I would like to make it more public friendly but its a reconciler error and it feels odd to be too descriptive about the DOM here. I could implement the error in the host config but then I need to add it to all the others and it still is only going to be used by DOM presumably until the error goes away.

I was thinking of adding a warning that contextualizes the error better inside getResource since that's already in the host config and then this error can be generic but i'm having trouble with non fiber-internal language in the message that is still not host specific

Copy link
Collaborator

@acdlite acdlite May 31, 2024

Choose a reason for hiding this comment

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

We should still try to express the message in terms of the possible mistakes that might cause it. It can link to a docs page if the explanation is too verbose.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Re: host-specific language, it's annoying but the right thing to do is probably a fiber config method.

if (nextResource === currentResource) {
workInProgress.flags &= ~MaySuspendCommit;
} else {
// This is an update.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What all this refactoring about? Does it do anything?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We no longer support transitioning between types (we error in begin work) so we can simplify the update logic. If we have a resource now then we must have had one before. If we don't have one now we must have not had one before.

this removes a duplicate check of nextResource !== currentResource.

@gnoff gnoff force-pushed the error-on-hoistable-change branch 3 times, most recently from 623d8a6 to 2fea326 Compare May 31, 2024 22:24
Host Components can exist as four semantic types

1. regular Components (Vanilla)
2. singleton Components
2. hoistable components
3. resources

Each of these component types have their own rules related to mounting and reconciliation however they are not direclty modeled as their own unique fiber type. This is partly for code size but also because reconciling the inner type of these components would be in a very hot path in fiber creation and reconciliation and it's just not practical to do this logic check here.

Right now we have three Fiber types used to implement these 4 concepts but we probably need to reconsider the model and think of Host Components as a single fiber type with an inner implementation. Once we do this we can regularize things like transitioning between a resource and a regular component or a singleton and a hoistable instance. The cases where these transitions happen today aren't particularly common but they can be observed and currently the handling of these transitions is incmplete at best and buggy at worst. The most egregious case is the link type. This can be a regular component (stylesheet without precedence) a hositable component (non stylesheet link tags) or a resource (stylesheet with a precedence) and if you have a single jsx slot that tries to reconcile transitions between these types it just doesn't work well.

This commit adds an error for when a Hoistable goes from Instance to Resource. This is the most urgent because it is the easiest to hit but doesn't add much overhead in hot paths

detecting type shifting to and from regular components is harder to do efficiently because we don't want to reevaluate the type on every update for host components which is currently not required and would add overhead to a very hot path

singletons can't really type shift in their one practical implementation (DOM) so they are only a problem in theroy not practice
+ ${describeLinkForResourceErrorDEV(pendingProps)}`;
}
throw new Error(
'Expected <link> not to update to be updated to a stylehsheet with precedence.' +
Copy link
Contributor

@unstubbable unstubbable Jun 3, 2024

Choose a reason for hiding this comment

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

Suggested change
'Expected <link> not to update to be updated to a stylehsheet with precedence.' +
'Expected <link> to not be updated to a stylesheet with precedence.' +

await waitForAll([]);
if (__DEV__) {
expect(errors).toEqual([
`Expected <link> not to update to be updated to a stylehsheet with precedence. Check the \`rel\`, \`href\`, and \`precedence\` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.
Copy link
Contributor

@unstubbable unstubbable Jun 3, 2024

Choose a reason for hiding this comment

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

Suggested change
`Expected <link> not to update to be updated to a stylehsheet with precedence. Check the \`rel\`, \`href\`, and \`precedence\` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.
`Expected <link> to not be updated to a stylesheet with precedence. Check the \`rel\`, \`href\`, and \`precedence\` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.

]);
} else {
expect(errors).toEqual([
'Expected <link> not to update to be updated to a stylehsheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.',
Copy link
Contributor

@unstubbable unstubbable Jun 3, 2024

Choose a reason for hiding this comment

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

Suggested change
'Expected <link> not to update to be updated to a stylehsheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.',
'Expected <link> to not be updated to a stylesheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.',

@@ -512,5 +512,7 @@
"524": "Values cannot be passed to next() of AsyncIterables passed to Client Components.",
"525": "A React Element from an older version of React was rendered. This is not supported. It can happen if:\n- Multiple copies of the \"react\" package is used.\n- A library pre-bundled an old copy of \"react\" or \"react/jsx-runtime\".\n- A compiler tries to \"inline\" JSX instead of using the runtime.",
"526": "Could not reference an opaque temporary reference. This is likely due to misconfiguring the temporaryReferences options on the server.",
"527": "Incompatible React versions: The \"react\" and \"react-dom\" packages must have the exact same version. Instead got:\n - react: %s\n - react-dom: %s\nLearn more: https://react.dev/warnings/version-mismatch"
"527": "Incompatible React versions: The \"react\" and \"react-dom\" packages must have the exact same version. Instead got:\n - react: %s\n - react-dom: %s\nLearn more: https://react.dev/warnings/version-mismatch",
"528": "Expected <link> not to update to be updated to a stylehsheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.%s",
Copy link
Contributor

@unstubbable unstubbable Jun 3, 2024

Choose a reason for hiding this comment

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

Suggested change
"528": "Expected <link> not to update to be updated to a stylehsheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.%s",
"528": "Expected <link> to not be updated to a stylesheet with precedence. Check the `rel`, `href`, and `precedence` props of this component. Alternatively, check whether two different <link> components render in the same slot or share the same key.%s",

@gnoff gnoff merged commit 47d0c30 into facebook:main Jun 3, 2024
40 checks passed
@gnoff
Copy link
Collaborator Author

gnoff commented Jun 3, 2024

resolved typo in #29732

@gnoff gnoff deleted the error-on-hoistable-change branch June 3, 2024 14:51
github-actions bot pushed a commit that referenced this pull request Jun 3, 2024
Host Components can exist as four semantic types

1. regular Components (Vanilla obv)
2. singleton Components
2. hoistable components
3. resources

Each of these component types have their own rules related to mounting
and reconciliation however they are not direclty modeled as their own
unique fiber type. This is partly for code size but also because
reconciling the inner type of these components would be in a very hot
path in fiber creation and reconciliation and it's just not practical to
do this logic check here.

Right now we have three Fiber types used to implement these 4 concepts
but we probably need to reconsider the model and think of Host
Components as a single fiber type with an inner implementation. Once we
do this we can regularize things like transitioning between a resource
and a regular component or a singleton and a hoistable instance. The
cases where these transitions happen today aren't particularly common
but they can be observed and currently the handling of these transitions
is incomplete at best and buggy at worst. The most egregious case is the
link type. This can be a regular component (stylesheet without
precedence) a hoistable component (non stylesheet link tags) or a
resource (stylesheet with a precedence) and if you have a single jsx
slot that tries to reconcile transitions between these types it just
doesn't work well.

This commit adds an error for when a Hoistable goes from Instance to
Resource. Currently this is only possible for `<link>` elements going to
and from stylesheets with precedence. Hopefully we'll be able to remove
this error and implement as an inner type before we encounter new
categories for the Hoistable types

detecting type shifting to and from regular components is harder to do
efficiently because we don't want to reevaluate the type on every update
for host components which is currently not required and would add
overhead to a very hot path

singletons can't really type shift in their one practical implementation
(DOM) so they are only a problem in theroy not practice

DiffTrain build for commit 47d0c30.
github-actions bot pushed a commit that referenced this pull request Jun 3, 2024
Host Components can exist as four semantic types

1. regular Components (Vanilla obv)
2. singleton Components
2. hoistable components
3. resources

Each of these component types have their own rules related to mounting
and reconciliation however they are not direclty modeled as their own
unique fiber type. This is partly for code size but also because
reconciling the inner type of these components would be in a very hot
path in fiber creation and reconciliation and it's just not practical to
do this logic check here.

Right now we have three Fiber types used to implement these 4 concepts
but we probably need to reconsider the model and think of Host
Components as a single fiber type with an inner implementation. Once we
do this we can regularize things like transitioning between a resource
and a regular component or a singleton and a hoistable instance. The
cases where these transitions happen today aren't particularly common
but they can be observed and currently the handling of these transitions
is incomplete at best and buggy at worst. The most egregious case is the
link type. This can be a regular component (stylesheet without
precedence) a hoistable component (non stylesheet link tags) or a
resource (stylesheet with a precedence) and if you have a single jsx
slot that tries to reconcile transitions between these types it just
doesn't work well.

This commit adds an error for when a Hoistable goes from Instance to
Resource. Currently this is only possible for `<link>` elements going to
and from stylesheets with precedence. Hopefully we'll be able to remove
this error and implement as an inner type before we encounter new
categories for the Hoistable types

detecting type shifting to and from regular components is harder to do
efficiently because we don't want to reevaluate the type on every update
for host components which is currently not required and would add
overhead to a very hot path

singletons can't really type shift in their one practical implementation
(DOM) so they are only a problem in theroy not practice

DiffTrain build for [47d0c30](47d0c30)
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.

6 participants