lighthouse 12.8.2-dev.20251007 → 12.8.2-dev.20251008
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/core/audits/insights/font-display-insight.js +3 -1
- package/core/config/default-config.js +0 -12
- package/package.json +1 -2
- package/shared/localization/locales/ar-XB.json +0 -27
- package/shared/localization/locales/ar.json +0 -27
- package/shared/localization/locales/bg.json +0 -27
- package/shared/localization/locales/ca.json +0 -27
- package/shared/localization/locales/cs.json +0 -27
- package/shared/localization/locales/da.json +0 -27
- package/shared/localization/locales/de.json +0 -27
- package/shared/localization/locales/el.json +0 -27
- package/shared/localization/locales/en-GB.json +0 -27
- package/shared/localization/locales/en-US.json +0 -27
- package/shared/localization/locales/en-XA.json +0 -27
- package/shared/localization/locales/en-XL.json +0 -27
- package/shared/localization/locales/es-419.json +0 -27
- package/shared/localization/locales/es.json +0 -27
- package/shared/localization/locales/fi.json +0 -27
- package/shared/localization/locales/fil.json +0 -27
- package/shared/localization/locales/fr.json +0 -27
- package/shared/localization/locales/he.json +0 -27
- package/shared/localization/locales/hi.json +0 -27
- package/shared/localization/locales/hr.json +0 -27
- package/shared/localization/locales/hu.json +0 -27
- package/shared/localization/locales/id.json +0 -27
- package/shared/localization/locales/it.json +0 -27
- package/shared/localization/locales/ja.json +0 -27
- package/shared/localization/locales/ko.json +0 -27
- package/shared/localization/locales/lt.json +0 -27
- package/shared/localization/locales/lv.json +0 -27
- package/shared/localization/locales/nl.json +0 -27
- package/shared/localization/locales/no.json +0 -27
- package/shared/localization/locales/pl.json +0 -27
- package/shared/localization/locales/pt-PT.json +0 -27
- package/shared/localization/locales/pt.json +0 -27
- package/shared/localization/locales/ro.json +0 -27
- package/shared/localization/locales/ru.json +0 -27
- package/shared/localization/locales/sk.json +0 -27
- package/shared/localization/locales/sl.json +0 -27
- package/shared/localization/locales/sr-Latn.json +0 -27
- package/shared/localization/locales/sr.json +0 -27
- package/shared/localization/locales/sv.json +0 -27
- package/shared/localization/locales/ta.json +0 -27
- package/shared/localization/locales/te.json +0 -27
- package/shared/localization/locales/th.json +0 -27
- package/shared/localization/locales/tr.json +0 -27
- package/shared/localization/locales/uk.json +0 -27
- package/shared/localization/locales/vi.json +0 -27
- package/shared/localization/locales/zh-HK.json +0 -27
- package/shared/localization/locales/zh-TW.json +0 -27
- package/shared/localization/locales/zh.json +0 -27
- package/tsconfig.json +0 -3
- package/types/artifacts.d.ts +0 -37
- package/core/audits/byte-efficiency/offscreen-images.d.ts +0 -63
- package/core/audits/byte-efficiency/offscreen-images.js +0 -240
- 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-passive-event-listeners.d.ts +0 -16
- package/core/audits/dobetterweb/uses-passive-event-listeners.js +0 -69
- package/core/audits/metrics/first-meaningful-paint.d.ts +0 -12
- package/core/audits/metrics/first-meaningful-paint.js +0 -47
- package/core/gather/gatherers/cache-contents.d.ts +0 -11
- package/core/gather/gatherers/cache-contents.js +0 -56
- 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/types/internal/parse-cache-control.d.ts +0 -20
package/types/artifacts.d.ts
CHANGED
|
@@ -107,8 +107,6 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
107
107
|
AnchorElements: Artifacts.AnchorElement[];
|
|
108
108
|
/** Errors when attempting to use the back/forward cache. */
|
|
109
109
|
BFCacheFailures: Artifacts.BFCacheFailure[];
|
|
110
|
-
/** Array of all URLs cached in CacheStorage. */
|
|
111
|
-
CacheContents: string[];
|
|
112
110
|
/** CSS coverage information for styles used by page's final state. */
|
|
113
111
|
CSSUsage: Crdp.CSS.RuleUsage[];
|
|
114
112
|
/** The log of devtools protocol activity if there was a page load error and Chrome navigated to a `chrome-error://` page. */
|
|
@@ -116,8 +114,6 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
116
114
|
/** Information on the document's doctype(or null if not present), specifically the name, publicId, and systemId.
|
|
117
115
|
All properties default to an empty string if not present */
|
|
118
116
|
Doctype: Artifacts.Doctype | null;
|
|
119
|
-
/** Information on the size of all DOM nodes in the page and the most extreme members. */
|
|
120
|
-
DOMStats: Artifacts.DOMStats;
|
|
121
117
|
/** All the iframe elements in the page. */
|
|
122
118
|
IFrameElements: Artifacts.IFrameElement[];
|
|
123
119
|
/** All the input elements, including associated form and label elements. */
|
|
@@ -131,10 +127,6 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
131
127
|
JsUsage: Record<string, Omit<Crdp.Profiler.ScriptCoverage, 'url'>>;
|
|
132
128
|
/** The user agent string that Lighthouse used to load the page. Set to the empty string if unknown. */
|
|
133
129
|
NetworkUserAgent: string;
|
|
134
|
-
/** Size and compression opportunity information for all the images in the page. */
|
|
135
|
-
OptimizedImages: Array<Artifacts.OptimizedImage | Artifacts.OptimizedImageError>;
|
|
136
|
-
/** Size info of all network records sent without compression and their size after gzipping. */
|
|
137
|
-
ResponseCompression: {requestId: string, url: string, mimeType: string, transferSize: number, resourceSize: number, gzipSize?: number}[];
|
|
138
130
|
/** Information on fetching and the content of the /robots.txt file. */
|
|
139
131
|
RobotsTxt: {status: number|null, content: string|null, errorMessage?: string};
|
|
140
132
|
/** Source maps of scripts executed in the page. */
|
|
@@ -224,13 +216,6 @@ declare module Artifacts {
|
|
|
224
216
|
documentCompatMode: string;
|
|
225
217
|
}
|
|
226
218
|
|
|
227
|
-
interface DOMStats {
|
|
228
|
-
/** The total number of elements found within the page's body. */
|
|
229
|
-
totalBodyElements: number;
|
|
230
|
-
width: NodeDetails & {max: number;};
|
|
231
|
-
depth: NodeDetails & {max: number;};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
219
|
interface IFrameElement {
|
|
235
220
|
/** The `id` attribute of the iframe. */
|
|
236
221
|
id: string,
|
|
@@ -443,28 +428,6 @@ declare module Artifacts {
|
|
|
443
428
|
fetchPriority?: string;
|
|
444
429
|
}
|
|
445
430
|
|
|
446
|
-
interface OptimizedImage {
|
|
447
|
-
failed: false;
|
|
448
|
-
originalSize: number;
|
|
449
|
-
jpegSize?: number;
|
|
450
|
-
webpSize?: number;
|
|
451
|
-
|
|
452
|
-
requestId: string;
|
|
453
|
-
url: string;
|
|
454
|
-
mimeType: string;
|
|
455
|
-
resourceSize: number;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
interface OptimizedImageError {
|
|
459
|
-
failed: true;
|
|
460
|
-
errMsg: string;
|
|
461
|
-
|
|
462
|
-
requestId: string;
|
|
463
|
-
url: string;
|
|
464
|
-
mimeType: string;
|
|
465
|
-
resourceSize: number;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
431
|
interface TraceElement {
|
|
469
432
|
traceEventType: 'trace-engine'|'layout-shift'|'animation';
|
|
470
433
|
node: NodeDetails;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export default OffscreenImages;
|
|
2
|
-
export type WasteResult = {
|
|
3
|
-
node: LH.Audit.Details.NodeValue;
|
|
4
|
-
url: string;
|
|
5
|
-
requestStartTime: number;
|
|
6
|
-
totalBytes: number;
|
|
7
|
-
wastedBytes: number;
|
|
8
|
-
wastedPercent: number;
|
|
9
|
-
};
|
|
10
|
-
/** @typedef {{node: LH.Audit.Details.NodeValue, url: string, requestStartTime: number, totalBytes: number, wastedBytes: number, wastedPercent: number}} WasteResult */
|
|
11
|
-
declare class OffscreenImages extends ByteEfficiencyAudit {
|
|
12
|
-
/**
|
|
13
|
-
* @param {{top: number, bottom: number, left: number, right: number}} imageRect
|
|
14
|
-
* @param {{innerWidth: number, innerHeight: number}} viewportDimensions
|
|
15
|
-
* @return {number}
|
|
16
|
-
*/
|
|
17
|
-
static computeVisiblePixels(imageRect: {
|
|
18
|
-
top: number;
|
|
19
|
-
bottom: number;
|
|
20
|
-
left: number;
|
|
21
|
-
right: number;
|
|
22
|
-
}, viewportDimensions: {
|
|
23
|
-
innerWidth: number;
|
|
24
|
-
innerHeight: number;
|
|
25
|
-
}): number;
|
|
26
|
-
/**
|
|
27
|
-
* @param {LH.Artifacts.ImageElement} image
|
|
28
|
-
* @param {{innerWidth: number, innerHeight: number}} viewportDimensions
|
|
29
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
30
|
-
* @return {null|Error|WasteResult}
|
|
31
|
-
*/
|
|
32
|
-
static computeWaste(image: LH.Artifacts.ImageElement, viewportDimensions: {
|
|
33
|
-
innerWidth: number;
|
|
34
|
-
innerHeight: number;
|
|
35
|
-
}, networkRecords: Array<LH.Artifacts.NetworkRequest>): null | Error | WasteResult;
|
|
36
|
-
/**
|
|
37
|
-
* Filters out image requests that were requested after the last long task based on lantern timings.
|
|
38
|
-
*
|
|
39
|
-
* @param {WasteResult[]} images
|
|
40
|
-
* @param {LH.Artifacts.LanternMetric} lanternMetricData
|
|
41
|
-
*/
|
|
42
|
-
static filterLanternResults(images: WasteResult[], lanternMetricData: LH.Artifacts.LanternMetric): WasteResult[];
|
|
43
|
-
/**
|
|
44
|
-
* Filters out image requests that were requested after TTI.
|
|
45
|
-
*
|
|
46
|
-
* @param {WasteResult[]} images
|
|
47
|
-
* @param {number} interactiveTimestamp
|
|
48
|
-
*/
|
|
49
|
-
static filterObservedResults(images: WasteResult[], interactiveTimestamp: number): WasteResult[];
|
|
50
|
-
/**
|
|
51
|
-
* @param {LH.Artifacts} artifacts
|
|
52
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
53
|
-
* @param {LH.Audit.Context} context
|
|
54
|
-
* @return {Promise<import('./byte-efficiency-audit.js').ByteEfficiencyProduct>}
|
|
55
|
-
*/
|
|
56
|
-
static audit_(artifacts: LH.Artifacts, networkRecords: Array<LH.Artifacts.NetworkRequest>, context: LH.Audit.Context): Promise<import("./byte-efficiency-audit.js").ByteEfficiencyProduct>;
|
|
57
|
-
}
|
|
58
|
-
export namespace UIStrings {
|
|
59
|
-
let title: string;
|
|
60
|
-
let description: string;
|
|
61
|
-
}
|
|
62
|
-
import { ByteEfficiencyAudit } from './byte-efficiency-audit.js';
|
|
63
|
-
//# sourceMappingURL=offscreen-images.d.ts.map
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2017 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* @fileoverview Checks to see if images are displayed only outside of the viewport.
|
|
8
|
-
* Images requested after TTI are not flagged as violations.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {ByteEfficiencyAudit} from './byte-efficiency-audit.js';
|
|
13
|
-
import {NetworkRequest} from '../../lib/network-request.js';
|
|
14
|
-
import {Sentry} from '../../lib/sentry.js';
|
|
15
|
-
import UrlUtils from '../../lib/url-utils.js';
|
|
16
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
17
|
-
import {Interactive} from '../../computed/metrics/interactive.js';
|
|
18
|
-
import {ProcessedTrace} from '../../computed/processed-trace.js';
|
|
19
|
-
|
|
20
|
-
const UIStrings = {
|
|
21
|
-
/** Imperative title of a Lighthouse audit that tells the user to defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. This is displayed in a list of audit titles that Lighthouse generates. */
|
|
22
|
-
title: 'Defer offscreen images',
|
|
23
|
-
/** Description of a Lighthouse audit that tells the user *why* they should defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. 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. */
|
|
24
|
-
description:
|
|
25
|
-
'Consider lazy-loading offscreen and hidden images after all critical resources have ' +
|
|
26
|
-
'finished loading to lower time to interactive. ' +
|
|
27
|
-
'[Learn how to defer offscreen images](https://developer.chrome.com/docs/lighthouse/performance/offscreen-images/).',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
31
|
-
|
|
32
|
-
// See https://github.com/GoogleChrome/lighthouse/issues/10471 for discussion about the thresholds here.
|
|
33
|
-
const ALLOWABLE_OFFSCREEN_IN_PX = 100;
|
|
34
|
-
const ALLOWABLE_OFFSCREEN_BOTTOM_IN_VIEWPORTS = 3;
|
|
35
|
-
|
|
36
|
-
const IGNORE_THRESHOLD_IN_BYTES = 2048;
|
|
37
|
-
const IGNORE_THRESHOLD_IN_PERCENT = 75;
|
|
38
|
-
const IGNORE_THRESHOLD_IN_MS = 50;
|
|
39
|
-
|
|
40
|
-
/** @typedef {{node: LH.Audit.Details.NodeValue, url: string, requestStartTime: number, totalBytes: number, wastedBytes: number, wastedPercent: number}} WasteResult */
|
|
41
|
-
|
|
42
|
-
class OffscreenImages extends ByteEfficiencyAudit {
|
|
43
|
-
/**
|
|
44
|
-
* @return {LH.Audit.Meta}
|
|
45
|
-
*/
|
|
46
|
-
static get meta() {
|
|
47
|
-
return {
|
|
48
|
-
id: 'offscreen-images',
|
|
49
|
-
title: str_(UIStrings.title),
|
|
50
|
-
description: str_(UIStrings.description),
|
|
51
|
-
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
52
|
-
supportedModes: ['navigation'],
|
|
53
|
-
guidanceLevel: 2,
|
|
54
|
-
requiredArtifacts: ['ImageElements', 'ViewportDimensions', 'GatherContext', 'DevtoolsLog',
|
|
55
|
-
'Trace', 'URL', 'SourceMaps'],
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {{top: number, bottom: number, left: number, right: number}} imageRect
|
|
61
|
-
* @param {{innerWidth: number, innerHeight: number}} viewportDimensions
|
|
62
|
-
* @return {number}
|
|
63
|
-
*/
|
|
64
|
-
static computeVisiblePixels(imageRect, viewportDimensions) {
|
|
65
|
-
const innerWidth = viewportDimensions.innerWidth;
|
|
66
|
-
const innerHeight = viewportDimensions.innerHeight;
|
|
67
|
-
const allowableOffscreenBottomInPx = ALLOWABLE_OFFSCREEN_BOTTOM_IN_VIEWPORTS *
|
|
68
|
-
viewportDimensions.innerHeight;
|
|
69
|
-
|
|
70
|
-
const top = Math.max(imageRect.top, -1 * ALLOWABLE_OFFSCREEN_IN_PX);
|
|
71
|
-
const right = Math.min(imageRect.right, innerWidth + ALLOWABLE_OFFSCREEN_IN_PX);
|
|
72
|
-
const bottom = Math.min(imageRect.bottom, innerHeight + allowableOffscreenBottomInPx);
|
|
73
|
-
const left = Math.max(imageRect.left, -1 * ALLOWABLE_OFFSCREEN_IN_PX);
|
|
74
|
-
|
|
75
|
-
return Math.max(right - left, 0) * Math.max(bottom - top, 0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @param {LH.Artifacts.ImageElement} image
|
|
80
|
-
* @param {{innerWidth: number, innerHeight: number}} viewportDimensions
|
|
81
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
82
|
-
* @return {null|Error|WasteResult}
|
|
83
|
-
*/
|
|
84
|
-
static computeWaste(image, viewportDimensions, networkRecords) {
|
|
85
|
-
const networkRecord = networkRecords.find(record => record.url === image.src);
|
|
86
|
-
// If we don't know how big it was, we can't really report savings, treat it as passed.
|
|
87
|
-
if (!networkRecord) return null;
|
|
88
|
-
// If the image had its loading behavior explicitly controlled already, treat it as passed.
|
|
89
|
-
if (image.loading === 'lazy' || image.loading === 'eager') return null;
|
|
90
|
-
|
|
91
|
-
const url = UrlUtils.elideDataURI(image.src);
|
|
92
|
-
const totalPixels = image.displayedWidth * image.displayedHeight;
|
|
93
|
-
const visiblePixels = this.computeVisiblePixels(image.clientRect, viewportDimensions);
|
|
94
|
-
// Treat images with 0 area as if they're offscreen. See https://github.com/GoogleChrome/lighthouse/issues/1914
|
|
95
|
-
const wastedRatio = totalPixels === 0 ? 1 : 1 - visiblePixels / totalPixels;
|
|
96
|
-
const totalBytes = NetworkRequest.getResourceSizeOnNetwork(networkRecord);
|
|
97
|
-
const wastedBytes = Math.round(totalBytes * wastedRatio);
|
|
98
|
-
|
|
99
|
-
if (!Number.isFinite(wastedRatio)) {
|
|
100
|
-
return new Error(`Invalid image sizing information ${url}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
node: ByteEfficiencyAudit.makeNodeItem(image.node),
|
|
105
|
-
url,
|
|
106
|
-
requestStartTime: networkRecord.networkRequestTime,
|
|
107
|
-
totalBytes,
|
|
108
|
-
wastedBytes,
|
|
109
|
-
wastedPercent: 100 * wastedRatio,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Filters out image requests that were requested after the last long task based on lantern timings.
|
|
115
|
-
*
|
|
116
|
-
* @param {WasteResult[]} images
|
|
117
|
-
* @param {LH.Artifacts.LanternMetric} lanternMetricData
|
|
118
|
-
*/
|
|
119
|
-
static filterLanternResults(images, lanternMetricData) {
|
|
120
|
-
const nodeTimings = lanternMetricData.pessimisticEstimate.nodeTimings;
|
|
121
|
-
|
|
122
|
-
// Find the last long task start time
|
|
123
|
-
let lastLongTaskStartTime = 0;
|
|
124
|
-
// Find the start time of all requests
|
|
125
|
-
/** @type {Map<string, number>} */
|
|
126
|
-
const startTimesByURL = new Map();
|
|
127
|
-
for (const [node, timing] of nodeTimings) {
|
|
128
|
-
if (node.type === 'cpu' && timing.duration >= 50) {
|
|
129
|
-
lastLongTaskStartTime = Math.max(lastLongTaskStartTime, timing.startTime);
|
|
130
|
-
} else if (node.type === 'network') {
|
|
131
|
-
startTimesByURL.set(node.request.url, timing.startTime);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return images.filter(image => {
|
|
136
|
-
// Filter out images that had little waste
|
|
137
|
-
if (image.wastedBytes < IGNORE_THRESHOLD_IN_BYTES) return false;
|
|
138
|
-
if (image.wastedPercent < IGNORE_THRESHOLD_IN_PERCENT) return false;
|
|
139
|
-
// Filter out images that started after the last long task
|
|
140
|
-
const imageRequestStartTime = startTimesByURL.get(image.url) || 0;
|
|
141
|
-
return imageRequestStartTime < lastLongTaskStartTime - IGNORE_THRESHOLD_IN_MS;
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Filters out image requests that were requested after TTI.
|
|
147
|
-
*
|
|
148
|
-
* @param {WasteResult[]} images
|
|
149
|
-
* @param {number} interactiveTimestamp
|
|
150
|
-
*/
|
|
151
|
-
static filterObservedResults(images, interactiveTimestamp) {
|
|
152
|
-
return images.filter(image => {
|
|
153
|
-
if (image.wastedBytes < IGNORE_THRESHOLD_IN_BYTES) return false;
|
|
154
|
-
if (image.wastedPercent < IGNORE_THRESHOLD_IN_PERCENT) return false;
|
|
155
|
-
return image.requestStartTime < interactiveTimestamp / 1000 - IGNORE_THRESHOLD_IN_MS;
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* @param {LH.Artifacts} artifacts
|
|
161
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
162
|
-
* @param {LH.Audit.Context} context
|
|
163
|
-
* @return {Promise<import('./byte-efficiency-audit.js').ByteEfficiencyProduct>}
|
|
164
|
-
*/
|
|
165
|
-
static async audit_(artifacts, networkRecords, context) {
|
|
166
|
-
const {URL, SourceMaps} = artifacts;
|
|
167
|
-
const images = artifacts.ImageElements;
|
|
168
|
-
const viewportDimensions = artifacts.ViewportDimensions;
|
|
169
|
-
const gatherContext = artifacts.GatherContext;
|
|
170
|
-
const trace = artifacts.Trace;
|
|
171
|
-
const devtoolsLog = artifacts.DevtoolsLog;
|
|
172
|
-
|
|
173
|
-
/** @type {string[]} */
|
|
174
|
-
const warnings = [];
|
|
175
|
-
/** @type {Map<string, WasteResult>} */
|
|
176
|
-
const resultsMap = new Map();
|
|
177
|
-
for (const image of images) {
|
|
178
|
-
const processed = OffscreenImages.computeWaste(image, viewportDimensions, networkRecords);
|
|
179
|
-
if (processed === null) {
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (processed instanceof Error) {
|
|
184
|
-
warnings.push(processed.message);
|
|
185
|
-
Sentry.captureException(processed, {tags: {audit: this.meta.id}, level: 'warning'});
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// If an image was used more than once, warn only about its least wasteful usage
|
|
190
|
-
const existing = resultsMap.get(processed.url);
|
|
191
|
-
if (!existing || existing.wastedBytes > processed.wastedBytes) {
|
|
192
|
-
resultsMap.set(processed.url, processed);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const settings = context.settings;
|
|
197
|
-
|
|
198
|
-
let items;
|
|
199
|
-
const unfilteredResults = Array.from(resultsMap.values());
|
|
200
|
-
// get the interactive time or fallback to getting the end of trace time
|
|
201
|
-
try {
|
|
202
|
-
const metricComputationData =
|
|
203
|
-
{trace, devtoolsLog, gatherContext, settings, URL, SourceMaps, simulator: null};
|
|
204
|
-
const interactive = await Interactive.request(metricComputationData, context);
|
|
205
|
-
|
|
206
|
-
// use interactive to generate items
|
|
207
|
-
const lanternInteractive = /** @type {LH.Artifacts.LanternMetric} */ (interactive);
|
|
208
|
-
// Filter out images that were loaded after all CPU activity
|
|
209
|
-
items = context.settings.throttlingMethod === 'simulate' ?
|
|
210
|
-
OffscreenImages.filterLanternResults(unfilteredResults, lanternInteractive) :
|
|
211
|
-
// @ts-expect-error - .timestamp will exist if throttlingMethod isn't lantern
|
|
212
|
-
OffscreenImages.filterObservedResults(unfilteredResults, interactive.timestamp);
|
|
213
|
-
} catch (err) {
|
|
214
|
-
// if the error is during a Lantern run, end of trace may also be inaccurate, so rethrow
|
|
215
|
-
if (context.settings.throttlingMethod === 'simulate') {
|
|
216
|
-
throw err;
|
|
217
|
-
}
|
|
218
|
-
// use end of trace as a substitute for finding interactive time
|
|
219
|
-
items = OffscreenImages.filterObservedResults(unfilteredResults,
|
|
220
|
-
await ProcessedTrace.request(trace, context).then(tot => tot.timestamps.traceEnd));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/** @type {LH.Audit.Details.Opportunity['headings']} */
|
|
224
|
-
const headings = [
|
|
225
|
-
{key: 'node', valueType: 'node', label: ''},
|
|
226
|
-
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
227
|
-
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnResourceSize)},
|
|
228
|
-
{key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
|
|
229
|
-
];
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
warnings,
|
|
233
|
-
items,
|
|
234
|
-
headings,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export default OffscreenImages;
|
|
240
|
-
export {UIStrings};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export default NoDocWriteAudit;
|
|
2
|
-
declare class NoDocWriteAudit 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=no-document-write.d.ts.map
|
|
@@ -1,86 +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's using document.write(). document.write() has terrible performance characteristics.
|
|
9
|
-
*
|
|
10
|
-
* *Intervention*
|
|
11
|
-
* There is a Chrome intervention for the API: https://developers.google.com/web/updates/2016/08/removing-document-write
|
|
12
|
-
* The intervention appears to only be enabled when the user is on a slow connnection. https://chromestatus.com/features#document.write
|
|
13
|
-
* When it's enabled, _some_ calls to document.write() will just not do anything. They're just no-ops.
|
|
14
|
-
* - "some" == mostly third-party situations. src: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/script/document_write_intervention.cc?l=109&rcl=61a806621861e9abc07b3a57a6f2edae188d1742
|
|
15
|
-
* If this happens, there will be an error message in the console. src: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/script/document_write_intervention.cc?l=51-61&rcl=61a806621861e9abc07b3a57a6f2edae188d1742
|
|
16
|
-
* - Lighthouse doesn't report here on that situation, though it'll show up in `errors-in-console`
|
|
17
|
-
* The intervention may also not block the .write() (because the connection wasn't slow),
|
|
18
|
-
* but it will emit a console warning.
|
|
19
|
-
* - Lighthouse will also report that here, as the .write() call succeeded.
|
|
20
|
-
* Demo URL: https://output.jsbin.com/qopijux/quiet
|
|
21
|
-
*
|
|
22
|
-
* *This Audit*
|
|
23
|
-
* This audit reports on document.write() calls which the intervention didn't stop.
|
|
24
|
-
* (They worked as intended). If that happens, the browser emits a verbose-level violation
|
|
25
|
-
* console message (hidden by default) that says:
|
|
26
|
-
* "Parser was blocked due to document.write(<script>)". src: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/frame/performance_monitor.cc?l=294-300&rcl=40b90cafad9f219e0845879ed8648bdcc96116dc
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import ViolationAudit from '../violation-audit.js';
|
|
31
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
32
|
-
|
|
33
|
-
const UIStrings = {
|
|
34
|
-
/** Title of a Lighthouse audit that provides detail on the page's use of the `document.write` API. This descriptive title is shown to users when the page does not use `document.write`. */
|
|
35
|
-
title: 'Avoids `document.write()`',
|
|
36
|
-
/** Title of a Lighthouse audit that provides detail on the page's use of the `document.write` API. This imperative title is shown to users when the page does use `document.write`. */
|
|
37
|
-
failureTitle: 'Avoid `document.write()`',
|
|
38
|
-
/** Description of a Lighthouse audit that tells the user why they should avoid `document.write`. 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. */
|
|
39
|
-
description: 'For users on slow connections, external scripts dynamically injected via ' +
|
|
40
|
-
'`document.write()` can delay page load by tens of seconds. ' +
|
|
41
|
-
'[Learn how to avoid document.write()](https://developer.chrome.com/docs/lighthouse/best-practices/no-document-write/).',
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
45
|
-
|
|
46
|
-
class NoDocWriteAudit extends ViolationAudit {
|
|
47
|
-
/**
|
|
48
|
-
* @return {LH.Audit.Meta}
|
|
49
|
-
*/
|
|
50
|
-
static get meta() {
|
|
51
|
-
return {
|
|
52
|
-
id: 'no-document-write',
|
|
53
|
-
title: str_(UIStrings.title),
|
|
54
|
-
failureTitle: str_(UIStrings.failureTitle),
|
|
55
|
-
description: str_(UIStrings.description),
|
|
56
|
-
guidanceLevel: 2,
|
|
57
|
-
requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'Scripts'],
|
|
58
|
-
scoreDisplayMode: ViolationAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {LH.Artifacts} artifacts
|
|
64
|
-
* @param {LH.Audit.Context} context
|
|
65
|
-
* @return {Promise<LH.Audit.Product>}
|
|
66
|
-
*/
|
|
67
|
-
static async audit(artifacts, context) {
|
|
68
|
-
const results =
|
|
69
|
-
await ViolationAudit.getViolationResults(artifacts, context, /document\.write/);
|
|
70
|
-
|
|
71
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
72
|
-
const headings = [
|
|
73
|
-
{key: 'source', valueType: 'source-location', label: str_(i18n.UIStrings.columnSource)},
|
|
74
|
-
];
|
|
75
|
-
// TODO(bckenny): see TODO in geolocation-on-start
|
|
76
|
-
const details = ViolationAudit.makeTableDetails(headings, results);
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
score: Number(results.length === 0),
|
|
80
|
-
details,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export default NoDocWriteAudit;
|
|
86
|
-
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,12 +0,0 @@
|
|
|
1
|
-
export default FirstMeaningfulPaint;
|
|
2
|
-
declare class FirstMeaningfulPaint extends Audit {
|
|
3
|
-
/**
|
|
4
|
-
* @return {Promise<LH.Audit.Product>}
|
|
5
|
-
*/
|
|
6
|
-
static audit(): Promise<LH.Audit.Product>;
|
|
7
|
-
}
|
|
8
|
-
export namespace UIStrings {
|
|
9
|
-
let description: string;
|
|
10
|
-
}
|
|
11
|
-
import { Audit } from '../audit.js';
|
|
12
|
-
//# sourceMappingURL=first-meaningful-paint.d.ts.map
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// TODO(COMPAT): This is just a shell. Remove in future breaking release.
|
|
8
|
-
|
|
9
|
-
import {Audit} from '../audit.js';
|
|
10
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
11
|
-
|
|
12
|
-
const UIStrings = {
|
|
13
|
-
/** Description of the First Meaningful Paint (FMP) metric, which marks the time at which a majority of the content has been painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
14
|
-
description: 'First Meaningful Paint measures when the primary content of a page is ' +
|
|
15
|
-
'visible. [Learn more about the First Meaningful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/first-meaningful-paint/).',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
19
|
-
|
|
20
|
-
class FirstMeaningfulPaint extends Audit {
|
|
21
|
-
/**
|
|
22
|
-
* @return {LH.Audit.Meta}
|
|
23
|
-
*/
|
|
24
|
-
static get meta() {
|
|
25
|
-
return {
|
|
26
|
-
id: 'first-meaningful-paint',
|
|
27
|
-
title: str_(i18n.UIStrings.firstMeaningfulPaintMetric),
|
|
28
|
-
description: str_(UIStrings.description),
|
|
29
|
-
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
30
|
-
supportedModes: ['navigation'],
|
|
31
|
-
requiredArtifacts: ['Trace', 'DevtoolsLog', 'GatherContext', 'URL'],
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @return {Promise<LH.Audit.Product>}
|
|
37
|
-
*/
|
|
38
|
-
static async audit() {
|
|
39
|
-
return {
|
|
40
|
-
score: null,
|
|
41
|
-
notApplicable: true,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default FirstMeaningfulPaint;
|
|
47
|
-
export {UIStrings};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export default CacheContents;
|
|
2
|
-
declare class CacheContents extends BaseGatherer {
|
|
3
|
-
/**
|
|
4
|
-
* Creates an array of cached URLs.
|
|
5
|
-
* @param {LH.Gatherer.Context} passContext
|
|
6
|
-
* @return {Promise<LH.Artifacts['CacheContents']>}
|
|
7
|
-
*/
|
|
8
|
-
getArtifact(passContext: LH.Gatherer.Context): Promise<LH.Artifacts["CacheContents"]>;
|
|
9
|
-
}
|
|
10
|
-
import BaseGatherer from '../base-gatherer.js';
|
|
11
|
-
//# sourceMappingURL=cache-contents.d.ts.map
|