vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.54k stars 8.31k forks source link

Safari src/srcset behavior #6391

Open 719media opened 2 years ago

719media commented 2 years ago

What problem does this feature solve?

Safari on iOS and macOS (other browsers not sure?) render an <img> tag src attribute initially before calculating an <img> tag srcset attribute. This basically means the following 2 javascript examples behave differently:

// example 1, srcset first
const newImage = new Image();
newImage.srcset = 'https://domain.com/image.jpg?w=200 200w';
newImage.src = 'https://domain.com/image.jpg';
document.body.appendChild(newImage);
// example 2, src first
const newImage = new Image();
newImage.src = 'https://domain.com/image.jpg';
newImage.srcset = 'https://domain.com/image.jpg?w=200 200w';
document.body.appendChild(newImage);

Safari will send 1 network request for for the srcset URL for example 1, but 2 network requests for both the src and srcset URLs for example 2. I believe most people would not expect example 2 behavior.

This behavior occurs in Vue templates because of how the template compiles down to javascript. So writing:

<img
  :src="someSrc"
  :srcset="someSrcset"
>

which compiles down to something like (pseudocode) in vue:

...
("img",{src:someSrc, srcset:someSrcset})
...

will experience double network requests in Safari.

I wonder if vue could optimize the template generation to append the srcset attribute first when constructing an image tag? I know there's some funny business around object property order and simply rearranging src and srcset in the object above might have some caveats... so this request, although simple, may have some unappreciated complexities. I at least wanted to start the conversation around what I think is a seemingly trivial and common example for anyone using srcset, and how Safari behaves. Simply put, a common practice could be resulting in basically double (or more!) bandwidth usage, let alone degrading the render time based on image loading priority.

What does the proposed API look like?

If this is something that makes sense to address, there would be no changes to the developer-facing side. I imagine it would just be an edge case hardcode in vue template compiler for inserting srcset before src potentially?

Totally understand if this isn't "vue's" problem to solve, just logging something I found unexpected. I really think this change would immediately impact performance significantly for anyone using srcset.

BrendanEthika commented 2 years ago

Replicated this behavior as well for safari mobile https://github.com/vuejs/core/issues/6391#issue-1324834994

posva commented 2 years ago

Same as https://github.com/vuejs/core/issues/4680#issuecomment-927166733

719media commented 2 years ago

Just leaving a follow up note that the same problem/behavior happens in safari desktop/mobile for a template like:

<img
  :srcset="https://domain.com/image.jpg?w=200 200w, https://domain.com/image.jpg?w=100 100w"
  sizes="50px"
>

What happens is, Safari eagerly loads the srcset before the sizes attribute has been appended by vue, and so it will actually load the 200 width image and then immediately afterward load the 100 width image.

In my opinion, this behavior effectively makes using srcset broken within vue + safari. I understand this isn't really vue's fault, but bring it up again as unexpected behavior.

Also, to be clear, the easiest workaround here is to rearrange the attribute order such that sizes comes first. I'm not sure there's a guarantee here in vue about the order of a template matching the order that attributes will be appended, so this could just be a problem that crops up if some optimization or change happens inside vue-template-compiler.

Workaround:

<img
  sizes="50px"
  :srcset="https://domain.com/image.jpg?w=200 200w, https://domain.com/image.jpg?w=100 100w"
>
ahorovyi commented 11 months ago

I've experienced the same problem when working with Angular 15. I couldn't even imagine that the order of src and srcset attributes does matter.

Thanks for finding out what the reason is.

gdubicki commented 9 months ago

Hi 719media and everyone!

The related Safari bug tracker ticket: https://bugs.webkit.org/show_bug.cgi?id=190031

Perhaps someone here can help get it fixed.

gdubicki commented 9 months ago

That's a longshot, but maybe you could help getting the bug fixed, @jensimmons? Please see the Safari bug tracker link above.