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

new_audit: add no-unload-listeners audit #11085

Merged
merged 7 commits into from
Jul 21, 2020
Merged

new_audit: add no-unload-listeners audit #11085

merged 7 commits into from
Jul 21, 2020

Conversation

brendankenny
Copy link
Member

@brendankenny brendankenny commented Jul 10, 2020

Fixes #10848. WIP for now All should feel free to comment on the details to highlight and advice the audit should provide.

Right now the audit fails if any 'unload' listener is registered, and recommends using 'pagehide' or 'visibilitychange' instead (leaving it up to the (eventually) linked docs to explain which of the two you might choose to use). The audit table is just using the plain old violations-style table using source-location, happy to iterate:

unload event LH audit screenshot

live example:
https://googlechrome.github.io/lighthouse/viewer/?gist=12c8d8d522e867564a4c3a526f4981bd

old example unload event LH audit screenshot

live example (scroll down to Best Practices)
https://googlechrome.github.io/lighthouse/viewer/?gist=aeb90c472c6c079e0429faf370bb83b1


for the new gatherer, this information didn't really fit into an existing one, and I didn't really want to open us up to just collecting all the event listeners, so I kept it somewhat narrow in scope. I did include other unload-adjacent events because I get the feeling from talking to @philipwalton that there is more analysis we can do here about bfcache-worthiness, but if that doesn't materialize I can also narrow it down even more. I'm also open to completely different ideas :)

@brendankenny brendankenny requested a review from a team as a code owner July 10, 2020 18:27
@brendankenny brendankenny requested review from patrickhulce and removed request for a team July 10, 2020 18:27
@brendankenny brendankenny marked this pull request as draft July 10, 2020 18:29
/** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
failureTitle: 'Listens for the `unload` event',
/** Description of a Lighthouse audit that tells the user why pages should not use the 'unload' event. This is displayed after a user expands the section to see more. 'Learn More' becomes link text to additional documentation. */
description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the back/forward cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn More](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#legacy-lifecycle-apis-to-avoid)',
Copy link
Member Author

Choose a reason for hiding this comment

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

url will be updated when we have an article

/** @type {LH.Audit.Details.Table['items']} */
const tableItems = unloadListeners.map(listener => {
// Look up scriptId to script URL via the JsUsage artifact.
const usageEntry = jsUsageValues.find(usage => usage.scriptId === listener.scriptId);
Copy link
Member Author

Choose a reason for hiding this comment

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

The protocol doesn't give script URLs for event listeners, just scriptIds, so JsUsage seemed like the best place to get the mapping.

Comment on lines 29 to 32
const {result: {objectId}} = await driver.sendCommand('Runtime.evaluate', {
expression: 'window',
returnByValue: false,
});
Copy link
Member Author

Choose a reason for hiding this comment

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

if anyone has an easier way of getting window's RemoteObjectId, please let me know :)

Comment on lines 16 to 18
return listener.type === 'pagehide' ||
listener.type === 'unload' ||
listener.type === 'visibilitychange';
Copy link
Member Author

Choose a reason for hiding this comment

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

as mentioned in the PR description, this can go back to just unload before landing, but there may be more analysis that we can do with these so leaving it like this for now

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

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

seems like this could be upgraded to non-draft, nothing showstopping here looks good to me 👍

lighthouse-core/gather/gatherers/unload-listeners.js Outdated Show resolved Hide resolved
lighthouse-core/audits/no-unload-listeners.js Outdated Show resolved Hide resolved
@brendankenny
Copy link
Member Author

switched to source-location and updated the PR description with a better example with multiple (first and third party) unload handlers

@brendankenny
Copy link
Member Author

done and done

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

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

a basic unit test for the audit linking up the script ID to the network would be nice

LGTM otherwise 🎉

lighthouse-core/audits/no-unload-listeners.js Outdated Show resolved Hide resolved
lighthouse-core/test/results/sample_v2.json Outdated Show resolved Hide resolved
Copy link
Member Author

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

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

a basic unit test for the audit linking up the script ID to the network would be nice

yes, definitely, in progress :)

lighthouse-core/audits/no-unload-listeners.js Outdated Show resolved Hide resolved
lighthouse-core/test/results/sample_v2.json Outdated Show resolved Hide resolved
/** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
failureTitle: 'Listens for the `unload` event',
/** Description of a Lighthouse audit that tells the user why pages should not use the 'unload' event. This is displayed after a user expands the section to see more. 'Learn More' becomes link text to additional documentation. */
description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the back/forward cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn More](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the back/forward cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn More](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)',
description: 'The `unload` event does not fire reliably and listening for it prevents browser optimizations like the back/forward cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn More](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)',

?

Copy link
Member Author

Choose a reason for hiding this comment

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

wellllll, that may be complicated :) I'll wait for @philipwalton and others to come weigh in on everything and we can nail down the exact wording all at once

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -552,6 +554,7 @@ const defaultConfig = {
{id: 'doctype', weight: 1, group: 'best-practices-browser-compat'},
{id: 'charset', weight: 1, group: 'best-practices-browser-compat'},
// General Group
{id: 'no-unload-listeners', weight: 1, group: 'best-practices-general'},
Copy link
Collaborator

Choose a reason for hiding this comment

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

feels like it could be a diagnostic too, any particular decision insights behind best practices we can leave for future git blame archeologists? :)

Copy link
Member Author

Choose a reason for hiding this comment

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

feels like it could be a diagnostic too, any particular decision insights behind best practices we can leave for future git blame archeologists? :)

I guess it kind of falls in with uses-long-cache-ttl as something diagnosing performance, just not the performance of any of the metrics just measured (since a Lighthouse run isn't (usually) with a warm cache or on a hit of the back button). I guess I could see the argument that it's still worthwhile to have there, but I chose this as the uncontroversial spot to put it. I don't feel strongly :)

return listeners
.filter(GlobalListeners._filterForUnloadTypes)
.map(listener => {
const {type, scriptId, lineNumber, columnNumber} = listener;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm just noticing this is already back in node-land so serialization isn't the reason for reexposing, just trying to limit what we return?

Copy link
Member Author

Choose a reason for hiding this comment

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

just trying to limit what we return?

yeah

/** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
failureTitle: 'Listens for the `unload` event',
/** Description of a Lighthouse audit that tells the user why pages should not use the 'unload' event. This is displayed after a user expands the section to see more. 'Learn More' becomes link text to additional documentation. */
description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the back/forward cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn More](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)',
Copy link
Member

Choose a reason for hiding this comment

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

https://webkit.org/blog/427/webkit-page-cache-i-the-basics/ and https://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ cover it as well. also shout out to Dojo for addressing this audit 11 years ago. :)

/** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds none. */
title: 'Avoids `unload` event listeners',
/** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
failureTitle: 'Listens for the `unload` event',
Copy link
Member

Choose a reason for hiding this comment

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

Alt wording would be "Registers an unload listener". I like it a tad more, but, not a huge deal.

Copy link
Member Author

Choose a reason for hiding this comment

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

Alt wording would be "Registers an unload listener". I like it a tad more, but, not a huge deal.

I guess it's technically still true, but a little awkward when the page registers multiple unload listeners (plural).

@brendankenny brendankenny merged commit ca5b892 into master Jul 21, 2020
@brendankenny brendankenny deleted the unloadlisteners branch July 21, 2020 19:37
kodiakhq bot pushed a commit to vercel/next.js that referenced this pull request Sep 12, 2020
ref GoogleChrome/web-vitals#68

won't fail the new [`no-unload-listeners`](GoogleChrome/lighthouse#11085) Lighthouse audit.
HitoriSensei pushed a commit to HitoriSensei/next.js that referenced this pull request Sep 26, 2020
ref GoogleChrome/web-vitals#68

won't fail the new [`no-unload-listeners`](GoogleChrome/lighthouse#11085) Lighthouse audit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create a Performance audit for avoiding the unload event
7 participants