lighthouse 12.8.2-dev.20251004 → 12.8.2-dev.20251006
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/test/smokehouse/config/exclusions.js +0 -2
- package/core/audits/audit.js +0 -1
- package/core/audits/insights/cls-culprits-insight.js +1 -1
- package/core/audits/insights/dom-size-insight.js +6 -6
- package/core/audits/redirects.js +1 -0
- package/core/audits/server-response-time.d.ts +0 -5
- package/core/audits/server-response-time.js +12 -26
- package/core/computed/metrics/lcp-breakdown.js +1 -0
- package/core/config/default-config.js +20 -63
- package/core/config/experimental-config.js +1 -26
- 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/gatherers/trace-elements.js +1 -0
- package/core/lib/proto-preprocessor.js +5 -22
- 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 +3 -3
- 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/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 +3 -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 +0 -330
- package/shared/localization/locales/ar.json +0 -330
- package/shared/localization/locales/bg.json +0 -330
- package/shared/localization/locales/ca.json +0 -330
- package/shared/localization/locales/cs.json +0 -330
- package/shared/localization/locales/da.json +0 -330
- package/shared/localization/locales/de.json +0 -330
- package/shared/localization/locales/el.json +0 -330
- package/shared/localization/locales/en-GB.json +0 -330
- package/shared/localization/locales/en-US.json +26 -275
- package/shared/localization/locales/en-XA.json +0 -330
- package/shared/localization/locales/en-XL.json +26 -275
- package/shared/localization/locales/es-419.json +0 -330
- package/shared/localization/locales/es.json +0 -330
- package/shared/localization/locales/fi.json +0 -330
- package/shared/localization/locales/fil.json +0 -330
- package/shared/localization/locales/fr.json +0 -330
- package/shared/localization/locales/he.json +0 -330
- package/shared/localization/locales/hi.json +0 -330
- package/shared/localization/locales/hr.json +0 -330
- package/shared/localization/locales/hu.json +0 -330
- package/shared/localization/locales/id.json +0 -330
- package/shared/localization/locales/it.json +0 -330
- package/shared/localization/locales/ja.json +0 -330
- package/shared/localization/locales/ko.json +0 -330
- package/shared/localization/locales/lt.json +0 -330
- package/shared/localization/locales/lv.json +0 -330
- package/shared/localization/locales/nl.json +0 -330
- package/shared/localization/locales/no.json +0 -330
- package/shared/localization/locales/pl.json +0 -330
- package/shared/localization/locales/pt-PT.json +0 -330
- package/shared/localization/locales/pt.json +0 -330
- package/shared/localization/locales/ro.json +0 -330
- package/shared/localization/locales/ru.json +0 -330
- package/shared/localization/locales/sk.json +0 -330
- package/shared/localization/locales/sl.json +0 -330
- package/shared/localization/locales/sr-Latn.json +0 -330
- package/shared/localization/locales/sr.json +0 -330
- package/shared/localization/locales/sv.json +0 -330
- package/shared/localization/locales/ta.json +0 -330
- package/shared/localization/locales/te.json +0 -330
- package/shared/localization/locales/th.json +0 -330
- package/shared/localization/locales/tr.json +0 -330
- package/shared/localization/locales/uk.json +0 -330
- package/shared/localization/locales/vi.json +0 -330
- package/shared/localization/locales/zh-HK.json +0 -330
- package/shared/localization/locales/zh-TW.json +0 -330
- package/shared/localization/locales/zh.json +0 -330
- package/types/artifacts.d.ts +1 -0
- 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/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/uses-http2.d.ts +0 -72
- package/core/audits/dobetterweb/uses-http2.js +0 -276
- 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/prioritize-lcp-image.d.ts +0 -74
- package/core/audits/prioritize-lcp-image.js +0 -297
- 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/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
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2020 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @fileoverview This audit highlights JavaScript modules that appear to be duplicated across
|
|
9
|
-
* all resources, either within the same bundle or between different bundles.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/** @typedef {import('./byte-efficiency-audit.js').ByteEfficiencyProduct} ByteEfficiencyProduct */
|
|
13
|
-
/** @typedef {LH.Audit.ByteEfficiencyItem & {source: string, subItems: {type: 'subitems', items: SubItem[]}}} Item */
|
|
14
|
-
/** @typedef {{url: string, sourceTransferBytes?: number}} SubItem */
|
|
15
|
-
|
|
16
|
-
import {ByteEfficiencyAudit} from './byte-efficiency-audit.js';
|
|
17
|
-
import {ModuleDuplication} from '../../computed/module-duplication.js';
|
|
18
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
19
|
-
import {estimateCompressionRatioForContent} from '../../lib/script-helpers.js';
|
|
20
|
-
|
|
21
|
-
const UIStrings = {
|
|
22
|
-
/** Imperative title of a Lighthouse audit that tells the user to remove duplicate JavaScript from their code. This is displayed in a list of audit titles that Lighthouse generates. */
|
|
23
|
-
title: 'Remove duplicate modules in JavaScript bundles',
|
|
24
|
-
/** Description of a Lighthouse audit that tells the user *why* they should remove duplicate JavaScript from their scripts. This is displayed after a user expands the section to see more. No word length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
25
|
-
description: 'Remove large, duplicate JavaScript modules from bundles ' +
|
|
26
|
-
'to reduce unnecessary bytes consumed by network activity. ', // +
|
|
27
|
-
// TODO: we need docs.
|
|
28
|
-
// '[Learn more](https://developer.chrome.com/docs/lighthouse/performance/duplicated-javascript/).',
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
32
|
-
|
|
33
|
-
const IGNORE_THRESHOLD_IN_BYTES = 1024 * 10;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @param {string} haystack
|
|
37
|
-
* @param {string} needle
|
|
38
|
-
* @param {number} startPosition
|
|
39
|
-
*/
|
|
40
|
-
function indexOfOrEnd(haystack, needle, startPosition = 0) {
|
|
41
|
-
const index = haystack.indexOf(needle, startPosition);
|
|
42
|
-
return index === -1 ? haystack.length : index;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
class DuplicatedJavascript extends ByteEfficiencyAudit {
|
|
46
|
-
/**
|
|
47
|
-
* @return {LH.Audit.Meta}
|
|
48
|
-
*/
|
|
49
|
-
static get meta() {
|
|
50
|
-
return {
|
|
51
|
-
id: 'duplicated-javascript',
|
|
52
|
-
title: str_(UIStrings.title),
|
|
53
|
-
description: str_(UIStrings.description),
|
|
54
|
-
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
55
|
-
guidanceLevel: 2,
|
|
56
|
-
requiredArtifacts: ['DevtoolsLog', 'Trace', 'SourceMaps', 'Scripts',
|
|
57
|
-
'GatherContext', 'URL'],
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @param {string} source
|
|
63
|
-
*/
|
|
64
|
-
static _getNodeModuleName(source) {
|
|
65
|
-
const sourceSplit = source.split('node_modules/');
|
|
66
|
-
source = sourceSplit[sourceSplit.length - 1];
|
|
67
|
-
|
|
68
|
-
const indexFirstSlash = indexOfOrEnd(source, '/');
|
|
69
|
-
if (source[0] === '@') {
|
|
70
|
-
return source.slice(0, indexOfOrEnd(source, '/', indexFirstSlash + 1));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return source.slice(0, indexFirstSlash);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* @param {LH.Artifacts} artifacts
|
|
78
|
-
* @param {LH.Audit.Context} context
|
|
79
|
-
*/
|
|
80
|
-
static async _getDuplicationGroupedByNodeModules(artifacts, context) {
|
|
81
|
-
const duplication = await ModuleDuplication.request(artifacts, context);
|
|
82
|
-
|
|
83
|
-
/** @type {typeof duplication} */
|
|
84
|
-
const groupedDuplication = new Map();
|
|
85
|
-
for (const [source, sourceDatas] of duplication.entries()) {
|
|
86
|
-
if (!source.includes('node_modules')) {
|
|
87
|
-
groupedDuplication.set(source, sourceDatas);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const normalizedSource = 'node_modules/' + DuplicatedJavascript._getNodeModuleName(source);
|
|
92
|
-
const aggregatedSourceDatas = groupedDuplication.get(normalizedSource) || [];
|
|
93
|
-
for (const {scriptId, scriptUrl, resourceSize} of sourceDatas) {
|
|
94
|
-
let sourceData = aggregatedSourceDatas.find(d => d.scriptId === scriptId);
|
|
95
|
-
if (!sourceData) {
|
|
96
|
-
sourceData = {scriptId, scriptUrl, resourceSize: 0};
|
|
97
|
-
aggregatedSourceDatas.push(sourceData);
|
|
98
|
-
}
|
|
99
|
-
sourceData.resourceSize += resourceSize;
|
|
100
|
-
}
|
|
101
|
-
groupedDuplication.set(normalizedSource, aggregatedSourceDatas);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
for (const sourceDatas of duplication.values()) {
|
|
105
|
-
sourceDatas.sort((a, b) => b.resourceSize - a.resourceSize);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return groupedDuplication;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Each details item returned is a module with subItems for each resource that
|
|
113
|
-
* includes it. The wastedBytes for the details item is the number of bytes
|
|
114
|
-
* occupied by the sum of all but the largest copy of the module. wastedBytesByUrl
|
|
115
|
-
* attributes the cost of the bytes to a specific resource, for use by lantern.
|
|
116
|
-
* @param {LH.Artifacts} artifacts
|
|
117
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
118
|
-
* @param {LH.Audit.Context} context
|
|
119
|
-
* @return {Promise<ByteEfficiencyProduct>}
|
|
120
|
-
*/
|
|
121
|
-
static async audit_(artifacts, networkRecords, context) {
|
|
122
|
-
const ignoreThresholdInBytes =
|
|
123
|
-
context.options?.ignoreThresholdInBytes || IGNORE_THRESHOLD_IN_BYTES;
|
|
124
|
-
const duplication =
|
|
125
|
-
await DuplicatedJavascript._getDuplicationGroupedByNodeModules(artifacts, context);
|
|
126
|
-
|
|
127
|
-
/** @type {Map<string, number>} */
|
|
128
|
-
const compressionRatioByUrl = new Map();
|
|
129
|
-
|
|
130
|
-
/** @type {Item[]} */
|
|
131
|
-
const items = [];
|
|
132
|
-
|
|
133
|
-
let overflowWastedBytes = 0;
|
|
134
|
-
const overflowUrls = new Set();
|
|
135
|
-
|
|
136
|
-
/** @type {Map<string, number>} */
|
|
137
|
-
const wastedBytesByUrl = new Map();
|
|
138
|
-
for (const [source, sourceDatas] of duplication.entries()) {
|
|
139
|
-
// One copy of this module is treated as the canonical version - the rest will have
|
|
140
|
-
// non-zero `wastedBytes`. In the case of all copies being the same version, all sizes are
|
|
141
|
-
// equal and the selection doesn't matter (ignoring compression ratios). When the copies are
|
|
142
|
-
// different versions, it does matter. Ideally the newest version would be the canonical
|
|
143
|
-
// copy, but version information is not present. Instead, size is used as a heuristic for
|
|
144
|
-
// latest version. This makes the audit conserative in its estimation.
|
|
145
|
-
|
|
146
|
-
/** @type {SubItem[]} */
|
|
147
|
-
const subItems = [];
|
|
148
|
-
|
|
149
|
-
let wastedBytesTotal = 0;
|
|
150
|
-
for (let i = 0; i < sourceDatas.length; i++) {
|
|
151
|
-
const sourceData = sourceDatas[i];
|
|
152
|
-
const scriptId = sourceData.scriptId;
|
|
153
|
-
const script = artifacts.Scripts.find(script => script.scriptId === scriptId);
|
|
154
|
-
const url = script?.url || '';
|
|
155
|
-
const compressionRatio = estimateCompressionRatioForContent(
|
|
156
|
-
compressionRatioByUrl, url, artifacts, networkRecords);
|
|
157
|
-
const transferSize = Math.round(sourceData.resourceSize * compressionRatio);
|
|
158
|
-
|
|
159
|
-
subItems.push({
|
|
160
|
-
url,
|
|
161
|
-
sourceTransferBytes: transferSize,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (i === 0) continue;
|
|
165
|
-
wastedBytesTotal += transferSize;
|
|
166
|
-
wastedBytesByUrl.set(url, (wastedBytesByUrl.get(url) || 0) + transferSize);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (wastedBytesTotal <= ignoreThresholdInBytes) {
|
|
170
|
-
overflowWastedBytes += wastedBytesTotal;
|
|
171
|
-
for (const subItem of subItems) {
|
|
172
|
-
overflowUrls.add(subItem.url);
|
|
173
|
-
}
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
items.push({
|
|
178
|
-
source,
|
|
179
|
-
wastedBytes: wastedBytesTotal,
|
|
180
|
-
// Not needed, but keeps typescript happy.
|
|
181
|
-
url: '',
|
|
182
|
-
// Not needed, but keeps typescript happy.
|
|
183
|
-
totalBytes: 0,
|
|
184
|
-
subItems: {
|
|
185
|
-
type: 'subitems',
|
|
186
|
-
items: subItems,
|
|
187
|
-
},
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (overflowWastedBytes > ignoreThresholdInBytes) {
|
|
192
|
-
items.push({
|
|
193
|
-
source: 'Other',
|
|
194
|
-
wastedBytes: overflowWastedBytes,
|
|
195
|
-
url: '',
|
|
196
|
-
totalBytes: 0,
|
|
197
|
-
subItems: {
|
|
198
|
-
type: 'subitems',
|
|
199
|
-
items: Array.from(overflowUrls).map(url => ({url})),
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** @type {LH.Audit.Details.TableColumnHeading[]} */
|
|
205
|
-
const headings = [
|
|
206
|
-
/* eslint-disable max-len */
|
|
207
|
-
{key: 'source', valueType: 'code', subItemsHeading: {key: 'url', valueType: 'url'}, label: str_(i18n.UIStrings.columnSource)},
|
|
208
|
-
{key: null, valueType: 'bytes', subItemsHeading: {key: 'sourceTransferBytes'}, granularity: 10, label: str_(i18n.UIStrings.columnTransferSize)},
|
|
209
|
-
{key: 'wastedBytes', valueType: 'bytes', granularity: 10, label: str_(i18n.UIStrings.columnWastedBytes)},
|
|
210
|
-
/* eslint-enable max-len */
|
|
211
|
-
];
|
|
212
|
-
|
|
213
|
-
// TODO: show warning somewhere if no source maps.
|
|
214
|
-
return {
|
|
215
|
-
items,
|
|
216
|
-
headings,
|
|
217
|
-
wastedBytesByUrl,
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export default DuplicatedJavascript;
|
|
223
|
-
export {UIStrings};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export default EfficientAnimatedContent;
|
|
2
|
-
declare class EfficientAnimatedContent extends ByteEfficiencyAudit {
|
|
3
|
-
/**
|
|
4
|
-
* Calculate rough savings percentage based on 1000 real gifs transcoded to video
|
|
5
|
-
* @param {number} bytes
|
|
6
|
-
* @return {number} rough savings percentage
|
|
7
|
-
* @see https://github.com/GoogleChrome/lighthouse/issues/4696#issuecomment-380296510 bytes
|
|
8
|
-
*/
|
|
9
|
-
static getPercentSavings(bytes: number): number;
|
|
10
|
-
/**
|
|
11
|
-
* @param {LH.Artifacts} artifacts
|
|
12
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
13
|
-
* @return {import('./byte-efficiency-audit.js').ByteEfficiencyProduct}
|
|
14
|
-
*/
|
|
15
|
-
static audit_(artifacts: LH.Artifacts, networkRecords: Array<LH.Artifacts.NetworkRequest>): import("./byte-efficiency-audit.js").ByteEfficiencyProduct;
|
|
16
|
-
}
|
|
17
|
-
export namespace UIStrings {
|
|
18
|
-
let title: string;
|
|
19
|
-
let description: string;
|
|
20
|
-
}
|
|
21
|
-
import { ByteEfficiencyAudit } from './byte-efficiency-audit.js';
|
|
22
|
-
//# sourceMappingURL=efficient-animated-content.d.ts.map
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2018 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
/*
|
|
7
|
-
* @fileoverview Audit a page to ensure that videos are used instead of animated gifs
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {NetworkRequest} from '../../lib/network-request.js';
|
|
12
|
-
import {ByteEfficiencyAudit} from './byte-efficiency-audit.js';
|
|
13
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
14
|
-
|
|
15
|
-
const UIStrings = {
|
|
16
|
-
/** Imperative title of a Lighthouse audit that tells the user to use video formats rather than animated GIFs, which are wasteful. This is displayed in a list of audit titles that Lighthouse generates. */
|
|
17
|
-
title: 'Use video formats for animated content',
|
|
18
|
-
/** Description of a Lighthouse audit that tells the user *why* they should use video instead of GIF format for delivering animated content. 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. */
|
|
19
|
-
description: 'Large GIFs are inefficient for delivering animated content. Consider using ' +
|
|
20
|
-
'MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save ' +
|
|
21
|
-
'network bytes. [Learn more about efficient video formats](https://developer.chrome.com/docs/lighthouse/performance/efficient-animated-content/)',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
25
|
-
|
|
26
|
-
// If GIFs are above this size, we'll flag them
|
|
27
|
-
// See https://github.com/GoogleChrome/lighthouse/pull/4885#discussion_r178406623 and https://github.com/GoogleChrome/lighthouse/issues/4696#issuecomment-370979920
|
|
28
|
-
const GIF_BYTE_THRESHOLD = 100 * 1024;
|
|
29
|
-
|
|
30
|
-
class EfficientAnimatedContent extends ByteEfficiencyAudit {
|
|
31
|
-
/**
|
|
32
|
-
* @return {LH.Audit.Meta}
|
|
33
|
-
*/
|
|
34
|
-
static get meta() {
|
|
35
|
-
return {
|
|
36
|
-
id: 'efficient-animated-content',
|
|
37
|
-
title: str_(UIStrings.title),
|
|
38
|
-
description: str_(UIStrings.description),
|
|
39
|
-
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
40
|
-
guidanceLevel: 3,
|
|
41
|
-
requiredArtifacts: ['DevtoolsLog', 'Trace', 'GatherContext', 'URL', 'SourceMaps'],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Calculate rough savings percentage based on 1000 real gifs transcoded to video
|
|
47
|
-
* @param {number} bytes
|
|
48
|
-
* @return {number} rough savings percentage
|
|
49
|
-
* @see https://github.com/GoogleChrome/lighthouse/issues/4696#issuecomment-380296510 bytes
|
|
50
|
-
*/
|
|
51
|
-
static getPercentSavings(bytes) {
|
|
52
|
-
return Math.round((29.1 * Math.log10(bytes) - 100.7)) / 100;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @param {LH.Artifacts} artifacts
|
|
57
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
58
|
-
* @return {import('./byte-efficiency-audit.js').ByteEfficiencyProduct}
|
|
59
|
-
*/
|
|
60
|
-
static audit_(artifacts, networkRecords) {
|
|
61
|
-
const unoptimizedContent = networkRecords.filter(
|
|
62
|
-
record => record.mimeType === 'image/gif' &&
|
|
63
|
-
record.resourceType === NetworkRequest.TYPES.Image &&
|
|
64
|
-
(record.resourceSize || 0) > GIF_BYTE_THRESHOLD
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
/** @type {Array<{url: string, totalBytes: number, wastedBytes: number}>}*/
|
|
68
|
-
const items = unoptimizedContent.map(record => {
|
|
69
|
-
const resourceSize = record.resourceSize || 0;
|
|
70
|
-
return {
|
|
71
|
-
url: record.url,
|
|
72
|
-
totalBytes: resourceSize,
|
|
73
|
-
wastedBytes: Math.round(resourceSize *
|
|
74
|
-
EfficientAnimatedContent.getPercentSavings(resourceSize)),
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
/** @type {LH.Audit.Details.Opportunity['headings']} */
|
|
79
|
-
const headings = [
|
|
80
|
-
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
81
|
-
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnResourceSize)},
|
|
82
|
-
{key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
items,
|
|
87
|
-
headings,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export default EfficientAnimatedContent;
|
|
93
|
-
export {UIStrings};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export default LegacyJavascript;
|
|
2
|
-
export type ByteEfficiencyProduct = import("./byte-efficiency-audit.js").ByteEfficiencyProduct;
|
|
3
|
-
export type Item = LH.Audit.ByteEfficiencyItem & {
|
|
4
|
-
subItems: {
|
|
5
|
-
type: "subitems";
|
|
6
|
-
items: SubItem[];
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
export type SubItem = {
|
|
10
|
-
signal: string;
|
|
11
|
-
location: LH.Audit.Details.SourceLocationValue;
|
|
12
|
-
};
|
|
13
|
-
declare class LegacyJavascript extends ByteEfficiencyAudit {
|
|
14
|
-
/**
|
|
15
|
-
* @param {LH.Artifacts} artifacts
|
|
16
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
17
|
-
* @param {LH.Audit.Context} context
|
|
18
|
-
* @return {Promise<ByteEfficiencyProduct>}
|
|
19
|
-
*/
|
|
20
|
-
static audit_(artifacts: LH.Artifacts, networkRecords: Array<LH.Artifacts.NetworkRequest>, context: LH.Audit.Context): Promise<ByteEfficiencyProduct>;
|
|
21
|
-
}
|
|
22
|
-
export namespace UIStrings {
|
|
23
|
-
let title: string;
|
|
24
|
-
let description: string;
|
|
25
|
-
let detectedCoreJs2Warning: string;
|
|
26
|
-
}
|
|
27
|
-
import { ByteEfficiencyAudit } from './byte-efficiency-audit.js';
|
|
28
|
-
//# sourceMappingURL=legacy-javascript.d.ts.map
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2020 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @fileoverview Identifies polyfills and transforms that should not be present if needing to support only Baseline browsers.
|
|
9
|
-
* @see https://docs.google.com/document/d/1ItjJwAd6e0Ts6yMbvh8TN3BBh_sAd58rYE1whnpuxaA/edit Design document (old, based on module/nomodule pattern)
|
|
10
|
-
* @see https://docs.google.com/spreadsheets/d/1z28Au8wo8-c2UsM2lDVEOJcI3jOkb2c951xEBqzBKCc/edit?usp=sharing Legacy babel transforms / polyfills
|
|
11
|
-
* ./core/scripts/legacy-javascript - verification tool.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/** @typedef {import('./byte-efficiency-audit.js').ByteEfficiencyProduct} ByteEfficiencyProduct */
|
|
15
|
-
/** @typedef {LH.Audit.ByteEfficiencyItem & {subItems: {type: 'subitems', items: SubItem[]}}} Item */
|
|
16
|
-
/** @typedef {{signal: string, location: LH.Audit.Details.SourceLocationValue}} SubItem */
|
|
17
|
-
|
|
18
|
-
import {ByteEfficiencyAudit} from './byte-efficiency-audit.js';
|
|
19
|
-
import {EntityClassification} from '../../computed/entity-classification.js';
|
|
20
|
-
import {JSBundles} from '../../computed/js-bundles.js';
|
|
21
|
-
import * as i18n from '../../lib/i18n/i18n.js';
|
|
22
|
-
import {estimateCompressionRatioForContent} from '../../lib/script-helpers.js';
|
|
23
|
-
import {detectLegacyJavaScript} from '../../lib/legacy-javascript/legacy-javascript.js';
|
|
24
|
-
|
|
25
|
-
const UIStrings = {
|
|
26
|
-
/** Title of a Lighthouse audit that tells the user about legacy polyfills and transforms used on the page. This is displayed in a list of audit titles that Lighthouse generates. */
|
|
27
|
-
title: 'Avoid serving legacy JavaScript to modern browsers',
|
|
28
|
-
// TODO: developer.chrome.com article. this codelab is good starting place: https://web.dev/articles/codelab-serve-modern-code
|
|
29
|
-
/** Description of a Lighthouse audit that tells the user about old JavaScript that is no longer needed. 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. */
|
|
30
|
-
description: 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\'t necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/baseline) features, unless you know you must support legacy browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)',
|
|
31
|
-
/** Warning text that an outdated version of the library "core-js" was found, and the developer should upgrade. */
|
|
32
|
-
// eslint-disable-next-line max-len
|
|
33
|
-
detectedCoreJs2Warning: 'Version 2 of core-js was detected on the page. You should upgrade to version 3 for many performance improvements.',
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
37
|
-
|
|
38
|
-
class LegacyJavascript extends ByteEfficiencyAudit {
|
|
39
|
-
/**
|
|
40
|
-
* @return {LH.Audit.Meta}
|
|
41
|
-
*/
|
|
42
|
-
static get meta() {
|
|
43
|
-
return {
|
|
44
|
-
id: 'legacy-javascript',
|
|
45
|
-
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
46
|
-
description: str_(UIStrings.description),
|
|
47
|
-
title: str_(UIStrings.title),
|
|
48
|
-
guidanceLevel: 2,
|
|
49
|
-
requiredArtifacts: ['DevtoolsLog', 'Trace', 'Scripts', 'SourceMaps',
|
|
50
|
-
'GatherContext', 'URL'],
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @param {LH.Artifacts} artifacts
|
|
56
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
57
|
-
* @param {LH.Audit.Context} context
|
|
58
|
-
* @return {Promise<ByteEfficiencyProduct>}
|
|
59
|
-
*/
|
|
60
|
-
static async audit_(artifacts, networkRecords, context) {
|
|
61
|
-
const devtoolsLog = artifacts.DevtoolsLog;
|
|
62
|
-
const classifiedEntities = await EntityClassification.request(
|
|
63
|
-
{URL: artifacts.URL, devtoolsLog}, context);
|
|
64
|
-
|
|
65
|
-
const bundles = await JSBundles.request(artifacts, context);
|
|
66
|
-
|
|
67
|
-
/** @type {Item[]} */
|
|
68
|
-
const items = [];
|
|
69
|
-
|
|
70
|
-
/** @type {Map<string, number>} */
|
|
71
|
-
const compressionRatioByUrl = new Map();
|
|
72
|
-
|
|
73
|
-
for (const script of artifacts.Scripts) {
|
|
74
|
-
const bundle = bundles.find(bundle => bundle.script.scriptId === script.scriptId);
|
|
75
|
-
const {matches, estimatedByteSavings} =
|
|
76
|
-
detectLegacyJavaScript(script.content ?? '', bundle?.map ?? null);
|
|
77
|
-
if (matches.length === 0) continue;
|
|
78
|
-
|
|
79
|
-
const compressionRatio = estimateCompressionRatioForContent(
|
|
80
|
-
compressionRatioByUrl, script.url, artifacts, networkRecords);
|
|
81
|
-
const wastedBytes = Math.round(estimatedByteSavings * compressionRatio);
|
|
82
|
-
/** @type {typeof items[number]} */
|
|
83
|
-
const item = {
|
|
84
|
-
url: script.url,
|
|
85
|
-
wastedBytes,
|
|
86
|
-
subItems: {
|
|
87
|
-
type: 'subitems',
|
|
88
|
-
items: [],
|
|
89
|
-
},
|
|
90
|
-
// Not needed, but keeps typescript happy.
|
|
91
|
-
totalBytes: 0,
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
for (const match of matches) {
|
|
95
|
-
const {name, line, column} = match;
|
|
96
|
-
/** @type {SubItem} */
|
|
97
|
-
const subItem = {
|
|
98
|
-
signal: name,
|
|
99
|
-
location: ByteEfficiencyAudit.makeSourceLocation(script.url, line, column, bundle),
|
|
100
|
-
};
|
|
101
|
-
item.subItems.items.push(subItem);
|
|
102
|
-
}
|
|
103
|
-
items.push(item);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const warnings = [];
|
|
107
|
-
for (const bundle of bundles) {
|
|
108
|
-
if (classifiedEntities.isFirstParty(bundle.script.url)) {
|
|
109
|
-
if (bundle.rawMap.sources.some(s => s.match(/node_modules\/core-js\/modules\/es[67]/))) {
|
|
110
|
-
warnings.push(str_(UIStrings.detectedCoreJs2Warning));
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** @type {Map<string, number>} */
|
|
117
|
-
const wastedBytesByUrl = new Map();
|
|
118
|
-
for (const item of items) {
|
|
119
|
-
// Only estimate savings if first party code has legacy code.
|
|
120
|
-
if (classifiedEntities.isFirstParty(item.url)) {
|
|
121
|
-
wastedBytesByUrl.set(item.url, item.wastedBytes);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** @type {LH.Audit.Details.TableColumnHeading[]} */
|
|
126
|
-
const headings = [
|
|
127
|
-
/* eslint-disable max-len */
|
|
128
|
-
{key: 'url', valueType: 'url', subItemsHeading: {key: 'location', valueType: 'source-location'}, label: str_(i18n.UIStrings.columnURL)},
|
|
129
|
-
{key: null, valueType: 'code', subItemsHeading: {key: 'signal'}, label: ''},
|
|
130
|
-
{key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
|
|
131
|
-
/* eslint-enable max-len */
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
items,
|
|
136
|
-
headings,
|
|
137
|
-
wastedBytesByUrl,
|
|
138
|
-
warnings,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export default LegacyJavascript;
|
|
144
|
-
export {UIStrings};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export default ModernImageFormats;
|
|
2
|
-
declare class ModernImageFormats extends ByteEfficiencyAudit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {{naturalWidth: number, naturalHeight: number}} imageElement
|
|
5
|
-
* @return {number}
|
|
6
|
-
*/
|
|
7
|
-
static estimateWebPSizeFromDimensions(imageElement: {
|
|
8
|
-
naturalWidth: number;
|
|
9
|
-
naturalHeight: number;
|
|
10
|
-
}): number;
|
|
11
|
-
/**
|
|
12
|
-
* @param {{naturalWidth: number, naturalHeight: number}} imageElement
|
|
13
|
-
* @return {number}
|
|
14
|
-
*/
|
|
15
|
-
static estimateAvifSizeFromDimensions(imageElement: {
|
|
16
|
-
naturalWidth: number;
|
|
17
|
-
naturalHeight: number;
|
|
18
|
-
}): number;
|
|
19
|
-
/**
|
|
20
|
-
* @param {{jpegSize: number | undefined, webpSize: number | undefined}} otherFormatSizes
|
|
21
|
-
* @return {number|undefined}
|
|
22
|
-
*/
|
|
23
|
-
static estimateAvifSizeFromWebPAndJpegEstimates(otherFormatSizes: {
|
|
24
|
-
jpegSize: number | undefined;
|
|
25
|
-
webpSize: number | undefined;
|
|
26
|
-
}): number | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* @param {LH.Artifacts} artifacts
|
|
29
|
-
* @return {import('./byte-efficiency-audit.js').ByteEfficiencyProduct}
|
|
30
|
-
*/
|
|
31
|
-
static audit_(artifacts: LH.Artifacts): import("./byte-efficiency-audit.js").ByteEfficiencyProduct;
|
|
32
|
-
}
|
|
33
|
-
export namespace UIStrings {
|
|
34
|
-
let title: string;
|
|
35
|
-
let description: string;
|
|
36
|
-
}
|
|
37
|
-
import { ByteEfficiencyAudit } from './byte-efficiency-audit.js';
|
|
38
|
-
//# sourceMappingURL=modern-image-formats.d.ts.map
|