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

Move networkRecords to a computed artifact #2062

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7b034ef
WIP kill recordNetwork option
paulirish Apr 29, 2017
bd58729
config double passname validation
paulirish Apr 29, 2017
a206d3f
record network events via networkRecorder dispatcher
paulirish Apr 15, 2017
d26b466
networkRecords computed artifact. (and some assertions that the data …
paulirish Apr 15, 2017
bb36757
basic tests.
paulirish Apr 15, 2017
2ab1285
tests for networkrecords. in good shape.
paulirish Apr 15, 2017
7d6e5c4
remove runtime assertions, as we have found networkRecords to be equal
paulirish Apr 25, 2017
0e66f17
fix perflog importing.
paulirish Apr 25, 2017
06410ab
perflog. must be an object.
paulirish Apr 25, 2017
f853e50
breaking change. performanceLog => devtoolsLogs
paulirish Apr 25, 2017
e7d39a1
move devtoolsLog assignment outside of if(recordtrace) conditional
paulirish Apr 26, 2017
fa43ff9
feedback.
paulirish Apr 26, 2017
a85c4ce
reduce -> forEach
paulirish Apr 26, 2017
9506235
remove extra promise.resolve()
paulirish Apr 26, 2017
60e6223
update *runner tests with removed netRecords.
paulirish Apr 29, 2017
fac3c3d
feedback
paulirish Apr 29, 2017
aaabf3f
rebase cleanup
paulirish Apr 29, 2017
8712532
Merge branch 'master' into netrecordsComputed
brendankenny May 2, 2017
9802ad0
fixup types
brendankenny May 2, 2017
633c84f
Merge branch 'master' into netrecordsComputed
brendankenny May 3, 2017
fc03fc1
always construct networkRecords from devtoolsLog (#2133)
brendankenny May 5, 2017
fc2b9fd
Merge branch 'master' into netrecordsComputed
brendankenny May 5, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ class UnusedBytes extends Audit {
* @return {!Promise<!AuditResult>}
*/
static audit(artifacts) {
const networkRecords = artifacts.networkRecords[Audit.DEFAULT_PASS];
return artifacts.requestNetworkThroughput(networkRecords).then(networkThroughput => {
return Promise.resolve(this.audit_(artifacts, networkRecords)).then(result => {
return this.createAuditResult(result, networkThroughput);
});
const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords => {
return artifacts.requestNetworkThroughput(networkRecords).then(networkThroughput =>
Copy link
Member

Choose a reason for hiding this comment

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

since computed artifacts can call each other now, do you want to make requestNetworkThroughput take devtoolsLogs directly now and have it create the networkRecords internally?

Copy link
Member Author

Choose a reason for hiding this comment

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

i do, yes! totally makes sense. in fact, i mentioned this at the end of the issue description :) ..

i'd do it in this PR but it'd add a lot more to the diff for no immediate benefit. I am suggesting doing that cleanup in a followup.

Copy link
Member

Choose a reason for hiding this comment

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

i do, yes! totally makes sense. in fact, i mentioned this at the end of the issue description :) ..

got it, didn't realize that's what that was referring to

Copy link
Member

Choose a reason for hiding this comment

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

but it'd add a lot more to the diff

although, would it? It would remove a lot of the lines just due to nesting added to this PR. Is the hard part network-throughput-test.js?

Promise.resolve(this.audit_(artifacts, networkRecords)).then(result =>
this.createAuditResult(result, networkThroughput)
)
);
});
}

Expand Down
2 changes: 1 addition & 1 deletion lighthouse-core/audits/byte-efficiency/offscreen-images.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class OffscreenImages extends ByteEfficiencyAudit {
informative: true,
helpText: 'Images that are not above the fold should be lazily loaded after the page is ' +
'interactive. Consider using the [IntersectionObserver](https://developers.google.com/web/updates/2016/04/intersectionobserver) API.',
requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'traces', 'networkRecords']
requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'traces', 'devtoolsLogs']
Copy link
Member

Choose a reason for hiding this comment

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

this (and the old networkRecords) doesn't appear to be used?

Copy link
Collaborator

Choose a reason for hiding this comment

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

used by the shared audit they extend

Copy link
Member

Choose a reason for hiding this comment

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

oh, I see. const Audit = require('./byte-efficiency-audit'); makes that difficult to spot. We should probably rename at some point :)

};
}

