diff --git a/lighthouse-cli/test/fixtures/dobetterweb/dbw_tester.html b/lighthouse-cli/test/fixtures/dobetterweb/dbw_tester.html index 32e75993292a..8089053387c8 100644 --- a/lighthouse-cli/test/fixtures/dobetterweb/dbw_tester.html +++ b/lighthouse-cli/test/fixtures/dobetterweb/dbw_tester.html @@ -149,6 +149,13 @@

Do better web tester page

Hi there! + + + + Facebook + + +
touchmove section
diff --git a/lighthouse-cli/test/smokehouse/dbw-config.js b/lighthouse-cli/test/smokehouse/dbw-config.js index 7226e3f3e7f5..c4f87d8356db 100644 --- a/lighthouse-cli/test/smokehouse/dbw-config.js +++ b/lighthouse-cli/test/smokehouse/dbw-config.js @@ -19,6 +19,7 @@ module.exports = { 'render-blocking-resources', 'errors-in-console', 'efficient-animated-content', + 'apple-touch-icon', // pull in apple touch icon to test `LinkElements` ], }, }; diff --git a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js index c6a86c2d975e..a64801be3577 100644 --- a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js +++ b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js @@ -16,6 +16,107 @@ module.exports = [ }, { id: 'wordpress', }], + LinkElements: [ + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=100', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=100', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/unknown404.css?delay=200', + hrefRaw: 'http://localhost:10200/dobetterweb/unknown404.css?delay=200', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=2200', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=2200', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_disabled.css?delay=200&isdisabled', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_disabled.css?delay=200&isdisabled', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'import', + href: 'http://localhost:10200/dobetterweb/dbw_partial_a.html?delay=200', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_partial_a.html?delay=200', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'import', + href: 'http://localhost:10200/dobetterweb/dbw_partial_b.html?delay=200&isasync', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_partial_b.html?delay=200&isasync', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=3000&capped', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=3000&capped', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=2000&async=true', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=2000&async=true', + hreflang: '', + as: 'style', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=3000&async=true', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?delay=3000&async=true', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'alternate stylesheet', + href: 'http://localhost:10200/dobetterweb/empty.css', + hrefRaw: 'http://localhost:10200/dobetterweb/empty.css', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + { + rel: 'stylesheet', + href: 'http://localhost:10200/dobetterweb/dbw_tester.css?scriptActivated&delay=200', + hrefRaw: 'http://localhost:10200/dobetterweb/dbw_tester.css?scriptActivated&delay=200', + hreflang: '', + as: '', + crossOrigin: null, + source: 'head', + }, + ], TagsBlockingFirstPaint: [ { tag: { @@ -261,11 +362,11 @@ module.exports = [ }, 'dom-size': { score: 1, - numericValue: 137, + numericValue: 141, details: { items: [ - {statistic: 'Total DOM Elements', value: '137'}, - {statistic: 'Maximum DOM Depth', value: '3'}, + {statistic: 'Total DOM Elements', value: '141'}, + {statistic: 'Maximum DOM Depth', value: '4'}, { statistic: 'Maximum Child Elements', value: '100', diff --git a/lighthouse-core/gather/gatherers/link-elements.js b/lighthouse-core/gather/gatherers/link-elements.js index 156dad46c254..a6961ed8b1b6 100644 --- a/lighthouse-core/gather/gatherers/link-elements.js +++ b/lighthouse-core/gather/gatherers/link-elements.js @@ -9,8 +9,9 @@ const Gatherer = require('./gatherer.js'); const URL = require('../../lib/url-shim.js').URL; const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js'); const LinkHeader = require('http-link-header'); -const getElementsInDocumentString = require('../../lib/page-functions.js') - .getElementsInDocumentString; // eslint-disable-line max-len +const {getElementsInDocumentString} = require('../../lib/page-functions.js'); + +/* globals HTMLLinkElement */ /** * @fileoverview @@ -42,6 +43,36 @@ function getCrossoriginFromHeader(value) { return null; } +/** + * @return {LH.Artifacts['LinkElements']} + */ +/* istanbul ignore next */ +function getLinkElementsInDOM() { + /** @type {Array} */ + // @ts-ignore - getElementsInDocument put into scope via stringification + const browserElements = getElementsInDocument('link'); // eslint-disable-line no-undef + /** @type {LH.Artifacts['LinkElements']} */ + const linkElements = []; + + for (const link of browserElements) { + // We're only interested in actual LinkElements, not `` tagName elements inside SVGs. + // https://github.com/GoogleChrome/lighthouse/issues/9764 + if (!(link instanceof HTMLLinkElement)) continue; + + linkElements.push({ + rel: link.rel, + href: link.href, + hrefRaw: link.href, + hreflang: link.hreflang, + as: link.as, + crossOrigin: link.crossOrigin, + source: link.closest('head') ? 'head' : 'body', + }); + } + + return linkElements; +} + class LinkElements extends Gatherer { /** * @param {LH.Gatherer.PassContext} passContext @@ -52,18 +83,9 @@ class LinkElements extends Gatherer { // the values like access from JavaScript does. return passContext.driver.evaluateAsync(`(() => { ${getElementsInDocumentString}; + ${getLinkElementsInDOM}; - return getElementsInDocument('link').map(link => { - return { - rel: link.rel, - href: link.href, - hrefRaw: link.href, - hreflang: link.hreflang, - as: link.as, - crossOrigin: link.crossOrigin, - source: link.closest('head') ? 'head' : 'body', - }; - }); + return getLinkElementsInDOM(); })()`, {useIsolation: true}); } diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index 50b188531672..cf188d1aeba8 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -217,7 +217,7 @@ declare global { /** The `as` attribute of the link */ as: string /** The `crossOrigin` attribute of the link */ - crossOrigin: 'anonymous'|'use-credentials'|null + crossOrigin: string | null /** Where the link was found, either in the DOM or in the headers of the main document */ source: 'head'|'body'|'headers' }