Skip to content

Commit

Permalink
networkRecords => computed artifact.
Browse files Browse the repository at this point in the history
generate networkRecords during gather via the networkRecorder dispatcher
breaking change: performanceLog => devtoolsLogs
  • Loading branch information
paulirish committed May 5, 2017
1 parent 9ccfd00 commit 11a1db3
Show file tree
Hide file tree
Showing 33 changed files with 464 additions and 356 deletions.
2 changes: 0 additions & 2 deletions lighthouse-cli/test/smokehouse/pwa-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/
module.exports = {
passes: [{
recordNetwork: true,
recordTrace: true,
gatherers: [
'url',
Expand All @@ -33,7 +32,6 @@ module.exports = {
},
{
passName: 'offlinePass',
recordNetwork: true,
gatherers: [
'service-worker',
'offline'
Expand Down
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 =>
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 @@ -42,7 +42,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']
};
}

Expand Down
81 changes: 41 additions & 40 deletions lighthouse-core/audits/byte-efficiency/total-byte-weight.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,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 @@ -55,53 +55,54 @@ 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);

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: {
url: 'URL',
totalKb: 'Total Size',
totalMs: 'Transfer Time',
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: {
url: 'URL',
totalKb: 'Total Size',
totalMs: 'Transfer Time',
}
}
}
}
};
};
});
});
}
}
Expand Down
36 changes: 19 additions & 17 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 @@ -171,23 +171,25 @@ 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);

return {
results,
tableHeadings: {
url: 'URL',
numUnused: 'Unused Rules',
totalKb: 'Original',
potentialSavings: 'Potential Savings',
}
};
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);

return {
results,
tableHeadings: {
url: 'URL',
numUnused: 'Unused Rules',
totalKb: 'Original',
potentialSavings: 'Potential Savings',
}
};
});
}
}

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']
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,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']
};
}

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']
};
}

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

0 comments on commit 11a1db3

Please sign in to comment.