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] Ensure srcset and src are assigned last on img instances #30340

Merged
merged 2 commits into from
Jul 16, 2024

Conversation

gnoff
Copy link
Collaborator

@gnoff gnoff commented Jul 15, 2024

Safari has a behavior (bug) where when you consturct an Image in javascript if you set srcset before properties for sizes the brwoser will download the largest image size because it starts to load before you communicate the sizes information.

https://x.com/OliverJAsh/status/1812408504444989588?t=CVHPqBaUiF5-6DBPGERTDA

There are likely other combinations or property order assignment that can cause problems such as setting crossorigin after assigning src or srcset. Conceptually we should withold the src and srcSet from the Image instance until last so all relevant other properties can be assigned before actually initiating any network activity.

This is an unforunate amount of code for what is realistically a bug in Browsers but it should allow us to avoid weird regressions depending on prop object order.

I didn't change the preload prop order because I don't believe preload links have the same issue (they are not fetched as eagerly I believe).

One nice benefit of this change though is the img case can move higher in the switch which is likely optimal given it's a relatively common tag. Previously it was as low as it was because it was part of the void element set so it couldn't be elevated without elevating less common tags

Copy link

vercel bot commented Jul 15, 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 Jul 16, 2024 3:21pm

Safari has a behavior (bug) where when you consturct an Image in javascript if you set srcset before properties for `sizes` the brwoser will download the largest image size because it starts to load before you communicate the sizes information.

https://x.com/OliverJAsh/status/1812408504444989588?t=CVHPqBaUiF5-6DBPGERTDA

This change updates the dom fiber implementation to ensure that sizes is added before srcset
@gnoff gnoff changed the title [Fiber] Ensure srcset is last on img instances [Fiber] Ensure srcset and src are assigned last on img instances Jul 15, 2024
Copy link
Member

@kassens kassens left a comment

Choose a reason for hiding this comment

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

While you're here, also work around the second mentioned bug of loading=lazy needed before src?

@@ -1031,6 +1031,53 @@ export function setInitialProperties(
// Fast track the most common tag types
break;
}
// img tags previously were implemented as void elements with non delegated events however Safari (and possibly Firefox)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Safari truly is the new IE.

@sophiebits
Copy link
Collaborator

sophiebits commented Jul 16, 2024

Does this fix this bug too?

I guess the img tag needs to be appended to its parent before .src is set.

@sophiebits
Copy link
Collaborator

And does this need to do something with srcset:

((domElement: any): HTMLImageElement).src = (newProps: any).src;

@react-sizebot
Copy link

Comparing: 8b08e99...f34f75a

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.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.22% 498.36 kB 499.44 kB +0.24% 89.37 kB 89.59 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 +0.22% 503.18 kB 504.26 kB +0.25% 90.08 kB 90.30 kB
facebook-www/ReactDOM-prod.classic.js +0.18% 598.11 kB 599.20 kB +0.22% 105.56 kB 105.79 kB
facebook-www/ReactDOM-prod.modern.js +0.19% 572.28 kB 573.37 kB +0.21% 101.46 kB 101.68 kB
test_utils/ReactAllWarnings.js Deleted 64.07 kB 0.00 kB Deleted 15.86 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-rc/react-dom/cjs/react-dom-client.production.js +0.22% 498.26 kB 499.34 kB +0.24% 89.35 kB 89.57 kB
oss-stable-semver/react-dom/cjs/react-dom-client.production.js +0.22% 498.26 kB 499.34 kB +0.24% 89.35 kB 89.57 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.22% 498.36 kB 499.44 kB +0.24% 89.37 kB 89.59 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js +0.22% 503.18 kB 504.26 kB +0.25% 90.08 kB 90.30 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.js +0.21% 519.56 kB 520.64 kB +0.24% 94.08 kB 94.30 kB
oss-stable-rc/react-dom/cjs/react-dom-profiling.profiling.js +0.20% 531.04 kB 532.12 kB +0.23% 94.53 kB 94.75 kB
oss-stable-semver/react-dom/cjs/react-dom-profiling.profiling.js +0.20% 531.04 kB 532.12 kB +0.23% 94.53 kB 94.75 kB
oss-stable/react-dom/cjs/react-dom-profiling.profiling.js +0.20% 531.14 kB 532.23 kB +0.23% 94.55 kB 94.77 kB
oss-experimental/react-dom/cjs/react-dom-profiling.profiling.js +0.20% 535.96 kB 537.04 kB +0.24% 95.24 kB 95.47 kB
test_utils/ReactAllWarnings.js Deleted 64.07 kB 0.00 kB Deleted 15.86 kB 0.00 kB

Generated by 🚫 dangerJS against f34f75a

@gnoff
Copy link
Collaborator Author

gnoff commented Jul 16, 2024

