lighthouse 12.8.2 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/cli-flags.js +1 -1
- package/cli/test/smokehouse/config/exclusions.js +0 -2
- package/cli/test/smokehouse/version-check.d.ts +1 -1
- package/core/audits/accessibility/accesskeys.js +3 -3
- package/core/audits/accessibility/aria-allowed-attr.js +3 -3
- package/core/audits/accessibility/aria-allowed-role.js +2 -1
- package/core/audits/accessibility/aria-command-name.js +1 -1
- package/core/audits/accessibility/aria-conditional-attr.js +1 -1
- package/core/audits/accessibility/aria-deprecated-role.js +1 -1
- package/core/audits/accessibility/aria-dialog-name.js +1 -1
- package/core/audits/accessibility/aria-hidden-body.js +3 -3
- package/core/audits/accessibility/aria-hidden-focus.js +3 -3
- package/core/audits/accessibility/aria-input-field-name.js +3 -3
- package/core/audits/accessibility/aria-meter-name.js +1 -1
- package/core/audits/accessibility/aria-progressbar-name.js +1 -1
- package/core/audits/accessibility/aria-prohibited-attr.js +1 -1
- package/core/audits/accessibility/aria-required-attr.js +3 -3
- package/core/audits/accessibility/aria-required-children.js +3 -3
- package/core/audits/accessibility/aria-required-parent.js +3 -3
- package/core/audits/accessibility/aria-roles.js +3 -3
- package/core/audits/accessibility/aria-text.js +3 -3
- package/core/audits/accessibility/aria-toggle-field-name.js +3 -3
- package/core/audits/accessibility/aria-tooltip-name.js +1 -1
- package/core/audits/accessibility/aria-treeitem-name.js +1 -1
- package/core/audits/accessibility/aria-valid-attr-value.js +3 -3
- package/core/audits/accessibility/aria-valid-attr.js +3 -3
- package/core/audits/accessibility/button-name.js +3 -3
- package/core/audits/accessibility/bypass.js +3 -3
- package/core/audits/accessibility/color-contrast.js +3 -3
- package/core/audits/accessibility/definition-list.js +3 -3
- package/core/audits/accessibility/dlitem.js +3 -3
- package/core/audits/accessibility/document-title.js +3 -3
- package/core/audits/accessibility/duplicate-id-aria.js +3 -3
- package/core/audits/accessibility/empty-heading.js +3 -3
- package/core/audits/accessibility/form-field-multiple-labels.js +3 -3
- package/core/audits/accessibility/frame-title.js +3 -3
- package/core/audits/accessibility/heading-order.js +3 -3
- package/core/audits/accessibility/html-has-lang.js +3 -3
- package/core/audits/accessibility/html-lang-valid.js +3 -3
- package/core/audits/accessibility/html-xml-lang-mismatch.js +3 -3
- package/core/audits/accessibility/identical-links-same-purpose.js +3 -3
- package/core/audits/accessibility/image-alt.js +3 -3
- package/core/audits/accessibility/image-redundant-alt.js +4 -3
- package/core/audits/accessibility/input-button-name.js +3 -3
- package/core/audits/accessibility/input-image-alt.js +3 -3
- package/core/audits/accessibility/label-content-name-mismatch.js +3 -3
- package/core/audits/accessibility/label.js +3 -3
- package/core/audits/accessibility/landmark-one-main.js +3 -4
- package/core/audits/accessibility/link-in-text-block.js +3 -3
- package/core/audits/accessibility/link-name.js +3 -3
- package/core/audits/accessibility/list.js +3 -3
- package/core/audits/accessibility/listitem.js +3 -3
- package/core/audits/accessibility/meta-refresh.js +3 -3
- package/core/audits/accessibility/meta-viewport.js +3 -3
- package/core/audits/accessibility/object-alt.js +3 -3
- package/core/audits/accessibility/select-name.js +3 -3
- package/core/audits/accessibility/skip-link.js +3 -3
- package/core/audits/accessibility/tabindex.js +3 -3
- package/core/audits/accessibility/table-duplicate-name.js +4 -3
- package/core/audits/accessibility/table-fake-caption.js +3 -3
- package/core/audits/accessibility/target-size.js +3 -3
- package/core/audits/accessibility/td-has-header.js +3 -3
- package/core/audits/accessibility/td-headers-attr.js +3 -3
- package/core/audits/accessibility/th-has-data-cells.js +3 -3
- package/core/audits/accessibility/valid-lang.js +3 -3
- package/core/audits/accessibility/video-caption.js +3 -3
- package/core/audits/audit.d.ts +0 -4
- package/core/audits/audit.js +2 -13
- package/core/audits/insights/cls-culprits-insight.js +1 -1
- package/core/audits/insights/dom-size-insight.js +11 -7
- package/core/audits/insights/font-display-insight.js +3 -1
- package/core/audits/insights/image-delivery-insight.js +4 -1
- package/core/audits/insights/insight-audit.d.ts +6 -4
- package/core/audits/insights/insight-audit.js +27 -8
- package/core/audits/insights/third-parties-insight.js +1 -1
- package/core/audits/layout-shifts.js +1 -1
- package/core/audits/predictive-perf.js +2 -2
- package/core/audits/seo/crawlable-anchors.js +2 -3
- package/core/audits/seo/manual/structured-data.js +1 -1
- package/core/audits/server-response-time.d.ts +0 -5
- package/core/audits/server-response-time.js +12 -26
- package/core/computed/metrics/cumulative-layout-shift.js +2 -2
- package/core/computed/metrics/lantern-metric.js +3 -3
- package/core/computed/metrics/lcp-breakdown.d.ts +10 -5
- package/core/computed/metrics/lcp-breakdown.js +50 -22
- package/core/computed/metrics/time-to-first-byte.js +33 -10
- package/core/computed/metrics/timing-summary.js +3 -2
- package/core/computed/page-dependency-graph.js +1 -1
- package/core/computed/trace-engine-result.js +2 -2
- package/core/config/default-config.js +110 -152
- package/core/config/experimental-config.js +1 -32
- package/core/config/filters.js +6 -9
- package/core/config/lr-desktop-config.js +0 -1
- package/core/config/lr-mobile-config.js +0 -1
- package/core/gather/driver/target-manager.d.ts +1 -1
- package/core/gather/driver.d.ts +1 -1
- package/core/gather/gatherers/anchor-elements.js +8 -24
- package/core/gather/gatherers/image-elements.js +32 -6
- package/core/gather/gatherers/inspector-issues.js +1 -28
- package/core/gather/gatherers/trace-elements.d.ts +2 -11
- package/core/gather/gatherers/trace-elements.js +9 -39
- package/core/gather/navigation-runner.js +0 -3
- package/core/gather/session.d.ts +1 -1
- package/core/lib/asset-saver.d.ts +2 -2
- package/core/lib/asset-saver.js +33 -43
- package/core/lib/bf-cache-strings.js +10 -9
- package/core/lib/deprecations-strings.js +5 -5
- package/core/lib/emulation.d.ts +10 -0
- package/core/lib/emulation.js +21 -6
- package/core/lib/legacy-javascript/legacy-javascript.js +4 -11
- package/core/lib/network-request.d.ts +0 -7
- package/core/lib/network-request.js +0 -16
- package/core/lib/proto-preprocessor.js +10 -25
- package/core/runner.js +1 -8
- package/core/scoring.js +1 -1
- package/dist/report/bundle.esm.js +10 -49
- package/dist/report/flow.js +12 -51
- package/dist/report/standalone.js +11 -50
- package/flow-report/src/i18n/i18n.d.ts +4 -6
- package/package.json +16 -19
- package/readme.md +2 -2
- package/report/assets/styles.css +0 -39
- package/report/renderer/api.js +0 -1
- package/report/renderer/category-renderer.js +6 -0
- package/report/renderer/components.js +1 -1
- package/report/renderer/details-renderer.d.ts +1 -2
- package/report/renderer/details-renderer.js +0 -1
- package/report/renderer/dom.d.ts +0 -13
- package/report/renderer/dom.js +0 -38
- package/report/renderer/performance-category-renderer.d.ts +0 -26
- package/report/renderer/performance-category-renderer.js +10 -142
- package/report/renderer/report-ui-features.d.ts +0 -1
- package/report/renderer/report-ui-features.js +2 -13
- package/report/renderer/report-utils.d.ts +2 -3
- package/report/renderer/report-utils.js +4 -6
- package/report/types/report-renderer.d.ts +0 -6
- package/shared/localization/locales/ar-XB.json +107 -455
- package/shared/localization/locales/ar.json +107 -455
- package/shared/localization/locales/bg.json +96 -444
- package/shared/localization/locales/ca.json +96 -444
- package/shared/localization/locales/cs.json +96 -444
- package/shared/localization/locales/da.json +96 -444
- package/shared/localization/locales/de.json +96 -444
- package/shared/localization/locales/el.json +96 -444
- package/shared/localization/locales/en-GB.json +96 -444
- package/shared/localization/locales/en-US.json +116 -467
- package/shared/localization/locales/en-XA.json +93 -441
- package/shared/localization/locales/en-XL.json +116 -467
- package/shared/localization/locales/es-419.json +96 -444
- package/shared/localization/locales/es.json +96 -444
- package/shared/localization/locales/fi.json +96 -444
- package/shared/localization/locales/fil.json +96 -444
- package/shared/localization/locales/fr.json +96 -444
- package/shared/localization/locales/he.json +118 -466
- package/shared/localization/locales/hi.json +96 -444
- package/shared/localization/locales/hr.json +100 -448
- package/shared/localization/locales/hu.json +96 -444
- package/shared/localization/locales/id.json +96 -444
- package/shared/localization/locales/it.json +96 -444
- package/shared/localization/locales/ja.json +96 -444
- package/shared/localization/locales/ko.json +97 -445
- package/shared/localization/locales/lt.json +96 -444
- package/shared/localization/locales/lv.json +97 -445
- package/shared/localization/locales/nl.json +96 -444
- package/shared/localization/locales/no.json +96 -444
- package/shared/localization/locales/pl.json +96 -444
- package/shared/localization/locales/pt-PT.json +96 -444
- package/shared/localization/locales/pt.json +97 -445
- package/shared/localization/locales/ro.json +97 -445
- package/shared/localization/locales/ru.json +96 -444
- package/shared/localization/locales/sk.json +96 -444
- package/shared/localization/locales/sl.json +96 -444
- package/shared/localization/locales/sr-Latn.json +96 -444
- package/shared/localization/locales/sr.json +96 -444
- package/shared/localization/locales/sv.json +96 -444
- package/shared/localization/locales/ta.json +96 -444
- package/shared/localization/locales/te.json +97 -445
- package/shared/localization/locales/th.json +96 -444
- package/shared/localization/locales/tr.json +96 -444
- package/shared/localization/locales/uk.json +96 -444
- package/shared/localization/locales/vi.json +96 -444
- package/shared/localization/locales/zh-HK.json +96 -444
- package/shared/localization/locales/zh-TW.json +97 -445
- package/shared/localization/locales/zh.json +96 -444
- package/shared/localization/locales.d.ts +2 -0
- package/shared/localization/locales.js +130 -139
- package/shared/tsconfig.json +2 -0
- package/tsconfig-base.json +2 -2
- package/tsconfig.json +1 -4
- package/types/artifacts.d.ts +6 -81
- package/types/audit.d.ts +1 -1
- package/types/lhr/settings.d.ts +1 -1
- package/core/audits/byte-efficiency/duplicated-javascript.d.ts +0 -45
- package/core/audits/byte-efficiency/duplicated-javascript.js +0 -223
- package/core/audits/byte-efficiency/efficient-animated-content.d.ts +0 -22
- package/core/audits/byte-efficiency/efficient-animated-content.js +0 -93
- package/core/audits/byte-efficiency/legacy-javascript.d.ts +0 -28
- package/core/audits/byte-efficiency/legacy-javascript.js +0 -144
- package/core/audits/byte-efficiency/modern-image-formats.d.ts +0 -38
- package/core/audits/byte-efficiency/modern-image-formats.js +0 -187
- package/core/audits/byte-efficiency/offscreen-images.d.ts +0 -63
- package/core/audits/byte-efficiency/offscreen-images.js +0 -240
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +0 -53
- package/core/audits/byte-efficiency/render-blocking-resources.js +0 -312
- package/core/audits/byte-efficiency/uses-long-cache-ttl.d.ts +0 -59
- package/core/audits/byte-efficiency/uses-long-cache-ttl.js +0 -293
- package/core/audits/byte-efficiency/uses-optimized-images.d.ts +0 -33
- package/core/audits/byte-efficiency/uses-optimized-images.js +0 -146
- package/core/audits/byte-efficiency/uses-responsive-images-snapshot.d.ts +0 -16
- package/core/audits/byte-efficiency/uses-responsive-images-snapshot.js +0 -106
- package/core/audits/byte-efficiency/uses-responsive-images.d.ts +0 -44
- package/core/audits/byte-efficiency/uses-responsive-images.js +0 -202
- package/core/audits/byte-efficiency/uses-text-compression.d.ts +0 -14
- package/core/audits/byte-efficiency/uses-text-compression.js +0 -108
- package/core/audits/critical-request-chains.d.ts +0 -44
- package/core/audits/critical-request-chains.js +0 -221
- package/core/audits/dobetterweb/dom-size.d.ts +0 -32
- package/core/audits/dobetterweb/dom-size.js +0 -182
- package/core/audits/dobetterweb/no-document-write.d.ts +0 -16
- package/core/audits/dobetterweb/no-document-write.js +0 -86
- package/core/audits/dobetterweb/uses-http2.d.ts +0 -72
- package/core/audits/dobetterweb/uses-http2.js +0 -276
- package/core/audits/dobetterweb/uses-passive-event-listeners.d.ts +0 -16
- package/core/audits/dobetterweb/uses-passive-event-listeners.js +0 -69
- package/core/audits/font-display.d.ts +0 -32
- package/core/audits/font-display.js +0 -195
- package/core/audits/largest-contentful-paint-element.d.ts +0 -34
- package/core/audits/largest-contentful-paint-element.js +0 -181
- package/core/audits/lcp-lazy-loaded.d.ts +0 -22
- package/core/audits/lcp-lazy-loaded.js +0 -115
- package/core/audits/metrics/first-meaningful-paint.d.ts +0 -12
- package/core/audits/metrics/first-meaningful-paint.js +0 -47
- package/core/audits/preload-fonts.d.ts +0 -25
- package/core/audits/preload-fonts.js +0 -97
- package/core/audits/prioritize-lcp-image.d.ts +0 -74
- package/core/audits/prioritize-lcp-image.js +0 -297
- package/core/audits/seo/font-size.d.ts +0 -24
- package/core/audits/seo/font-size.js +0 -344
- package/core/audits/third-party-facades.d.ts +0 -41
- package/core/audits/third-party-facades.js +0 -234
- package/core/audits/third-party-summary.d.ts +0 -78
- package/core/audits/third-party-summary.js +0 -236
- package/core/audits/uses-rel-preconnect.d.ts +0 -37
- package/core/audits/uses-rel-preconnect.js +0 -286
- package/core/audits/uses-rel-preload.d.ts +0 -57
- package/core/audits/uses-rel-preload.js +0 -263
- package/core/audits/viewport.d.ts +0 -17
- package/core/audits/viewport.js +0 -87
- package/core/audits/work-during-interaction.d.ts +0 -81
- package/core/audits/work-during-interaction.js +0 -287
- package/core/computed/critical-request-chains.d.ts +0 -42
- package/core/computed/critical-request-chains.js +0 -143
- package/core/computed/viewport-meta.d.ts +0 -37
- package/core/computed/viewport-meta.js +0 -71
- package/core/gather/gatherers/cache-contents.d.ts +0 -11
- package/core/gather/gatherers/cache-contents.js +0 -56
- package/core/gather/gatherers/devtools-log-compat.d.ts +0 -13
- package/core/gather/gatherers/devtools-log-compat.js +0 -35
- package/core/gather/gatherers/dobetterweb/domstats.d.ts +0 -10
- package/core/gather/gatherers/dobetterweb/domstats.js +0 -102
- package/core/gather/gatherers/dobetterweb/optimized-images.d.ts +0 -48
- package/core/gather/gatherers/dobetterweb/optimized-images.js +0 -169
- package/core/gather/gatherers/dobetterweb/response-compression.d.ts +0 -23
- package/core/gather/gatherers/dobetterweb/response-compression.js +0 -136
- package/core/gather/gatherers/seo/font-size.d.ts +0 -131
- package/core/gather/gatherers/seo/font-size.js +0 -347
- package/core/gather/gatherers/trace-compat.d.ts +0 -13
- package/core/gather/gatherers/trace-compat.js +0 -35
- package/types/internal/metaviewport-parser.d.ts +0 -13
- package/types/internal/parse-cache-control.d.ts +0 -20
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @fileoverview Audit a page to ensure that resource loaded over its own
|
|
9
|
-
* origin are over the http/2 protocol.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import {Audit} from '../audit.js';
|
|
13
|
-
import {EntityClassification} from '../../computed/entity-classification.js';
|
|
14
|
-
import UrlUtils from '../../lib/url-utils.js';
|
|
15
|
-
import {NetworkRequest} from '../../lib/network-request.js';
|
|
16
|
-
import {NetworkRecords} from '../../computed/network-records.js';
|
|
17
|
-
import {LoadSimulator} from '../../computed/load-simulator.js';
|
|
18
|
-
import {LanternLargestContentfulPaint} from '../../computed/metrics/lantern-largest-contentful-paint.js';
|
|
19
|
-
import {LanternFirstContentfulPaint} from '../../computed/metrics/lantern-first-contentful-paint.js';
|
|
20
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
21
|
-
|
|
22
|
-
const UIStrings = {
|
|
23
|
-
/** Imperative title of a Lighthouse audit that tells the user to enable HTTP/2. This is displayed in a list of audit titles that Lighthouse generates. */
|
|
24
|
-
title: 'Use HTTP/2',
|
|
25
|
-
/** Description of a Lighthouse audit that tells the user why they should use HTTP/2. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
26
|
-
description: 'HTTP/2 offers many benefits over HTTP/1.1, including binary headers and ' +
|
|
27
|
-
'multiplexing. [Learn more about HTTP/2](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',
|
|
28
|
-
/** [ICU Syntax] Label identifying the number of network requests that were not served with HTTP/2. */
|
|
29
|
-
displayValue: `{itemCount, plural,
|
|
30
|
-
=1 {1 request not served via HTTP/2}
|
|
31
|
-
other {# requests not served via HTTP/2}
|
|
32
|
-
}`,
|
|
33
|
-
/** Label for a column in a data table; entries in the column will be the HTTP Protocol used to make a network request. */
|
|
34
|
-
columnProtocol: 'Protocol',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
38
|
-
|
|
39
|
-
/** @type {Set<LH.Artifacts.NetworkRequest['resourceType']>} */
|
|
40
|
-
const STATIC_RESOURCE_TYPES = new Set([
|
|
41
|
-
NetworkRequest.TYPES.Document,
|
|
42
|
-
NetworkRequest.TYPES.Font,
|
|
43
|
-
NetworkRequest.TYPES.Image,
|
|
44
|
-
NetworkRequest.TYPES.Stylesheet,
|
|
45
|
-
NetworkRequest.TYPES.Script,
|
|
46
|
-
NetworkRequest.TYPES.Media,
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
class UsesHTTP2Audit extends Audit {
|
|
50
|
-
/**
|
|
51
|
-
* @return {LH.Audit.Meta}
|
|
52
|
-
*/
|
|
53
|
-
static get meta() {
|
|
54
|
-
return {
|
|
55
|
-
id: 'uses-http2',
|
|
56
|
-
title: str_(UIStrings.title),
|
|
57
|
-
description: str_(UIStrings.description),
|
|
58
|
-
scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
|
|
59
|
-
guidanceLevel: 3,
|
|
60
|
-
supportedModes: ['timespan', 'navigation'],
|
|
61
|
-
requiredArtifacts: ['URL', 'DevtoolsLog', 'Trace', 'GatherContext', 'SourceMaps'],
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Computes the estimated effect of all results being converted to http/2 on the provided graph.
|
|
67
|
-
*
|
|
68
|
-
* @param {Array<{url: string}>} results
|
|
69
|
-
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
70
|
-
* @param {LH.Gatherer.Simulation.Simulator} simulator
|
|
71
|
-
* @param {{label?: string}=} options
|
|
72
|
-
* @return {{savings: number, simulationBefore: LH.Gatherer.Simulation.Result, simulationAfter: LH.Gatherer.Simulation.Result}}
|
|
73
|
-
*/
|
|
74
|
-
static computeWasteWithGraph(results, graph, simulator, options) {
|
|
75
|
-
options = Object.assign({label: ''}, options);
|
|
76
|
-
const beforeLabel = `${this.meta.id}-${options.label}-before`;
|
|
77
|
-
const afterLabel = `${this.meta.id}-${options.label}-after`;
|
|
78
|
-
|
|
79
|
-
const urlsToChange = new Set(results.map(result => result.url));
|
|
80
|
-
const simulationBefore = simulator.simulate(graph, {label: beforeLabel});
|
|
81
|
-
|
|
82
|
-
// Update all the protocols to reflect implementing our recommendations
|
|
83
|
-
/** @type {Map<string, string>} */
|
|
84
|
-
const originalProtocols = new Map();
|
|
85
|
-
graph.traverse(node => {
|
|
86
|
-
if (node.type !== 'network') return;
|
|
87
|
-
if (!urlsToChange.has(node.request.url)) return;
|
|
88
|
-
|
|
89
|
-
originalProtocols.set(node.request.requestId, node.request.protocol);
|
|
90
|
-
node.request.protocol = 'h2';
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const simulationAfter = simulator.simulate(graph, {label: afterLabel});
|
|
94
|
-
|
|
95
|
-
// Restore the original protocol after we've done our simulation
|
|
96
|
-
graph.traverse(node => {
|
|
97
|
-
if (node.type !== 'network') return;
|
|
98
|
-
const originalProtocol = originalProtocols.get(node.request.requestId);
|
|
99
|
-
if (originalProtocol === undefined) return;
|
|
100
|
-
node.request.protocol = originalProtocol;
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
// Round waste to nearest 10ms
|
|
107
|
-
savings: Math.round(Math.max(savings, 0) / 10) * 10,
|
|
108
|
-
simulationBefore,
|
|
109
|
-
simulationAfter,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Determines whether a network request is a "static resource" that would benefit from H2 multiplexing.
|
|
115
|
-
* XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse
|
|
116
|
-
* for the same origin at the exact same time.
|
|
117
|
-
*
|
|
118
|
-
* @param {LH.Artifacts.NetworkRequest} networkRequest
|
|
119
|
-
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
120
|
-
* @return {boolean}
|
|
121
|
-
*/
|
|
122
|
-
static isMultiplexableStaticAsset(networkRequest, classifiedEntities) {
|
|
123
|
-
if (!STATIC_RESOURCE_TYPES.has(networkRequest.resourceType)) return false;
|
|
124
|
-
|
|
125
|
-
// Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.
|
|
126
|
-
// They can masquerade as static types though (gifs, documents, etc)
|
|
127
|
-
if (networkRequest.resourceSize < 100) {
|
|
128
|
-
const entity = classifiedEntities.entityByUrl.get(networkRequest.url);
|
|
129
|
-
if (entity) {
|
|
130
|
-
// Third-party assets are multiplexable in their first-party context.
|
|
131
|
-
if (classifiedEntities.firstParty?.name === entity.name) return true;
|
|
132
|
-
// Skip recognizable third-parties' requests.
|
|
133
|
-
if (!entity.isUnrecognized) return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Determine the set of resources that aren't HTTP/2 but should be.
|
|
142
|
-
* We're a little conservative about what we surface for a few reasons:
|
|
143
|
-
*
|
|
144
|
-
* - The simulator approximation of HTTP/2 is a little more generous than reality.
|
|
145
|
-
* - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss.**
|
|
146
|
-
* - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).
|
|
147
|
-
*
|
|
148
|
-
* Therefore, we only surface requests that were...
|
|
149
|
-
*
|
|
150
|
-
* - Served over HTTP/1.1 or earlier
|
|
151
|
-
* - Served over an origin that serves at least 6 static asset requests
|
|
152
|
-
* (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)
|
|
153
|
-
* - Not served on localhost (h2 is a pain to deal with locally & and CI)
|
|
154
|
-
*
|
|
155
|
-
* ** = https://news.ycombinator.com/item?id=19086639
|
|
156
|
-
* https://www.twilio.com/blog/2017/10/http2-issues.html
|
|
157
|
-
* https://www.cachefly.com/http-2-is-not-a-magic-bullet/
|
|
158
|
-
*
|
|
159
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
160
|
-
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
161
|
-
* @return {Array<{url: string, protocol: string}>}
|
|
162
|
-
*/
|
|
163
|
-
static determineNonHttp2Resources(networkRecords, classifiedEntities) {
|
|
164
|
-
/** @type {Array<{url: string, protocol: string}>} */
|
|
165
|
-
const nonHttp2Resources = [];
|
|
166
|
-
|
|
167
|
-
/** @type {Set<string>} */
|
|
168
|
-
const seenURLs = new Set();
|
|
169
|
-
/** @type {Map<string, Array<LH.Artifacts.NetworkRequest>>} */
|
|
170
|
-
const groupedByOrigin = new Map();
|
|
171
|
-
for (const record of networkRecords) {
|
|
172
|
-
if (!UsesHTTP2Audit.isMultiplexableStaticAsset(record, classifiedEntities)) continue;
|
|
173
|
-
if (UrlUtils.isLikeLocalhost(record.parsedURL.host)) continue;
|
|
174
|
-
const existing = groupedByOrigin.get(record.parsedURL.securityOrigin) || [];
|
|
175
|
-
existing.push(record);
|
|
176
|
-
groupedByOrigin.set(record.parsedURL.securityOrigin, existing);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
for (const record of networkRecords) {
|
|
180
|
-
// Skip duplicates.
|
|
181
|
-
if (seenURLs.has(record.url)) continue;
|
|
182
|
-
// Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.
|
|
183
|
-
// These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).
|
|
184
|
-
if (record.fetchedViaServiceWorker) continue;
|
|
185
|
-
// Test the protocol to see if it was http/1.1.
|
|
186
|
-
const isOldHttp = /HTTP\/[01][.\d]?/i.test(record.protocol);
|
|
187
|
-
if (!isOldHttp) continue;
|
|
188
|
-
// Check if the origin has enough requests to bother flagging.
|
|
189
|
-
const group = groupedByOrigin.get(record.parsedURL.securityOrigin) || [];
|
|
190
|
-
if (group.length < 6) continue;
|
|
191
|
-
|
|
192
|
-
seenURLs.add(record.url);
|
|
193
|
-
nonHttp2Resources.push({protocol: record.protocol, url: record.url});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return nonHttp2Resources;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @param {LH.Artifacts} artifacts
|
|
201
|
-
* @param {LH.Audit.Context} context
|
|
202
|
-
* @return {Promise<LH.Audit.Product>}
|
|
203
|
-
*/
|
|
204
|
-
static async audit(artifacts, context) {
|
|
205
|
-
const devtoolsLog = artifacts.DevtoolsLog;
|
|
206
|
-
const URL = artifacts.URL;
|
|
207
|
-
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
208
|
-
const classifiedEntities = await EntityClassification.request({URL, devtoolsLog}, context);
|
|
209
|
-
const resources = UsesHTTP2Audit.determineNonHttp2Resources(networkRecords, classifiedEntities);
|
|
210
|
-
|
|
211
|
-
let displayValue;
|
|
212
|
-
if (resources.length > 0) {
|
|
213
|
-
displayValue = str_(UIStrings.displayValue, {itemCount: resources.length});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// TODO: Compute actual savings for timespan mode.
|
|
217
|
-
if (artifacts.GatherContext.gatherMode === 'timespan') {
|
|
218
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
219
|
-
const headings = [
|
|
220
|
-
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
221
|
-
{key: 'protocol', valueType: 'text', label: str_(UIStrings.columnProtocol)},
|
|
222
|
-
];
|
|
223
|
-
|
|
224
|
-
const details = Audit.makeTableDetails(headings, resources);
|
|
225
|
-
|
|
226
|
-
return {
|
|
227
|
-
displayValue,
|
|
228
|
-
score: resources.length ? 0 : 1,
|
|
229
|
-
details,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const settings = context?.settings || {};
|
|
234
|
-
const simulatorOptions = {
|
|
235
|
-
devtoolsLog,
|
|
236
|
-
settings,
|
|
237
|
-
};
|
|
238
|
-
const simulator = await LoadSimulator.request(simulatorOptions, context);
|
|
239
|
-
const metricComputationInput = Audit.makeMetricComputationDataInput(artifacts, context);
|
|
240
|
-
|
|
241
|
-
const {
|
|
242
|
-
pessimisticGraph: fcpGraph,
|
|
243
|
-
} = await LanternFirstContentfulPaint.request(metricComputationInput, context);
|
|
244
|
-
const {
|
|
245
|
-
pessimisticGraph: lcpGraph,
|
|
246
|
-
} = await LanternLargestContentfulPaint.request(metricComputationInput, context);
|
|
247
|
-
|
|
248
|
-
const wasteFcp =
|
|
249
|
-
UsesHTTP2Audit.computeWasteWithGraph(resources,
|
|
250
|
-
fcpGraph, simulator, {label: 'fcp'});
|
|
251
|
-
const wasteLcp =
|
|
252
|
-
UsesHTTP2Audit.computeWasteWithGraph(resources,
|
|
253
|
-
lcpGraph, simulator, {label: 'lcp'});
|
|
254
|
-
|
|
255
|
-
/** @type {LH.Audit.Details.Opportunity['headings']} */
|
|
256
|
-
const headings = [
|
|
257
|
-
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
258
|
-
{key: 'protocol', valueType: 'text', label: str_(UIStrings.columnProtocol)},
|
|
259
|
-
];
|
|
260
|
-
|
|
261
|
-
const details = Audit.makeOpportunityDetails(headings, resources,
|
|
262
|
-
{overallSavingsMs: wasteLcp.savings});
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
displayValue,
|
|
266
|
-
numericValue: wasteLcp.savings,
|
|
267
|
-
numericUnit: 'millisecond',
|
|
268
|
-
score: resources.length ? 0 : 1,
|
|
269
|
-
details,
|
|
270
|
-
metricSavings: {LCP: wasteLcp.savings, FCP: wasteFcp.savings},
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export default UsesHTTP2Audit;
|
|
276
|
-
export {UIStrings};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export default PassiveEventsAudit;
|
|
2
|
-
declare class PassiveEventsAudit extends ViolationAudit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {LH.Artifacts} artifacts
|
|
5
|
-
* @param {LH.Audit.Context} context
|
|
6
|
-
* @return {Promise<LH.Audit.Product>}
|
|
7
|
-
*/
|
|
8
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
9
|
-
}
|
|
10
|
-
export namespace UIStrings {
|
|
11
|
-
let title: string;
|
|
12
|
-
let failureTitle: string;
|
|
13
|
-
let description: string;
|
|
14
|
-
}
|
|
15
|
-
import ViolationAudit from '../violation-audit.js';
|
|
16
|
-
//# sourceMappingURL=uses-passive-event-listeners.d.ts.map
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @fileoverview Audit a page to see if it is using passive event listeners on
|
|
9
|
-
* scroll-blocking touch and wheel event listeners.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import ViolationAudit from '../violation-audit.js';
|
|
14
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
15
|
-
|
|
16
|
-
const UIStrings = {
|
|
17
|
-
/** Title of a Lighthouse audit that provides detail on the page's use of passive event listeners used to improve the scrolling performance of the page. This descriptive title is shown to users when the page does use passive listeners. */
|
|
18
|
-
title: 'Uses passive listeners to improve scrolling performance',
|
|
19
|
-
/** Title of a Lighthouse audit that provides detail on the page's use of passive event listeners used to improve the scrolling performance of the page. This descriptive title is shown to users when the page does not use passive listeners. */
|
|
20
|
-
failureTitle: 'Does not use passive listeners to improve scrolling performance',
|
|
21
|
-
/** Description of a Lighthouse audit that tells the user why they should use passive event listeners on the page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
22
|
-
description: 'Consider marking your touch and wheel event listeners as `passive` ' +
|
|
23
|
-
'to improve your page\'s scroll performance. ' +
|
|
24
|
-
'[Learn more about adopting passive event listeners](https://developer.chrome.com/docs/lighthouse/best-practices/uses-passive-event-listeners/).',
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
28
|
-
|
|
29
|
-
class PassiveEventsAudit extends ViolationAudit {
|
|
30
|
-
/**
|
|
31
|
-
* @return {LH.Audit.Meta}
|
|
32
|
-
*/
|
|
33
|
-
static get meta() {
|
|
34
|
-
return {
|
|
35
|
-
id: 'uses-passive-event-listeners',
|
|
36
|
-
title: str_(UIStrings.title),
|
|
37
|
-
failureTitle: str_(UIStrings.failureTitle),
|
|
38
|
-
description: str_(UIStrings.description),
|
|
39
|
-
guidanceLevel: 3,
|
|
40
|
-
requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'Scripts'],
|
|
41
|
-
scoreDisplayMode: ViolationAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {LH.Artifacts} artifacts
|
|
47
|
-
* @param {LH.Audit.Context} context
|
|
48
|
-
* @return {Promise<LH.Audit.Product>}
|
|
49
|
-
*/
|
|
50
|
-
static async audit(artifacts, context) {
|
|
51
|
-
const results =
|
|
52
|
-
await ViolationAudit.getViolationResults(artifacts, context, /passive event listener/);
|
|
53
|
-
|
|
54
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
55
|
-
const headings = [
|
|
56
|
-
{key: 'source', valueType: 'source-location', label: str_(i18n.UIStrings.columnSource)},
|
|
57
|
-
];
|
|
58
|
-
// TODO(bckenny): see TODO in geolocation-on-start
|
|
59
|
-
const details = ViolationAudit.makeTableDetails(headings, results);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
score: Number(results.length === 0),
|
|
63
|
-
details,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export default PassiveEventsAudit;
|
|
69
|
-
export {UIStrings};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export default FontDisplay;
|
|
2
|
-
declare class FontDisplay extends Audit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {LH.Artifacts} artifacts
|
|
5
|
-
* @param {RegExp} passingFontDisplayRegex
|
|
6
|
-
* @return {{passingURLs: Set<string>, failingURLs: Set<string>}}
|
|
7
|
-
*/
|
|
8
|
-
static findFontDisplayDeclarations(artifacts: LH.Artifacts, passingFontDisplayRegex: RegExp): {
|
|
9
|
-
passingURLs: Set<string>;
|
|
10
|
-
failingURLs: Set<string>;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Some pages load many fonts we can't check, so dedupe on origin.
|
|
14
|
-
* @param {Array<string>} warningUrls
|
|
15
|
-
* @return {Array<LH.IcuMessage>}
|
|
16
|
-
*/
|
|
17
|
-
static getWarningsForFontUrls(warningUrls: Array<string>): Array<LH.IcuMessage>;
|
|
18
|
-
/**
|
|
19
|
-
* @param {LH.Artifacts} artifacts
|
|
20
|
-
* @param {LH.Audit.Context} context
|
|
21
|
-
* @return {Promise<LH.Audit.Product>}
|
|
22
|
-
*/
|
|
23
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
24
|
-
}
|
|
25
|
-
export namespace UIStrings {
|
|
26
|
-
let title: string;
|
|
27
|
-
let failureTitle: string;
|
|
28
|
-
let description: string;
|
|
29
|
-
let undeclaredFontOriginWarning: string;
|
|
30
|
-
}
|
|
31
|
-
import { Audit } from './audit.js';
|
|
32
|
-
//# sourceMappingURL=font-display.d.ts.map
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2017 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {Audit} from './audit.js';
|
|
8
|
-
import UrlUtils from '../lib/url-utils.js';
|
|
9
|
-
import * as i18n from '../lib/i18n/i18n.js';
|
|
10
|
-
import {Sentry} from '../lib/sentry.js';
|
|
11
|
-
import {NetworkRecords} from '../computed/network-records.js';
|
|
12
|
-
|
|
13
|
-
const PASSING_FONT_DISPLAY_REGEX = /^(block|fallback|optional|swap)$/;
|
|
14
|
-
const CSS_URL_REGEX = /url\((.*?)\)/;
|
|
15
|
-
const CSS_URL_GLOBAL_REGEX = new RegExp(CSS_URL_REGEX, 'g');
|
|
16
|
-
|
|
17
|
-
const UIStrings = {
|
|
18
|
-
/** Title of a diagnostic audit that provides detail on if all the text on a webpage was visible while the page was loading its webfonts. This descriptive title is shown to users when the amount is acceptable and no user action is required. */
|
|
19
|
-
title: 'All text remains visible during webfont loads',
|
|
20
|
-
/** Title of a diagnostic audit that provides detail on the load of the page's webfonts. Often the text is invisible for seconds before the webfont resource is loaded. This imperative title is shown to users when there is a significant amount of execution time that could be reduced. */
|
|
21
|
-
failureTitle: 'Ensure text remains visible during webfont load',
|
|
22
|
-
/** Description of a Lighthouse audit that tells the user *why* they should use the font-display CSS feature. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
23
|
-
description:
|
|
24
|
-
'Leverage the `font-display` CSS feature to ensure text is user-visible while ' +
|
|
25
|
-
'webfonts are loading. ' +
|
|
26
|
-
'[Learn more about `font-display`](https://developer.chrome.com/docs/lighthouse/performance/font-display/).',
|
|
27
|
-
/**
|
|
28
|
-
* @description [ICU Syntax] A warning message that is shown when Lighthouse couldn't automatically check some of the page's fonts, telling the user that they will need to manually check the fonts coming from a certain URL origin.
|
|
29
|
-
* @example {https://font.cdn.com/} fontOrigin
|
|
30
|
-
*/
|
|
31
|
-
undeclaredFontOriginWarning:
|
|
32
|
-
'{fontCountForOrigin, plural, ' +
|
|
33
|
-
// eslint-disable-next-line max-len
|
|
34
|
-
'=1 {Lighthouse was unable to automatically check the `font-display` value for the origin {fontOrigin}.} ' +
|
|
35
|
-
// eslint-disable-next-line max-len
|
|
36
|
-
'other {Lighthouse was unable to automatically check the `font-display` values for the origin {fontOrigin}.}}',
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
40
|
-
|
|
41
|
-
class FontDisplay extends Audit {
|
|
42
|
-
/**
|
|
43
|
-
* @return {LH.Audit.Meta}
|
|
44
|
-
*/
|
|
45
|
-
static get meta() {
|
|
46
|
-
return {
|
|
47
|
-
id: 'font-display',
|
|
48
|
-
title: str_(UIStrings.title),
|
|
49
|
-
failureTitle: str_(UIStrings.failureTitle),
|
|
50
|
-
description: str_(UIStrings.description),
|
|
51
|
-
supportedModes: ['navigation'],
|
|
52
|
-
guidanceLevel: 3,
|
|
53
|
-
requiredArtifacts: ['DevtoolsLog', 'Stylesheets', 'URL'],
|
|
54
|
-
scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @param {LH.Artifacts} artifacts
|
|
60
|
-
* @param {RegExp} passingFontDisplayRegex
|
|
61
|
-
* @return {{passingURLs: Set<string>, failingURLs: Set<string>}}
|
|
62
|
-
*/
|
|
63
|
-
static findFontDisplayDeclarations(artifacts, passingFontDisplayRegex) {
|
|
64
|
-
/** @type {Set<string>} */
|
|
65
|
-
const passingURLs = new Set();
|
|
66
|
-
/** @type {Set<string>} */
|
|
67
|
-
const failingURLs = new Set();
|
|
68
|
-
|
|
69
|
-
// Go through all the stylesheets to find all @font-face declarations
|
|
70
|
-
for (const stylesheet of artifacts.Stylesheets) {
|
|
71
|
-
// Eliminate newlines so we can more easily scan through with a regex
|
|
72
|
-
const newlinesStripped = stylesheet.content.replace(/(\r|\n)+/g, ' ');
|
|
73
|
-
// Find the @font-faces
|
|
74
|
-
const fontFaceDeclarations = newlinesStripped.match(/@font-face\s*{(.*?)}/g) || [];
|
|
75
|
-
// Go through all the @font-face declarations to find a declared `font-display: ` property
|
|
76
|
-
for (const declaration of fontFaceDeclarations) {
|
|
77
|
-
// We'll try to find the URL it's referencing.
|
|
78
|
-
const rawFontURLs = declaration.match(CSS_URL_GLOBAL_REGEX);
|
|
79
|
-
// If no URLs, we can't really do anything; bail
|
|
80
|
-
if (!rawFontURLs) continue;
|
|
81
|
-
// Find the font-display value by matching a single token, optionally surrounded by whitespace,
|
|
82
|
-
// followed either by a semicolon or the end of a block.
|
|
83
|
-
const fontDisplayMatch = declaration.match(/font-display\s*:\s*(\w+)\s*(;|\})/);
|
|
84
|
-
const rawFontDisplay = fontDisplayMatch?.[1] || '';
|
|
85
|
-
const hasPassingFontDisplay = passingFontDisplayRegex.test(rawFontDisplay);
|
|
86
|
-
const targetURLSet = hasPassingFontDisplay ? passingURLs : failingURLs;
|
|
87
|
-
|
|
88
|
-
// Finally convert the raw font URLs to the absolute URLs and add them to the set.
|
|
89
|
-
const relativeURLs = rawFontURLs
|
|
90
|
-
// @ts-expect-error - guaranteed to match from previous regex, pull URL group out
|
|
91
|
-
.map(s => s.match(CSS_URL_REGEX)[1].trim())
|
|
92
|
-
.map(s => {
|
|
93
|
-
// remove any quotes surrounding the URL
|
|
94
|
-
if (/^('|").*\1$/.test(s)) {
|
|
95
|
-
return s.substr(1, s.length - 2);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return s;
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Convert the relative CSS URL to an absolute URL and add it to the target set.
|
|
102
|
-
for (const relativeURL of relativeURLs) {
|
|
103
|
-
try {
|
|
104
|
-
const relativeRoot = UrlUtils.isValid(stylesheet.header.sourceURL) ?
|
|
105
|
-
stylesheet.header.sourceURL : artifacts.URL.finalDisplayedUrl;
|
|
106
|
-
const absoluteURL = new URL(relativeURL, relativeRoot);
|
|
107
|
-
targetURLSet.add(absoluteURL.href);
|
|
108
|
-
} catch (err) {
|
|
109
|
-
Sentry.captureException(err, {tags: {audit: this.meta.id}});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return {passingURLs, failingURLs};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Some pages load many fonts we can't check, so dedupe on origin.
|
|
120
|
-
* @param {Array<string>} warningUrls
|
|
121
|
-
* @return {Array<LH.IcuMessage>}
|
|
122
|
-
*/
|
|
123
|
-
static getWarningsForFontUrls(warningUrls) {
|
|
124
|
-
/** @type {Map<string, number>} */
|
|
125
|
-
const warningCountByOrigin = new Map();
|
|
126
|
-
for (const warningUrl of warningUrls) {
|
|
127
|
-
const origin = UrlUtils.getOrigin(warningUrl);
|
|
128
|
-
if (!origin) continue;
|
|
129
|
-
|
|
130
|
-
const count = warningCountByOrigin.get(origin) || 0;
|
|
131
|
-
warningCountByOrigin.set(origin, count + 1);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const warnings = [...warningCountByOrigin].map(([fontOrigin, fontCountForOrigin]) => {
|
|
135
|
-
return str_(UIStrings.undeclaredFontOriginWarning, {fontCountForOrigin, fontOrigin});
|
|
136
|
-
});
|
|
137
|
-
return warnings;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* @param {LH.Artifacts} artifacts
|
|
142
|
-
* @param {LH.Audit.Context} context
|
|
143
|
-
* @return {Promise<LH.Audit.Product>}
|
|
144
|
-
*/
|
|
145
|
-
static async audit(artifacts, context) {
|
|
146
|
-
const devtoolsLogs = artifacts.DevtoolsLog;
|
|
147
|
-
const networkRecords = await NetworkRecords.request(devtoolsLogs, context);
|
|
148
|
-
const {passingURLs, failingURLs} =
|
|
149
|
-
FontDisplay.findFontDisplayDeclarations(artifacts, PASSING_FONT_DISPLAY_REGEX);
|
|
150
|
-
/** @type {Array<string>} */
|
|
151
|
-
const warningURLs = [];
|
|
152
|
-
|
|
153
|
-
const results = networkRecords
|
|
154
|
-
// Find all fonts...
|
|
155
|
-
.filter(record => record.resourceType === 'Font')
|
|
156
|
-
// ...and that aren't data URLs, the blocking concern doesn't really apply
|
|
157
|
-
.filter(record => !/^data:/.test(record.url))
|
|
158
|
-
.filter(record => !/^blob:/.test(record.url))
|
|
159
|
-
// ...that have a failing font-display value
|
|
160
|
-
.filter(record => {
|
|
161
|
-
// Failing URLs should be considered.
|
|
162
|
-
if (failingURLs.has(record.url)) return true;
|
|
163
|
-
// Everything else shouldn't be, but we should warn if we don't recognize the URL at all.
|
|
164
|
-
if (!passingURLs.has(record.url)) warningURLs.push(record.url);
|
|
165
|
-
return false;
|
|
166
|
-
})
|
|
167
|
-
.map(record => {
|
|
168
|
-
// In reality the end time should be calculated with paint time included
|
|
169
|
-
// all browsers wait 3000ms to block text so we make sure 3000 is our max wasted time
|
|
170
|
-
const wastedMs = Math.min(record.networkEndTime - record.networkRequestTime, 3000);
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
url: record.url,
|
|
174
|
-
wastedMs,
|
|
175
|
-
};
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
179
|
-
const headings = [
|
|
180
|
-
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
181
|
-
{key: 'wastedMs', valueType: 'ms', label: str_(i18n.UIStrings.columnWastedMs)},
|
|
182
|
-
];
|
|
183
|
-
|
|
184
|
-
const details = Audit.makeTableDetails(headings, results);
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
score: Number(results.length === 0),
|
|
188
|
-
details,
|
|
189
|
-
warnings: FontDisplay.getWarningsForFontUrls(warningURLs),
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export default FontDisplay;
|
|
195
|
-
export {UIStrings};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export default LargestContentfulPaintElement;
|
|
2
|
-
declare class LargestContentfulPaintElement extends Audit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {LH.Artifacts} artifacts
|
|
5
|
-
* @return {LH.Audit.Details.Table|undefined}
|
|
6
|
-
*/
|
|
7
|
-
static makeElementTable(artifacts: LH.Artifacts): LH.Audit.Details.Table | undefined;
|
|
8
|
-
/**
|
|
9
|
-
* @param {number} metricLcp
|
|
10
|
-
* @param {LH.Artifacts.MetricComputationDataInput} metricComputationData
|
|
11
|
-
* @param {LH.Audit.Context} context
|
|
12
|
-
* @return {Promise<LH.Audit.Details.Table>}
|
|
13
|
-
*/
|
|
14
|
-
static makePhaseTable(metricLcp: number, metricComputationData: LH.Artifacts.MetricComputationDataInput, context: LH.Audit.Context): Promise<LH.Audit.Details.Table>;
|
|
15
|
-
/**
|
|
16
|
-
* @param {LH.Artifacts} artifacts
|
|
17
|
-
* @param {LH.Audit.Context} context
|
|
18
|
-
* @return {Promise<LH.Audit.Product>}
|
|
19
|
-
*/
|
|
20
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
21
|
-
}
|
|
22
|
-
export namespace UIStrings {
|
|
23
|
-
let title: string;
|
|
24
|
-
let description: string;
|
|
25
|
-
let columnPhase: string;
|
|
26
|
-
let columnPercentOfLCP: string;
|
|
27
|
-
let columnTiming: string;
|
|
28
|
-
let itemTTFB: string;
|
|
29
|
-
let itemLoadDelay: string;
|
|
30
|
-
let itemLoadTime: string;
|
|
31
|
-
let itemRenderDelay: string;
|
|
32
|
-
}
|
|
33
|
-
import { Audit } from './audit.js';
|
|
34
|
-
//# sourceMappingURL=largest-contentful-paint-element.d.ts.map
|