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

Add Flag to Favor Hydration Performance over User Safety #28655

Merged
merged 1 commit into from
Mar 27, 2024

Conversation

sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented Mar 27, 2024

If false, this ignores text comparison checks during hydration at the risk of privacy safety.

Since React 18 we recreate the DOM starting from the nearest Suspense boundary if any of the text content mismatches. This ensures that if we have nodes that otherwise line up correctly such as if they're the same type of Component but in a different order, then we don't accidentally transfer state or attributes to the wrong one.

If we didn't do this e.g. attributes like image src might not line up with the text. E.g. you might show the wrong profile picture with the wrong name. However, the main reason we do this is because it's a security/privacy concern if state from the original node can transfer to the other one. For example if you start typing into a text field to reply to a story but then it turns out that the hydration was in a different order, you might submit that text into a different story than you intended. Similarly, if you've already clicked an item and that gets replayed using Action replaying or is synchronously force hydrated - that click might end up applying to a different item in the list than you intended. E.g. liking the wrong photo.

Unfortunately a common case where this happens is when Google Translate is applied to a page. It'll always cause mismatches and recreate the tree. Most of the time this wouldn't be visible to users because it'd just recreate to the same thing and then translate again. It can affect metrics that trace when this hydration happened though.

Meta can use this flag to decide if they favor this perf metric over the risk to user privacy.

This is similar to the old enableClientRenderFallbackOnTextMismatch flag except this flag doesn't patch up the text when there's a mismatch. Because we don't have the patching anymore. The assumption is that it is safe to ignore the safety concern because we assume it's a match and therefore favoring not patching it will lead to better perf.

@react-sizebot
Copy link

react-sizebot commented Mar 27, 2024

Comparing: 2ec2aae...b41df97

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.min.js = 175.85 kB 175.85 kB = 54.67 kB 54.67 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 172.33 kB 172.33 kB = 53.81 kB 53.81 kB
facebook-www/ReactDOM-prod.classic.js = 589.61 kB 589.44 kB = 103.77 kB 103.72 kB
facebook-www/ReactDOM-prod.modern.js = 573.13 kB 572.97 kB = 100.81 kB 100.75 kB
test_utils/ReactAllWarnings.js Deleted 65.29 kB 0.00 kB Deleted 16.34 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
test_utils/ReactAllWarnings.js Deleted 65.29 kB 0.00 kB Deleted 16.34 kB 0.00 kB

Generated by 🚫 dangerJS against b41df97

@rickhanlonii
Copy link
Member

Small nit, but IMO all flags should be prefixed with enable or disable, in this case enableFavorSafetyOverHydrationPerf. I just makes it easier to understand the direction the flag is going.

If false, this ignores text comparison checks during hydration at the risk of
privacy safety.
@sebmarkbage sebmarkbage merged commit 5910eb3 into facebook:main Mar 27, 2024
38 checks passed
github-actions bot pushed a commit that referenced this pull request Mar 27, 2024
If false, this ignores text comparison checks during hydration at the
risk of privacy safety.

Since React 18 we recreate the DOM starting from the nearest Suspense
boundary if any of the text content mismatches. This ensures that if we
have nodes that otherwise line up correctly such as if they're the same
type of Component but in a different order, then we don't accidentally
transfer state or attributes to the wrong one.

If we didn't do this e.g. attributes like image src might not line up
with the text. E.g. you might show the wrong profile picture with the
wrong name. However, the main reason we do this is because it's a
security/privacy concern if state from the original node can transfer to
the other one. For example if you start typing into a text field to
reply to a story but then it turns out that the hydration was in a
different order, you might submit that text into a different story than
you intended. Similarly, if you've already clicked an item and that gets
replayed using Action replaying or is synchronously force hydrated -
that click might end up applying to a different item in the list than
you intended. E.g. liking the wrong photo.

Unfortunately a common case where this happens is when Google Translate
is applied to a page. It'll always cause mismatches and recreate the
tree. Most of the time this wouldn't be visible to users because it'd
just recreate to the same thing and then translate again. It can affect
metrics that trace when this hydration happened though.

Meta can use this flag to decide if they favor this perf metric over the
risk to user privacy.

This is similar to the old enableClientRenderFallbackOnTextMismatch flag
except this flag doesn't patch up the text when there's a mismatch.
Because we don't have the patching anymore. The assumption is that it is
safe to ignore the safety concern because we assume it's a match and
therefore favoring not patching it will lead to better perf.

DiffTrain build for [5910eb3](5910eb3)
@josephsavona
Copy link
Contributor

It's definitely the right default to favor correctness over performance. But it helps to have a feature flag so that we can compare the performance impact. For example, if we were to see a performance difference it could indicate that metrics might not be capturing the time taken to fix up hydration mismatches, in which case it wouldn't actually be a regression but just an incomplete measurement.

Thanks for adding the flag so we can investigate!

EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
)

If false, this ignores text comparison checks during hydration at the
risk of privacy safety.

Since React 18 we recreate the DOM starting from the nearest Suspense
boundary if any of the text content mismatches. This ensures that if we
have nodes that otherwise line up correctly such as if they're the same
type of Component but in a different order, then we don't accidentally
transfer state or attributes to the wrong one.

If we didn't do this e.g. attributes like image src might not line up
with the text. E.g. you might show the wrong profile picture with the
wrong name. However, the main reason we do this is because it's a
security/privacy concern if state from the original node can transfer to
the other one. For example if you start typing into a text field to
reply to a story but then it turns out that the hydration was in a
different order, you might submit that text into a different story than
you intended. Similarly, if you've already clicked an item and that gets
replayed using Action replaying or is synchronously force hydrated -
that click might end up applying to a different item in the list than
you intended. E.g. liking the wrong photo.

Unfortunately a common case where this happens is when Google Translate
is applied to a page. It'll always cause mismatches and recreate the
tree. Most of the time this wouldn't be visible to users because it'd
just recreate to the same thing and then translate again. It can affect
metrics that trace when this hydration happened though.

Meta can use this flag to decide if they favor this perf metric over the
risk to user privacy.

This is similar to the old enableClientRenderFallbackOnTextMismatch flag
except this flag doesn't patch up the text when there's a mismatch.
Because we don't have the patching anymore. The assumption is that it is
safe to ignore the safety concern because we assume it's a match and
therefore favoring not patching it will lead to better perf.
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.

None yet

5 participants