@sophiebits

And does this need to do something with srcset:

funny that's the first contribution I made to React I think :) I suspect yes it probably does need to include srcSet as well. I'll land in another PR

I guess the img tag needs to be appended to its parent before .src is set.

Yeah this is something I thought about when adding this. The composition with a picture parent is probably a problem and needs more consideration. Unfortunately it's not as simple a change so I'm not going to do it now.

I wonder if we should take a stronger stance on <picture> and say that it can only have "simple" children and just do innerHTML or something. That way we can avoid all the property and parent assignment ordering without having to worry about each browsers idiosyncracies.

@gnoff
Copy link
Collaborator Author

gnoff commented Jul 16, 2024

@kassens

While you're here, also work around the second mentioned bug of loading=lazy needed before src?

this should solve that issue too b/c it makes sure src and srcSet go last

@gnoff gnoff merged commit 0117239 into facebook:main Jul 16, 2024
185 checks passed
@gnoff gnoff deleted the ensure-srcset-last branch July 16, 2024 15:25
github-actions bot pushed a commit that referenced this pull request Jul 16, 2024
#30340)

Safari has a behavior (bug) where when you consturct an Image in
javascript if you set srcset before properties for `sizes` the brwoser
will download the largest image size because it starts to load before
you communicate the sizes information.

https://x.com/OliverJAsh/status/1812408504444989588?t=CVHPqBaUiF5-6DBPGERTDA

There are likely other combinations or property order assignment that
can cause problems such as setting crossorigin after assigning src or
srcset. Conceptually we should withold the src and srcSet from the Image
instance until last so all relevant other properties can be assigned
before actually initiating any network activity.

This is an unforunate amount of code for what is realistically a bug in
Browsers but it should allow us to avoid weird regressions depending on
prop object order.

I didn't change the preload prop order because I don't believe preload
links have the same issue (they are not fetched as eagerly I believe).

One nice benefit of this change though is the img case can move higher
in the switch which is likely optimal given it's a relatively common
tag. Previously it was as low as it was because it was part of the void
element set so it couldn't be elevated without elevating less common
tags

---------

Co-authored-by: Jan Kassens <[email protected]>

DiffTrain build for [0117239](0117239)
@kassens
Copy link
Member

kassens commented Jul 16, 2024

@kassens

While you're here, also work around the second mentioned bug of loading=lazy needed before src?

this should solve that issue too b/c it makes sure src and srcSet go last

D'oh, of course.

felixshiftellecon added a commit to felixshiftellecon/react that referenced this pull request Jul 24, 2024
facebook#30340)

Safari has a behavior (bug) where when you consturct an Image in
javascript if you set srcset before properties for `sizes` the brwoser
will download the largest image size because it starts to load before
you communicate the sizes information.


https://x.com/OliverJAsh/status/1812408504444989588?t=CVHPqBaUiF5-6DBPGERTDA

There are likely other combinations or property order assignment that
can cause problems such as setting crossorigin after assigning src or
srcset. Conceptually we should withold the src and srcSet from the Image
instance until last so all relevant other properties can be assigned
before actually initiating any network activity.

This is an unforunate amount of code for what is realistically a bug in
Browsers but it should allow us to avoid weird regressions depending on
prop object order.

I didn't change the preload prop order because I don't believe preload
links have the same issue (they are not fetched as eagerly I believe).

One nice benefit of this change though is the img case can move higher
in the switch which is likely optimal given it's a relatively common
tag. Previously it was as low as it was because it was part of the void
element set so it couldn't be elevated without elevating less common
tags

---------

Co-authored-by: Jan Kassens <[email protected]>
felixshiftellecon added a commit to felixshiftellecon/react that referenced this pull request Jul 24, 2024
facebook#30340)

Safari has a behavior (bug) where when you consturct an Image in
javascript if you set srcset before properties for `sizes` the brwoser
will download the largest image size because it starts to load before
you communicate the sizes information.


https://x.com/OliverJAsh/status/1812408504444989588?t=CVHPqBaUiF5-6DBPGERTDA

There are likely other combinations or property order assignment that
can cause problems such as setting crossorigin after assigning src or
srcset. Conceptually we should withold the src and srcSet from the Image
instance until last so all relevant other properties can be assigned
before actually initiating any network activity.

This is an unforunate amount of code for what is realistically a bug in
Browsers but it should allow us to avoid weird regressions depending on
prop object order.

I didn't change the preload prop order because I don't believe preload
links have the same issue (they are not fetched as eagerly I believe).

One nice benefit of this change though is the img case can move higher
in the switch which is likely optimal given it's a relatively common
tag. Previously it was as low as it was because it was part of the void
element set so it couldn't be elevated without elevating less common
tags

---------

Co-authored-by: Jan Kassens <[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.

6 participants