WordPress / performance

Performance plugin from the WordPress Performance Group, which is a collection of standalone performance modules.
https://wordpress.org/plugins/performance-lab/
GNU General Public License v2.0
339 stars 91 forks source link

Preconnect to domains of resources for LCP elements known to be in embeds when in initial viewport #1058

Closed westonruter closed 1 week ago

westonruter commented 4 months ago

Feature Description

When an embed is the LCP element, we can optimize its loading (beyond omitting loading=lazy cf. https://github.com/WordPress/performance/issues/1054) by adding preconnect links to domains for resources which are known to be present in the iframe, especially for the LCP element in the iframe.

YouTube Embeds

A YouTube embed loads resources from the following domains (see on trace.cafe):

Note that the actual LCP element and the perceived LCP element on YouTube are not the same due to limitations in the definition of LCP heuristics (h/t @tunetheweb):

As well as only considering some elements, LCP measurements use heuristics to exclude certain elements that users are likely to see as "non-contentful". For Chromium-based browsers, these include:

  • Elements with an opacity of 0, making them invisible to the user.
  • Elements that cover the full viewport, that are likely to be background elements.
  • Placeholder images or other images with a low entropy, that likely don't reflect the true content of the page.

Browsers are likely to continue to improve these heuristics to ensure we match user expectations of what the largest contentful element is.

Bullet point two is problematic for YouTube embeds. Chrome is detecting this element to be LCP:

<a class="ytp-title-link yt-uix-sessionlink" target="_blank" data-sessionlink="feature=player-title" tabindex="0" href="https://www.youtube.com/watch?v=3KtWfp0UopM">
    Google — 25 Years in Search: The Most Searched
</a>

But the percieved LCP element is the poster image which is background:

<div class="ytp-cued-thumbnail-overlay-image" style="background-image: url(&quot;https://i.ytimg.com/vi_webp/3KtWfp0UopM/maxresdefault.webp&quot;);"></div>

However, since it is a background image which covers the full viewport, it is excluded from being considered the LCP element.

youtube-embed

So this introduces a bit of a conundrum. For the sake of YouTube embeds, do we add a preconnect for fonts.gstatic.com so the actual LCP element renders sooner, or do we preconnect i.ytimg.com so that the perceived LCP element renders sooner? I guess for now the answer is both, at least until browsers improve on these heuristics to match user expectations.

Other Embeds

A similar analysis should be done for other embeds.

Implementation

This issue is tagged for both Embed Optimizer and the Optimization Detective plugins. The latter should expose an API so that the former can discover an initial viewport embed and then be able to add the preconnects.

See also https://github.com/ampproject/amp-toolbox-php/issues/10 (from 5+ years ago!) which proposed doing this similarly for AMP components for embeds. Note that AMP components are designed to be able to preconnect to relevant domains when initialized. For example, the amp-youtube component preconnects to https://s.ytimg.com and https://i.ytimg.com (the former seems obsolete which I've proposed removing in https://github.com/ampproject/amphtml/pull/39903). Nevertheless, when the embed is in the initial viewport, preconnecting when the component is rendered is almost too late, and the preconnect links should have rather been added to the HTML so they don't depend on JS to execute. This is what the amp-toolbox-php issue was for, and we can do the same for plain HTML.

adamsilverstein commented 4 months ago

Very interesting!

I guess for now the answer is both, at least until browsers improve on these heuristics to match user expectations.

Yeah, maybe always preconnect everything thats referenced above the fold?

For YouTube specifically I'd love to experiment with swapping in https://github.com/paulirish/lite-youtube-embed instead of the embed since it "Renders faster than a sneeze". That feels separate enough though that it might warrant a separate plugin. YouTube is important though, my research shows it is the most popular embed used on WordPress sites.

westonruter commented 4 months ago

For YouTube specifically I'd love to experiment with swapping in https://github.com/paulirish/lite-youtube-embed instead of the embed since it "Renders faster than a sneeze". That feels separate enough though that it might warrant a separate plugin. YouTube is important though, my research shows it is the most popular embed used on WordPress sites.

Unfortunately I think the UX hit for this outweighs the performance gains. On mobile it requires a double tap to play (a rage tap?): https://github.com/paulirish/lite-youtube-embed/issues/6

westonruter commented 4 months ago

Note: We cannot go a step beyond preconnecting to the domains and try to preload specific assets inside the iframe due to cross-origin isolation. This does not seem to apply to lower down in the network stack. Example of performance improvement: https://www.webpagetest.org/video/compare.php?tests=240319_AiDcZ0_DJS,240319_BiDc7S_DFE

westonruter commented 2 months ago

Another comparison: https://www.webpagetest.org/video/compare.php?tests=240423_AiDcQ5_BXJ%2C240423_AiDcW1_BXT&thumbSize=200&ival=100&end=visual

LCP reduced from 546ms to 526ms, which is a 3.66% improvement.

Configuration:

image