-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
core(image-elements): set 5s time budget, add _privateCssSizing #12065
Conversation
@@ -249,6 +249,10 @@ class ImageElements extends Gatherer { | |||
} | |||
|
|||
/** | |||
* Images might be sized via CSS. In order to compute unsized-images failures, we need to collect | |||
* matched CSS rules to see if this is the case. | |||
* Perf warning: Running this for 700 elements takes 1s to 5s. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking: did you mean 50 elements here (the previous limit)?
3s is currently the ~85th percentile on LR staging.
I presume that is 3s for the top 50, so it is surprising that 700 would only take 1-5s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah thx for bringing attention to these numbers.
Just checking: did you mean 50 elements here (the previous limit)?
nah i was just trying to provide some general context. though TBH the count of total imageElements doesn't correlate too well. kohls has 700 and takes 1s on my machine and 5s on LR... however like 500 of them are data uris and 495 of those are reusing network resources.
but the gatherer cost correlates with # of network-resource-associated non-css non-shadowdom images that we do these protocol calls for. (something like ~160 for kohls i think? eh.)
I'll remove this particular sentence and replace it with something more useful.
3s is currently the ~85th percentile on LR staging.
I presume that is 3s for the top 50, so it is surprising that 700 would only take 1-5s.
this 3s 85th percentile figure is accurate for staging LR, which has the top50 filter for fetchElementWithSizeInformation but not for fetchSourceRules.
700 does sound like a lot, but language selectors w/ flag sprites and other lazyload image stuff, the number can get high pretty quickly. shrug. i couldn't tell you what the distribution of ImageElements.length is for LR, but this investigation does make me curious...
for (let element of elements) { | ||
// Pull some of our information directly off the network record. | ||
const networkRecord = indexedNetworkRecords[element.src] || {}; | ||
element.mimeType = networkRecord.mimeType; | ||
|
||
if (!element.isInShadowDOM && !element.isCss) { | ||
// Need source rules to determine if sized via CSS (for unsized-images). | ||
if (!element.isInShadowDOM && !element.isCss && hasBudget) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this bailout is the big change. Won't this lead to false failures? My read of
lighthouse/lighthouse-core/audits/unsized-images.js
Lines 70 to 82 in aaf1365
static isSizedImage(image) { | |
const attrWidth = image.attributeWidth; | |
const attrHeight = image.attributeHeight; | |
const cssWidth = image.cssWidth; | |
const cssHeight = image.cssHeight; | |
const widthIsValidAttribute = UnsizedImages.isValidAttr(attrWidth); | |
const widthIsValidCss = UnsizedImages.isValidCss(cssWidth); | |
const heightIsValidAttribute = UnsizedImages.isValidAttr(attrHeight); | |
const heightIsValidCss = UnsizedImages.isValidCss(cssHeight); | |
const validWidth = widthIsValidAttribute || widthIsValidCss; | |
const validHeight = heightIsValidAttribute || heightIsValidCss; | |
return validWidth && validHeight; | |
} |
is that if fetchSourceRules
isn't run, then cssWidth
and cssHeight
will be undefined
, and so images could be falsely marked as unsized. We should probably fail the other way, not making a claim if we don't have the info?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(also it looks like we don't have any unsized-image
tests with cssWidth: undefined, cssHeight: undefined
. Not a huge deal because we rely on falsy behavior so the tests using the empty string are equivalent, but we should probably add a few at some point since that's an allowed state)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I did miss this change. The previous PR was just focused on saving time for the second request for the source rules, and that's all I was looking at.
So the long tail is not that the 50 largest elements take a long time in fetchElementWithSizeInformation
, but that all the elements take a long time to go thru fetchSourceRules
We should probably fail the other way, not making a claim if we don't have the info?
Should we mark these fields null
to signify we don't know, and undefined
if the element size is not specified (aka when getEffectiveSizingRule
returns undefined)? Or put cssWidth/cssHeight
into an optional property cssSizing?: {width?: string, height?: string}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we discussed in chat.. highlights from that:
I tend to think of
undefined
as equivalent to "not set" andnull
as equivalent to "set and has no value".
👍 👍 👍 👍 👍 👍
idea for imageElement.cssSizing
obj width width/height props.. obj is appropriately null/undefined if skipped etc.
obj could include the naturalWidth bits as well and be fetchedDimensions
or we keep 'em separate.
it would be nice on the next major to do a minor rethink of ImageElements to make it easier on audits using them, since naturalWidth/naturalHeight is in a similar but not quite the same situation as cssWidth/cssHeight after this change
(to add to the null/undefined confusion, don't forget the return value of el.getAttribute('notASetAttribute') :)
edit: filed in #12077
Co-authored-by: Connor Clark <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments etc.
…ndefined. but anyway now its explicitly null. yay
+1. Seems like a good eng sync topic given that we all seem to be on ever so slightly different pages :) Not smoke testing this doesn't feel good, but I have no suggestions for a good way to test it :/ |
Co-authored-by: Connor Clark <[email protected]>
2ec71e0
to
7d80b31
Compare
works for me. renamed to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
types/artifacts.d.ts
Outdated
/** The CSS width property of the image element. */ | ||
/** | ||
* The CSS width property of the image element. | ||
* @deprecated Use `element?._privateCssSizing.width` instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these deprecations be TODO
since we don't actually want anyone using _privateCssSizing
yet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes definitely. done.
types/artifacts.d.ts
Outdated
cssHeight?: string; | ||
/** | ||
* The width/height of the element as defined by matching CSS rules. Set to `undefined` if the data was not collected. | ||
* @private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems not worth it to ts-expect-error
all uses of this to keep it @private
? We could actually mark this @deprecated
which is kind of backwards but would discourage use and strike it out in vscode but still leave it visible for type checking. Maybe there are other options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dig it. done. and added some careful wording around it.
Co-authored-by: Brendan Kenny <[email protected]>
as explored in #11289, we can spend a lot of time in image-elements gathering on some pages.
https://www.kohls.com
is one such repro.this PR adds a time budget the expensive parts of gathering that data.
3s is currently the ~85th percentile on LR staging.
fix #11289
also related: #12054