Expand Down
93 changes: 47 additions & 46 deletions lighthouse-core/audits/byte-efficiency/total-byte-weight.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class TotalByteWeight extends ByteEfficiencyAudit {
'and is [highly correlated](http://httparchive.org/interesting.php#onLoad) with long load times. ' +
'Try to find ways to reduce the size of required files.',
scoringMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
requiredArtifacts: ['networkRecords']
requiredArtifacts: ['devtoolsLogs']
};
}

Expand All @@ -54,59 +54,60 @@ class TotalByteWeight extends ByteEfficiencyAudit {
* @return {!Promise<!AuditResult>}
*/
static audit(artifacts) {
const networkRecords = artifacts.networkRecords[ByteEfficiencyAudit.DEFAULT_PASS];
return artifacts.requestNetworkThroughput(networkRecords).then(networkThroughput => {
let totalBytes = 0;
const results = networkRecords.reduce((prev, record) => {
// exclude data URIs since their size is reflected in other resources
if (record.scheme === 'data') {
return prev;
}
const devtoolsLogs = artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords => {
return artifacts.requestNetworkThroughput(networkRecords).then(networkThroughput => {
let totalBytes = 0;
let results = [];
networkRecords.forEach(record => {
// exclude data URIs since their size is reflected in other resources
if (record.scheme === 'data') return;

const result = {
url: URL.getDisplayName(record.url),
totalBytes: record.transferSize,
totalKb: this.bytesToKbString(record.transferSize),
totalMs: this.bytesToMsString(record.transferSize, networkThroughput),
};
const result = {
url: URL.getDisplayName(record.url),
totalBytes: record.transferSize,
totalKb: this.bytesToKbString(record.transferSize),
totalMs: this.bytesToMsString(record.transferSize, networkThroughput),
};

totalBytes += result.totalBytes;
prev.push(result);
return prev;
}, []).sort((itemA, itemB) => itemB.totalBytes - itemA.totalBytes).slice(0, 10);
totalBytes += result.totalBytes;
results.push(result);
});
results = results.sort((itemA, itemB) => itemB.totalBytes - itemA.totalBytes).slice(0, 10);


// Use the CDF of a log-normal distribution for scoring.
// <= 1600KB: score≈100
// 4000KB: score=50
// >= 9000KB: score≈0
const distribution = TracingProcessor.getLogNormalDistribution(
// Use the CDF of a log-normal distribution for scoring.
// <= 1600KB: score≈100
// 4000KB: score=50
// >= 9000KB: score≈0
const distribution = TracingProcessor.getLogNormalDistribution(
SCORING_MEDIAN, SCORING_POINT_OF_DIMINISHING_RETURNS);
const score = 100 * distribution.computeComplementaryPercentile(totalBytes);
const score = 100 * distribution.computeComplementaryPercentile(totalBytes);

const headings = [
{key: 'url', itemType: 'url', text: 'URL'},
{key: 'totalKb', itemType: 'text', text: 'Total Size'},
{key: 'totalMs', itemType: 'text', text: 'Transfer Time'},
];
const headings = [
{key: 'url', itemType: 'url', text: 'URL'},
{key: 'totalKb', itemType: 'text', text: 'Total Size'},
{key: 'totalMs', itemType: 'text', text: 'Transfer Time'},
];

const v1TableHeadings = ByteEfficiencyAudit.makeV1TableHeadings(headings);
const v2TableDetails = ByteEfficiencyAudit.makeV2TableDetails(headings, results);
const v1TableHeadings = ByteEfficiencyAudit.makeV1TableHeadings(headings);
const v2TableDetails = ByteEfficiencyAudit.makeV2TableDetails(headings, results);

return {
rawValue: totalBytes,
optimalValue: this.meta.optimalValue,
displayValue: `Total size was ${ByteEfficiencyAudit.bytesToKbString(totalBytes)}`,
score: Math.round(Math.max(0, Math.min(score, 100))),
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.TABLE,
value: {
results,
tableHeadings: v1TableHeadings
}
},
details: v2TableDetails
};
return {
rawValue: totalBytes,
optimalValue: this.meta.optimalValue,
displayValue: `Total size was ${ByteEfficiencyAudit.bytesToKbString(totalBytes)}`,
score: Math.round(Math.max(0, Math.min(score, 100))),
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.TABLE,
value: {
results,
tableHeadings: v1TableHeadings
}
},
details: v2TableDetails
};
});
});
}
}
Expand Down
41 changes: 21 additions & 20 deletions lighthouse-core/audits/byte-efficiency/unused-css-rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
helpText: 'Remove unused rules from stylesheets to reduce unnecessary ' +
'bytes consumed by network activity. ' +
'[Learn more](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery)',
requiredArtifacts: ['CSSUsage', 'Styles', 'URL', 'networkRecords']
requiredArtifacts: ['CSSUsage', 'Styles', 'URL', 'devtoolsLogs']
};
}

