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

Fix: Limit false positives for async stylesheets #1389

Merged
merged 2 commits into from
Jan 4, 2017
Merged

Conversation

patrickhulce
Copy link
Collaborator

Attempts to reduce false positive rate for tags blocking first paint. Whitelists tags that were added via script or whose rel/async/disabled attributes indicated asynchronous behavior at any point in their lifecycle.

Addresses #1317

Attempts to reduce false positive rate for tags blocking first paint. Whitelists tags that were added via script or whose rel/async/disabled attributes indicated asynchronous behavior at any point in their lifecycle.

Addresses #1317
@ebidel
Copy link
Contributor

ebidel commented Jan 3, 2017

cc @gauntface

}

window.__asyncLinks = window.__asyncLinks || {};
setInterval(checkForLinks, 100);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

couldn't use documentUpdated because the granularity was too coarse

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

also has the unfortunate wrinkle that if a blocking script occurs in the head before the stylesheet and the script takes longer than the stylesheet to load and execute the querySelector will return nothing and we will have missed the window to identify it as a preloaded stylesheet

@gauntface
Copy link

I'm not 100% sure what this is doing.

Is it looking at the initial page, noting the stylesheets following the loadCSS usage of rel=preload to then account for the rel=stylesheet change after load?

If so, how would this behave with developers that use loadCSS like so:

loadCSS( "path/to/mystylesheet.css" );

My personal site waits for page load before adding the link tag with javascript, which may or may not be the same as loadCSS().

@patrickhulce
Copy link
Collaborator Author

@gauntface this first step attacks the problem from two angles.

  1. Any stylesheet added with JavaScript is no longer marked as blocking, so if you're adding tags with script and not using document.write you shouldn't fail the audit.
  2. If the rel=preload approach is used the network request still reports the HTML parser as the initiator and so we instead poll for any link tags that at one point were non-blocking and remove those from the set of blocking tags we report.

@gauntface
Copy link

LGTM from me - Thanks for this @patrickhulce. Seems like a good solution to me.

@@ -21,6 +21,21 @@ const Gatherer = require('../gatherer');
/* global document,window */

Copy link
Member

Choose a reason for hiding this comment

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

can you add a big @fileoverview comment block at the top that explains how this gatherer works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

function saveAsyncLinks() {
function checkForLinks() {
document.querySelectorAll('link').forEach(link => {
if (link.rel === 'preload' || link.disabled || link.async) {
Copy link
Contributor

Choose a reason for hiding this comment

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

link.hasAttribute('async'). Link doesn't have a .async property.

Copy link
Contributor

Choose a reason for hiding this comment

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

Though I'm not sure we need to check for this one. async only applies to HTMLImports and I can think of a use case where someone would set async on an import, only to remove it later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

whoops, good catch. Yeah I'll remove.

@@ -62,7 +78,11 @@ function collectTagsThatBlockFirstPaint() {
function filteredAndIndexedByUrl(networkRecords) {
return networkRecords.reduce((prev, record) => {
// Filter stylesheet, javascript, and html import mimetypes.
if (/(css|html|script)/.test(record._mimeType)) {
const isHtml = record._mimeType.indexOf('html') > -1;
// See https://html.spec.whatwg.org/multipage/semantics.html#interactions-of-styling-and-scripting
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a supplemental comment to the supporting link?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

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

nice work!

@paulirish paulirish merged commit 6fb07ea into master Jan 4, 2017
@paulirish paulirish deleted the allow_async_links branch January 4, 2017 19:45
andrewrota pushed a commit to andrewrota/lighthouse that referenced this pull request Jan 13, 2017
Attempts to reduce false positive rate for tags blocking first paint. Whitelists tags that were added via script or whose rel/async/disabled attributes indicated asynchronous behavior at any point in their lifecycle.

Addresses GoogleChrome#1317
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants