-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
feat: byte efficiency estimates based on average throughput #1536
Conversation
This is very cool. Instead of living on Would it also make sense to have an average time per domain? That makes certain questions slightly harder to answer (was the connection to a domain in some interval server limited or was it because there were a bunch of connections open to some other domain), but it clears up other things, like recognizing the use of a fast CDN for static assets while ads on the same page are loaded from a much slower server. |
Good point I totally forgot about those :) yes, I'll convert it
I actually started with this, but ended up just going back to all requests for a couple reasons:
Ideally, we'd have some fancy performance experimentation where we could cutoff downloading after X bytes have been received and really tell you what the savings would be |
@@ -26,6 +26,12 @@ | |||
.table_list tr:hover { | |||
background-color: #fafafa; | |||
} | |||
.table_list td * { |
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.
Perf isnt a huge deal on the report, but *
is always nasty. Is there something more specific we can use? Right now it's just br, code blocks as children elements. RIght?
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.
Interesting what makes it so expensive? Reflows become a lot slower?
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.
Yea. Selectors match right -> left. So *
first matches every DOM node, then filters on td
s, etc.
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.
TIL :)
@@ -78,13 +78,18 @@ class Table extends Formatter { | |||
|
|||
const rows = results.map(result => { | |||
const cols = headingKeys.map(key => { | |||
let value = result[key]; | |||
if (typeof value === 'undefined') { |
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.
nit: !(key in value)
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.
doesn't let foo; 'foo' in {foo} === true
?
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.
not sure how many undefined vals we get, but will a bunch of '--' cells be too noisy?
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 found it super helpful for the CLI to differentiate between missing cells and (totally subjectively) more pleasing in the HTML, but open to other ideas
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.
Sounds like we might need some shared helpers for the code and empty cell formatting. Should we do that here or consolidate later?
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.
Not sure what you mean, which code needs to be shared?
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.
https://github.com/GoogleChrome/lighthouse/pull/1536/files#diff-508b9167df0e380cb39ba29ab7deafa2R98 for example. I could use that over in the flexbox audit to fix the whitespace formatting of the code snippet.
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 the fix for that is most likely the ~
added to the report Handlebars template, those lines were some more aggressive edge case hunting, but yes we totally should. I'm in favor of getting this PR for consistency between the byte efficiency audits through and then doing a bit of refactor cleanup of the stuff that's starting to be repeated everywhere, if that makes sense to you too?
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.
Makes sense. I couldn't get ~
to work but I might be doing Handlebad.
case 'lineCol': | ||
return `${result.line}:${result.col}`; | ||
default: | ||
return result[key]; | ||
return String(value); |
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.
doesnt handlebars do this for us?
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.
Sure, but the results also get directly passed to the pretty formatter above which is where startsWith
handler fails with numbers
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.
ack
@@ -132,6 +132,7 @@ class ReportGenerator { | |||
// XSS, define a renderer that only transforms links and code snippets. | |||
// All other markdown ad HTML is ignored. | |||
const renderer = new marked.Renderer(); | |||
renderer.br = () => '<br>'; |
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.
are you using <br>
anywhere?
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 <space><space>\n
in between the url and the content preview for stylesheets
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.
Ah ok. I have a PR coming that introduces <pre>
to the markdown renderer. We could also use that for block level code snippets, removing the need for <br>
and the css you have. WDYT?
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 just not sure how to appropriately target the pre
tag then for margin only when its following other text. Also I can't get the pre
to generate with triple ticks, it still does code
for me after cherry-picking :/
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.
displayValue = `${Math.round(totalWastedBytes / KB_IN_BYTES)}KB potential savings`; | ||
const totalWastedKb = Math.round(totalWastedBytes / KB_IN_BYTES); | ||
const totalWastedMs = Math.round(totalWastedBytes / networkThroughput * 1000); | ||
displayValue = `${totalWastedKb}KB (~${totalWastedMs}ms) potential savings`; |
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.
Because this number is super hand-wavy let's reduce the precision some more. Shall we round to the nearest ten? e.g. 497 => 500 and 432 => 430.
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.
sure sg
I'm not getting off this easy am I? PTAL :) |
static indexStylesheetsById(styles) { | ||
static indexStylesheetsById(styles, networkRecords) { | ||
const indexedNetworkRecords = networkRecords | ||
.filter(record => /css/.test(record.mimeType)) |
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.
rather than mimeType we might want to use record.resourceType()
:
https://github.com/ChromeDevTools/devtools-frontend/blob/b84fc38d5618d27b6a5b50d3948cb31a38488bfa/front_end/common/ResourceType.js#L183
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.
done
const firstRuleStart = preview.indexOf('{'); | ||
const firstRuleEnd = preview.indexOf('}'); | ||
|
||
if (firstRuleStart === -1 || firstRuleEnd === -1 |
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.
Is there anything from https://github.com/ChromeDevTools/devtools-frontend/blob/b84fc38d5618d27b6a5b50d3948cb31a38488bfa/front_end/gonzales/SCSSParser.js we can reuse
not sure, just curious if we can leave some of the parsing/traversal to another project.
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 I tried to use these but because everything is expressed in terms of lines and columns translating to absolute length ended up being even more complicated than this (and didn't really handle leading comments such as those used in every lighthouse file :) ) It also focuses a lot more on rules than rule-sets which made for tricky and generally confusing logic to show the first rule-set with its selector.
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 I would love to just totally kill this at some point in the future by attributing where the inline sheet came from and/or maybe showing a few of the selectors
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.
k sgtm
|
||
let totalBytes = 0; | ||
const timeBoundaries = networkRecords.reduce((boundaries, record) => { | ||
if (/^data:/.test(record.url) || record.failed || !record.finished || |
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.
could use record.parsedURL().scheme
here if you want.
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.
yessss, this is what I've been looking for.
62b7d7e
to
db0f7a7
Compare
addresses #1469 and several tasks of #1517
Switches the approach used previously from adding up the potential ms of each individual resource and instead estimating the time savings based on the average throughput across all requests and the total bytes saved. The previous approach had similar shortcomings to our current links-blocking-first-paint audit where we would report savings longer than the load of the page (because in reality these assets are loaded in parallel, not serially). This should give a more robust and realistic estimate of how many total milliseconds can be shaved off of the load time.
Before:
![image](https://cloud.githubusercontent.com/assets/2301202/22314090/a8921962-e314-11e6-804d-d71b00522c2d.png)
After:
![image](https://cloud.githubusercontent.com/assets/2301202/22313748/0b0bae7a-e313-11e6-86da-0ca835054d6f.png)