Expand Down Expand Up @@ -170,26 +170,27 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
const styles = artifacts.Styles;
const usage = artifacts.CSSUsage;
const pageUrl = artifacts.URL.finalUrl;
const networkRecords = artifacts.networkRecords[ByteEfficiencyAudit.DEFAULT_PASS];

const indexedSheets = UnusedCSSRules.indexStylesheetsById(styles, networkRecords);
UnusedCSSRules.countUnusedRules(usage, indexedSheets);
const results = Object.keys(indexedSheets).map(sheetId => {
return UnusedCSSRules.mapSheetToResult(indexedSheets[sheetId], pageUrl);
}).filter(sheet => sheet && sheet.wastedBytes > 1024);


const headings = [
{key: 'url', itemType: 'url', text: 'URL'},
{key: 'numUnused', itemType: 'url', text: 'Unused Rules'},
{key: 'totalKb', itemType: 'text', text: 'Original'},
{key: 'potentialSavings', itemType: 'text', text: 'Potential Savings'},
];

return {
results,
headings
};
const devtoolsLogs = artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords => {
const indexedSheets = UnusedCSSRules.indexStylesheetsById(styles, networkRecords);
UnusedCSSRules.countUnusedRules(usage, indexedSheets);
const results = Object.keys(indexedSheets).map(sheetId => {
return UnusedCSSRules.mapSheetToResult(indexedSheets[sheetId], pageUrl);
}).filter(sheet => sheet && sheet.wastedBytes > 1024);

const headings = [
{key: 'url', itemType: 'url', text: 'URL'},
{key: 'numUnused', itemType: 'url', text: 'Unused Rules'},
{key: 'totalKb', itemType: 'text', text: 'Original'},
{key: 'potentialSavings', itemType: 'text', text: 'Potential Savings'},
];

return {
results,
headings
};
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class UsesOptimizedImages extends ByteEfficiencyAudit {
'The following images could have smaller file sizes when compressed with ' +
'[WebP](https://developers.google.com/speed/webp/) or JPEG at 80 quality. ' +
'[Learn more about image optimization](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/image-optimization).',
requiredArtifacts: ['OptimizedImages', 'networkRecords']
requiredArtifacts: ['OptimizedImages', 'devtoolsLogs']
Copy link
Member

Choose a reason for hiding this comment

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

also unused?

Copy link
Collaborator

Choose a reason for hiding this comment

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

used by the shared audit they extend

};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ResponsesAreCompressed extends ByteEfficiencyAudit {
helpText: 'Text-based responses should be served with compression (gzip, deflate or brotli)' +
' to minimize total network bytes.' +
' [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer).',
requiredArtifacts: ['ResponseCompression', 'networkRecords']
requiredArtifacts: ['ResponseCompression', 'devtoolsLogs']
Copy link
Member

Choose a reason for hiding this comment

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

unused?

Copy link
Collaborator

Choose a reason for hiding this comment

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

used by the shared audit they extend

};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
'Image sizes served should be based on the device display size to save network bytes. ' +
'Learn more about [responsive images](https://developers.google.com/web/fundamentals/design-and-ui/media/images) ' +
'and [client hints](https://developers.google.com/web/updates/2015/09/automating-resource-selection-with-client-hints).',
requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'networkRecords']
requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'devtoolsLogs']
Copy link
Member

Choose a reason for hiding this comment

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

unused?

Copy link
Collaborator

Choose a reason for hiding this comment

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

used by the shared audit they extend

};
}

Expand Down
68 changes: 35 additions & 33 deletions lighthouse-core/audits/critical-request-chains.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CriticalRequestChains extends Audit {
'the length of chains, reducing the download size of resources, or ' +
'deferring the download of unnecessary resources. ' +
'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).',
requiredArtifacts: ['networkRecords']
requiredArtifacts: ['devtoolsLogs']
};
}

