feat(redirects-audit): Adding Redirect audit (PSI Compat)#3308
feat(redirects-audit): Adding Redirect audit (PSI Compat)#3308paulirish merged 17 commits intoGoogleChrome:masterfrom
Conversation
|
nice! using the time taken for everything but the last request (minus TCP handshake if its the same domain) as wasted ms sounds good to me |
|
do we need a smoke test? |
|
Ideally yes, though we'd have to add some kind of redirect support to the test server? Alternatively, some of the PWAs for the smokehouse run on live sites were chosen because they redirect. We could expand |
|
if it ends up being complicated, we can do in a followup to keep the PR single-purpose |
lighthouse-core/audits/redirects.js
Outdated
| displayValue: pageRedirects.length, | ||
| rawValue: passed, | ||
| extendedInfo: { | ||
| value: pageRedirects |
There was a problem hiding this comment.
yah lets calculated the wasted time. we can then show this in opportunities rather than diagnostics.
paulirish
left a comment
There was a problem hiding this comment.
a few more things noted. still thinking this should move to Opportunities with a wastedMs calculation.
lighthouse-core/audits/redirects.js
Outdated
| const Audit = require('./audit'); | ||
|
|
||
| // PSI allows one redirect (http://example.com => http://m.example.com) | ||
| const REDIRECT_TRESHOLD = 1; |
lighthouse-core/audits/redirects.js
Outdated
| const passed = pageRedirects.length <= REDIRECT_TRESHOLD; | ||
| if (!passed) { | ||
| debugString = `Your page has ${pageRedirects.length} redirects.` + | ||
| ' Redirects introduce additional delays before the page can be loaded.'; |
There was a problem hiding this comment.
I guess we dont need this second sentence since its already in helptext
65e45ac to
3e0f9d9
Compare
lighthouse-core/audits/redirects.js
Outdated
| } | ||
|
|
||
| static isRedirect(requestKey) { | ||
| return requestKey.includes('redirected'); |
There was a problem hiding this comment.
it looks like we depend here on 'redirected' being used in the name of request ID. IMO it'd be better to use something more solid likeWebInspector.NetworkRequest.redirects or request status code.
Since I'm dealing with a similar thing here: #3311 . How about creating a MainResource computed artifact that exposes WebInspector.NetworkRequest.redirects that we both could use?
There was a problem hiding this comment.
@kdzwinel Should we name it more like getMainResourceChain?
There was a problem hiding this comment.
@kdzwinel I think we have a slightly different use case :) I need to get the redirects as well so I cannot use the computed artifact
There was a problem hiding this comment.
@wardpeet maybe I'm missing something, but when you request a MainResource artifact you also get all NetworkRequest (that contain all timing info) representing all redirects that led to that resource. Check out this:
Isn't that all you need to compute the time wasted in redirects?
There was a problem hiding this comment.
ah sorry I missed that! Great!
There was a problem hiding this comment.
Awesome 🙌 I already got one 👍 on my PR, so I hope to merge soon.
There was a problem hiding this comment.
MainResource computed artifact sgtm, we'll prob want to move away from more "chain-like" computed artifacts though going forward and try to make use of the page-dependency-graph instead
| const cacheBuster = Number(new Date()); | ||
| module.exports = [ | ||
| { | ||
| initialUrl: `http://localhost:10200/online-only.html?cb=${cacheBuster}&delay=500&redirect=%2Foffline-only.html%3Fcb=${cacheBuster}%26delay=500%26redirect%3D%2Fredirects-final.html`, |
There was a problem hiding this comment.
ha this is quite the URL :)
patrickhulce
left a comment
There was a problem hiding this comment.
sweet I like the look of this one!
| url: 'http://localhost:10200/redirects-final.html', | ||
| audits: { | ||
| 'redirects': { | ||
| score: 2, |
There was a problem hiding this comment.
let's assert on details length instead
| url: 'http://localhost:10200/redirects-final.html', | ||
| audits: { | ||
| 'redirects': { | ||
| score: 1, |
lighthouse-core/audits/redirects.js
Outdated
|
|
||
| return { | ||
| debugString, | ||
| score: pageRedirects.length, |
There was a problem hiding this comment.
score actually has meaning for the opportunities and is used to color the bar based on how bad the offending opportunity was, they can still get this information from the details length
8da4782 to
f9db70a
Compare
|
@patrickhulce Updated the PR :) what do you think? |
patrickhulce
left a comment
There was a problem hiding this comment.
thanks for the quick turnaround @wardpeet! :)
chrome-launcher/ask.js
Outdated
| @@ -0,0 +1,32 @@ | |||
| /** | |||
lighthouse-core/audits/redirects.js
Outdated
|
|
||
| return { | ||
| debugString, | ||
| score: passed, |
There was a problem hiding this comment.
oops, maybe I wasn't very clear last time my bad!
score is automatically determined for the performance opportunities, let's reuse that
| url: 'http://localhost:10200/redirects-final.html', | ||
| audits: { | ||
| 'redirects': { | ||
| score: false, |
There was a problem hiding this comment.
once the numeric score is brought back, let's assert that this score is in the lowest bracket
46255c4 to
569e407
Compare
lighthouse-core/audits/redirects.js
Outdated
| let debugString = null; | ||
|
|
||
| const pageRedirects = redirectRequests.map(request => { | ||
| const wastedMs = (request.endTime - request.startTime) * 1000; |
There was a problem hiding this comment.
I don't think this is what we want here, from the screenshot of gmail it looks like request.endTime is the end time of the final mainResource, I think we want something more like requests[1].startTime - requests[0].startTime?
lighthouse-core/audits/redirects.js
Outdated
| }; | ||
| }); | ||
|
|
||
| const passed = pageRedirects.length <= REDIRECT_THRESHOLD; |
There was a problem hiding this comment.
let's go ahead and nuke the passed and debugString now that passed isn't needed, hopefully its clear from the table how many redirects they had :)
lighthouse-core/audits/redirects.js
Outdated
|
|
||
| const headings = [ | ||
| {key: 'url', itemType: 'text', text: 'URL'}, | ||
| {key: 'wastedMs', itemType: 'text', text: 'Wasted ms'}, |
There was a problem hiding this comment.
nit: let's set the text to "Time for Redirect"
patrickhulce
left a comment
There was a problem hiding this comment.
looks great! I'm ready to approve % open question about how to handle totalWastedMs :)
lighthouse-core/audits/redirects.js
Outdated
| name: 'redirects', | ||
| description: 'Avoids page redirects.', | ||
| failureDescription: 'Has page redirects.', | ||
| helpText: ' Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/speed/docs/insights/AvoidRedirects).', |
There was a problem hiding this comment.
nit: remove space at beginning
lighthouse-core/audits/redirects.js
Outdated
| const request = redirectRequests[i - 1]; | ||
| const nextRequest = redirectRequests[i]; | ||
| const wastedMs = (nextRequest.startTime - request.startTime) * 1000; | ||
| totalWastedMs += wastedMs; |
There was a problem hiding this comment.
I liked what you had about allowing a single redirect before like PSI, wdyt about excluding the first redirect cost from totalWastedMs but still reporting how long it took?
There was a problem hiding this comment.
I like as we should report all redirects as a cost is a cost +1
patrickhulce
left a comment
There was a problem hiding this comment.
nicely done! 🎉 💯
to you @paulirish if you still have lingering requested changes
lighthouse-core/audits/redirects.js
Outdated
| category: 'Performance', | ||
| name: 'redirects', | ||
| description: 'Avoids page redirects.', | ||
| failureDescription: 'Has page redirects.', |
There was a problem hiding this comment.
nit: I'd prefer adding an 'excessive' or some qualifier here so it's clear you can have one
There was a problem hiding this comment.
😱 I'm not that good with words in english so what about
Has more than one page redirects?
There was a problem hiding this comment.
heh sure Has more than one page redirect 👍
| audits: { | ||
| 'redirects': { | ||
| score: 100, | ||
| rawValue: '>=0', |
There was a problem hiding this comment.
nit: we can assert 0 exactly here, right?
brendankenny
left a comment
There was a problem hiding this comment.
sorry, drive-by nits on just the smoke testing part :)
|
|
||
| function sendResponse(statusCode, data) { | ||
| let headers; | ||
| let headers = {}; |
There was a problem hiding this comment.
this change not needed anymore?
| function sendResponse(statusCode, data) { | ||
| let headers; | ||
| let headers = {}; | ||
| let delay = 0; |
There was a problem hiding this comment.
maybe move delay declaration to below the filePath.endsWith set of conditionals since it's not used until inside if (queryString) {}?
|
|
||
| // redirect url to new url if present | ||
| if (typeof queryString.redirect !== 'undefined') { | ||
| if (delay > 0) { |
There was a problem hiding this comment.
since delay defaults to 0, for code readability this could just drop the delay check and do return setTimeout(sendRedirect, delay, queryString.redirect); for both
|
|
||
| // Delay the response by the specified ms defaulting to 2000ms for non-numeric values | ||
| if (queryString && typeof queryString.delay !== 'undefined') { | ||
| response.write(''); |
There was a problem hiding this comment.
was response.write(''); important here? I have no idea :) but it was here since the first version
There was a problem hiding this comment.
I don't think so as response.write(''); as response.end() is important to close the request.
maybe @paulirish still knows why he added it.
There was a problem hiding this comment.
i barely remember it being important. is it fine if we keep it as is?
There was a problem hiding this comment.
keep it as is = add the response.write('')?
There was a problem hiding this comment.
okay scratch what i said. response.write('') is a noop.
.write('.') does change things quite considerably, but in a bad direction. (the latency moves from TTFB to content download).
your change here is great. let's keep it. :)
|
|
||
| module.exports = [ | ||
| { | ||
| initialUrl: `http://localhost:10200/online-only.html?cb=${cacheBuster}&delay=500&redirect=%2Foffline-only.html%3Fcb=${cacheBuster}%26delay=500%26redirect%3D%2Fredirects-final.html`, |
There was a problem hiding this comment.
smokehouse should be opening a new instance of chrome for each expectations entry, so are the cache busters necessary?
|
@paulirish I can add it to the table :) give me a sec 😸 |
paulirish
left a comment
There was a problem hiding this comment.
I have some proposed superficial changes. I'd like to merge this PR as it is and i'll followup with a PR for ward to review.
|
|
||
| // Delay the response by the specified ms defaulting to 2000ms for non-numeric values | ||
| if (queryString && typeof queryString.delay !== 'undefined') { | ||
| response.write(''); |
There was a problem hiding this comment.
okay scratch what i said. response.write('') is a noop.
.write('.') does change things quite considerably, but in a bad direction. (the latency moves from TTFB to content download).
your change here is great. let's keep it. :)










Fixes #3210
fixes #605
Looking at psi it allows 1 redirect (not sure if we should only consider subdomains as allowed redirects).
https://example.com -> https://m.example.com
Report:

Perhaps we should use start & end time to calculate wasted ms?