-
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
new_audit(preload-audit): Adding preload audit #3450
Changes from all commits
3643a98
ba99764
63fb8e3
c640e4f
468b386
6069687
f127efc
b34de60
dc697a4
dddf663
47fab53
ac6620d
8194adc
31c838d
ae68a0e
1164106
930cad4
c468866
c2534f6
6acd392
14c36f9
b9591f0
d18b045
6e4b183
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* @license Copyright 2017 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
/* eslint-disable */ | ||
|
||
document.write('<script src="level-3.js"></script>'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* @license Copyright 2017 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
/* eslint-disable */ | ||
|
||
const dummyDiv = document.createElement('div'); | ||
dummyDiv.innerHTML = 'Hello!'; | ||
|
||
document.body.appendChild(dummyDiv); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
@font-face { | ||
font-family: "Lobster"; | ||
src: url("./lobster-v20-latin-regular.woff2") format("woff2"); | ||
} | ||
|
||
body { | ||
font-family: "Lobster"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* @license Copyright 2017 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
/* eslint-disable */ | ||
|
||
document.write('<script src="level-2.js?delay=500"></script>') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<html> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"> | ||
<link rel="stylesheet" href="/perf/preload_style.css" /> | ||
<body> | ||
There was nothing special about this site, | ||
nothing was left to be seen, | ||
not even a kite. | ||
<script src="/perf/preload_tester.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,42 @@ class CriticalRequestChains extends Audit { | |
return longest; | ||
} | ||
|
||
/** | ||
* @param {*} tree | ||
*/ | ||
static flattenRequests(tree) { | ||
const flattendChains = {}; | ||
const chainMap = new Map(); | ||
CriticalRequestChains._traverse(tree, opts => { | ||
let chain; | ||
if (chainMap.has(opts.id)) { | ||
chain = chainMap.get(opts.id); | ||
} else { | ||
chain = {}; | ||
flattendChains[opts.id] = chain; | ||
} | ||
|
||
const request = opts.node.request; | ||
chain.request = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe that flatten function is needed over here now? |
||
url: request.url, | ||
startTime: request.startTime, | ||
endTime: request.endTime, | ||
responseReceivedTime: request.responseReceivedTime, | ||
transferSize: request.transferSize, | ||
}; | ||
chain.children = {}; | ||
Object.keys(opts.node.children).forEach(chainId => { | ||
const childChain = {}; | ||
chainMap.set(chainId, childChain); | ||
chain.children[chainId] = childChain; | ||
}); | ||
|
||
chainMap.set(opts.id, chain); | ||
}); | ||
|
||
return flattendChains; | ||
} | ||
|
||
/** | ||
* Audits the page to give a score for First Meaningful Paint. | ||
* @param {!Artifacts} artifacts The artifacts from the gather phase. | ||
|
@@ -101,29 +137,31 @@ class CriticalRequestChains extends Audit { | |
walk(child.children, depth + 1); | ||
}, ''); | ||
} | ||
// Convert | ||
const flattenedChains = CriticalRequestChains.flattenRequests(chains); | ||
|
||
// Account for initial navigation | ||
const initialNavKey = Object.keys(chains)[0]; | ||
const initialNavChildren = initialNavKey && chains[initialNavKey].children; | ||
const initialNavKey = Object.keys(flattenedChains)[0]; | ||
const initialNavChildren = initialNavKey && flattenedChains[initialNavKey].children; | ||
if (initialNavChildren && Object.keys(initialNavChildren).length > 0) { | ||
walk(initialNavChildren, 0); | ||
} | ||
|
||
const longestChain = CriticalRequestChains._getLongestChain(chains); | ||
const longestChain = CriticalRequestChains._getLongestChain(flattenedChains); | ||
|
||
return { | ||
rawValue: chainCount === 0, | ||
displayValue: Util.formatNumber(chainCount), | ||
extendedInfo: { | ||
value: { | ||
chains, | ||
chains: flattenedChains, | ||
longestChain, | ||
}, | ||
}, | ||
details: { | ||
type: 'criticalrequestchain', | ||
header: {type: 'text', text: 'View critical network waterfall:'}, | ||
chains, | ||
chains: flattenedChains, | ||
longestChain, | ||
}, | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/** | ||
* @license Copyright 2017 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
const Audit = require('./audit'); | ||
const Util = require('../report/v2/renderer/util'); | ||
const UnusedBytes = require('./byte-efficiency/byte-efficiency-audit'); | ||
const THRESHOLD_IN_MS = 100; | ||
|
||
class UsesRelPreloadAudit extends Audit { | ||
/** | ||
* @return {!AuditMeta} | ||
*/ | ||
static get meta() { | ||
return { | ||
category: 'Performance', | ||
name: 'uses-rel-preload', | ||
description: 'Preload key requests', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's mark this as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
informative: true, | ||
helpText: 'Consider using <link rel=preload> to prioritize fetching late-discovered ' + | ||
'resources sooner [Learn more](https://developers.google.com/web/updates/2016/03/link-rel-preload).', | ||
requiredArtifacts: ['devtoolsLogs', 'traces'], | ||
scoringMode: Audit.SCORING_MODES.NUMERIC, | ||
}; | ||
} | ||
|
||
static _flattenRequests(chains, maxLevel, minLevel = 0) { | ||
const requests = []; | ||
const flatten = (chains, level) => { | ||
Object.keys(chains).forEach(chain => { | ||
if (chains[chain]) { | ||
const currentChain = chains[chain]; | ||
if (level >= minLevel) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting "bug".. :) repro:
it lists CRC depth=1 requests in the audit: but they're just depth=1 to my brain. in reality its because https://paulirish.com redirected to https://www.paulirish.com so we'll want to use the post-redirect URL as the root for this CRC depth calculation. Not sure how you want to handle this. if you want to grab the |
||
requests.push(currentChain.request); | ||
} | ||
|
||
if (level < maxLevel) { | ||
flatten(currentChain.children, level + 1); | ||
} | ||
} | ||
}); | ||
}; | ||
|
||
flatten(chains, 0); | ||
|
||
return requests; | ||
} | ||
|
||
/** | ||
* @param {!Artifacts} artifacts | ||
* @return {!AuditResult} | ||
*/ | ||
static audit(artifacts) { | ||
const devtoolsLogs = artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS]; | ||
|
||
return Promise.all([ | ||
artifacts.requestCriticalRequestChains(devtoolsLogs), | ||
artifacts.requestMainResource(devtoolsLogs), | ||
]).then(([critChains, mainResource]) => { | ||
const results = []; | ||
let maxWasted = 0; | ||
// get all critical requests 2 + mainResourceIndex levels deep | ||
const mainResourceIndex = mainResource.redirects ? mainResource.redirects.length : 0; | ||
|
||
const criticalRequests = UsesRelPreloadAudit._flattenRequests(critChains, | ||
3 + mainResourceIndex, 2 + mainResourceIndex); | ||
criticalRequests.forEach(request => { | ||
const networkRecord = request; | ||
if (!networkRecord._isLinkPreload && networkRecord.protocol !== 'data') { | ||
// calculate time between mainresource.endTime and resource start time | ||
const wastedMs = Math.min(request._startTime - mainResource._endTime, | ||
request._endTime - request._startTime) * 1000; | ||
|
||
if (wastedMs >= THRESHOLD_IN_MS) { | ||
maxWasted = Math.max(wastedMs, maxWasted); | ||
results.push({ | ||
url: request.url, | ||
wastedMs: Util.formatMilliseconds(wastedMs), | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
// sort results by wastedTime DESC | ||
results.sort((a, b) => b.wastedMs - a.wastedMs); | ||
|
||
const headings = [ | ||
{key: 'url', itemType: 'url', text: 'URL'}, | ||
{key: 'wastedMs', itemType: 'text', text: 'Potential Savings'}, | ||
]; | ||
const details = Audit.makeTableDetails(headings, results); | ||
|
||
return { | ||
score: UnusedBytes.scoreForWastedMs(maxWasted), | ||
rawValue: maxWasted, | ||
displayValue: Util.formatMilliseconds(maxWasted), | ||
extendedInfo: { | ||
value: results, | ||
}, | ||
details, | ||
}; | ||
}); | ||
} | ||
} | ||
|
||
module.exports = UsesRelPreloadAudit; |
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.
if we're changing this URL do we need the separate entry below still?