Expand Down Expand Up @@ -98,43 +98,45 @@ class CriticalRequestChains extends Audit {
* @return {!AuditResult} The score from the audit, ranging from 0-100.
*/
static audit(artifacts) {
const networkRecords = artifacts.networkRecords[Audit.DEFAULT_PASS];
return artifacts.requestCriticalRequestChains(networkRecords).then(chains => {
let chainCount = 0;
function walk(node, depth) {
const children = Object.keys(node);
const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords => {
return artifacts.requestCriticalRequestChains(networkRecords).then(chains => {
let chainCount = 0;
function walk(node, depth) {
const children = Object.keys(node);

// Since a leaf node indicates the end of a chain, we can inspect the number
// of child nodes, and, if the count is zero, increment the count.
if (children.length === 0) {
chainCount++;
}
// Since a leaf node indicates the end of a chain, we can inspect the number
// of child nodes, and, if the count is zero, increment the count.
if (children.length === 0) {
chainCount++;
}

children.forEach(id => {
const child = node[id];
walk(child.children, depth + 1);
}, '');
}
children.forEach(id => {
const child = node[id];
walk(child.children, depth + 1);
}, '');
}

// Account for initial navigation
const initialNavKey = Object.keys(chains)[0];
const initialNavChildren = initialNavKey && chains[initialNavKey].children;
if (initialNavChildren && Object.keys(initialNavChildren).length > 0) {
walk(initialNavChildren, 0);
}
// Account for initial navigation
const initialNavKey = Object.keys(chains)[0];
const initialNavChildren = initialNavKey && chains[initialNavKey].children;
if (initialNavChildren && Object.keys(initialNavChildren).length > 0) {
walk(initialNavChildren, 0);
}

return {
rawValue: chainCount <= this.meta.optimalValue,
displayValue: chainCount,
optimalValue: this.meta.optimalValue,
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.CRITICAL_REQUEST_CHAINS,
value: {
chains,
longestChain: CriticalRequestChains._getLongestChain(chains)
return {
rawValue: chainCount <= this.meta.optimalValue,
displayValue: chainCount,
optimalValue: this.meta.optimalValue,
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.CRITICAL_REQUEST_CHAINS,
value: {
chains,
longestChain: CriticalRequestChains._getLongestChain(chains)
}
}
}
};
};
});
});
}
}
Expand Down
64 changes: 33 additions & 31 deletions lighthouse-core/audits/dobetterweb/uses-http2.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class UsesHTTP2Audit extends Audit {
description: 'Uses HTTP/2 for its own resources',
helpText: 'HTTP/2 offers many benefits over HTTP/1.1, including binary headers, ' +
'multiplexing, and server push. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http2).',
requiredArtifacts: ['URL', 'networkRecords']
requiredArtifacts: ['URL', 'devtoolsLogs']
};
}

Expand All @@ -47,40 +47,42 @@ class UsesHTTP2Audit extends Audit {
* @return {!AuditResult}
*/
static audit(artifacts) {
const networkRecords = artifacts.networkRecords[Audit.DEFAULT_PASS];
const finalHost = new URL(artifacts.URL.finalUrl).host;
const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords => {
const finalHost = new URL(artifacts.URL.finalUrl).host;

// Filter requests that are on the same host as the page and not over h2.
const resources = networkRecords.filter(record => {
const requestHost = new URL(record._url).host;
const sameHost = requestHost === finalHost;
const notH2 = /HTTP\/[01][\.\d]?/i.test(record.protocol);
return sameHost && notH2;
}).map(record => {
return {
protocol: record.protocol,
url: record.url // .url is a getter and not copied over for the assign.
};
});
// Filter requests that are on the same host as the page and not over h2.
const resources = networkRecords.filter(record => {
const requestHost = new URL(record._url).host;
const sameHost = requestHost === finalHost;
const notH2 = /HTTP\/[01][\.\d]?/i.test(record.protocol);
return sameHost && notH2;
}).map(record => {
return {
protocol: record.protocol,
url: record.url // .url is a getter and not copied over for the assign.
};
});

let displayValue = '';
if (resources.length > 1) {
displayValue = `${resources.length} requests were not handled over h2`;
} else if (resources.length === 1) {
displayValue = `${resources.length} request was not handled over h2`;
}
let displayValue = '';
if (resources.length > 1) {
displayValue = `${resources.length} requests were not handled over h2`;
} else if (resources.length === 1) {
displayValue = `${resources.length} request was not handled over h2`;
}

return {
rawValue: resources.length === 0,
displayValue: displayValue,
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.TABLE,
value: {
results: resources,
tableHeadings: {url: 'URL', protocol: 'Protocol'}
return {
rawValue: resources.length === 0,
displayValue: displayValue,
extendedInfo: {
formatter: Formatter.SUPPORTED_FORMATS.TABLE,
value: {
results: resources,
tableHeadings: {url: 'URL', protocol: 'Protocol'}
}
}
}
};
};
});
}
}

Expand Down
Loading