lighthouse 11.4.0 → 11.5.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/test/smokehouse/__snapshots__/report-assert-test.js.snap +14 -4
- package/cli/test/smokehouse/core-tests.js +2 -0
- package/core/audits/audit.d.ts +5 -0
- package/core/audits/audit.js +46 -2
- package/core/audits/bf-cache.js +1 -1
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -1
- package/core/audits/byte-efficiency/legacy-javascript.js +13 -2
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +5 -4
- package/core/audits/byte-efficiency/render-blocking-resources.js +15 -9
- package/core/audits/byte-efficiency/unused-css-rules.js +1 -1
- package/core/audits/byte-efficiency/unused-javascript.js +1 -1
- package/core/audits/layout-shift-elements.js +1 -1
- package/core/audits/layout-shifts.d.ts +33 -0
- package/core/audits/layout-shifts.js +158 -0
- package/core/audits/prioritize-lcp-image.js +1 -1
- package/core/audits/unsized-images.js +1 -1
- package/core/audits/viewport.js +10 -0
- package/core/computed/metrics/cumulative-layout-shift.d.ts +20 -1
- package/core/computed/metrics/cumulative-layout-shift.js +74 -4
- package/core/computed/trace-engine-result.d.ts +40 -0
- package/core/computed/trace-engine-result.js +69 -0
- package/core/computed/unused-css.js +4 -4
- package/core/computed/viewport-meta.d.ts +4 -0
- package/core/computed/viewport-meta.js +6 -1
- package/core/config/default-config.js +4 -1
- package/core/config/metrics-to-audits.js +1 -0
- package/core/gather/driver/target-manager.js +10 -1
- package/core/gather/driver/wait-for-condition.js +1 -1
- package/core/gather/gatherers/dobetterweb/response-compression.js +1 -12
- package/core/gather/gatherers/root-causes.d.ts +20 -0
- package/core/gather/gatherers/root-causes.js +133 -0
- package/core/gather/gatherers/trace-elements.d.ts +38 -7
- package/core/gather/gatherers/trace-elements.js +113 -34
- package/core/gather/gatherers/trace.js +6 -3
- package/core/gather/navigation-runner.js +1 -1
- package/core/gather/session.js +16 -3
- package/core/lib/i18n/i18n.js +2 -0
- package/core/lib/lighthouse-compatibility.js +4 -0
- package/core/lib/network-request.js +10 -2
- package/core/lib/polyfill-dom-rect.d.ts +2 -0
- package/core/lib/polyfill-dom-rect.js +111 -0
- package/core/lib/trace-engine.d.ts +7 -0
- package/core/lib/trace-engine.js +19 -0
- package/core/scripts/download-chrome.sh +17 -0
- package/dist/report/bundle.esm.js +14 -10
- package/dist/report/flow.js +15 -11
- package/dist/report/standalone.js +13 -9
- package/flow-report/src/i18n/i18n.d.ts +2 -0
- package/package.json +5 -4
- package/report/assets/styles.css +9 -5
- package/report/renderer/category-renderer.d.ts +5 -12
- package/report/renderer/category-renderer.js +18 -18
- package/report/renderer/components.js +1 -1
- package/report/renderer/performance-category-renderer.d.ts +2 -1
- package/report/renderer/performance-category-renderer.js +90 -69
- package/report/renderer/pwa-category-renderer.js +11 -2
- package/report/renderer/report-utils.d.ts +1 -0
- package/report/renderer/report-utils.js +3 -0
- package/shared/localization/locales/en-US.json +27 -0
- package/shared/localization/locales/en-XL.json +27 -0
- package/types/artifacts.d.ts +10 -1
- package/types/audit.d.ts +9 -1
- package/types/config.d.ts +1 -0
- package/types/lhr/audit-result.d.ts +1 -7
- package/types/trace-engine.d.ts +1516 -0
|
@@ -211,73 +211,103 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
|
|
|
211
211
|
filmstripEl && timelineEl.append(filmstripEl);
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
const allInsights = category.auditRefs
|
|
215
|
+
.filter(audit => this._isPerformanceInsight(audit))
|
|
216
|
+
.map(auditRef => {
|
|
217
|
+
const {overallImpact, overallLinearImpact} = this.overallImpact(auditRef, metricAudits);
|
|
218
|
+
const guidanceLevel = auditRef.result.guidanceLevel || 1;
|
|
219
|
+
const auditEl = this.renderAudit(auditRef);
|
|
220
|
+
|
|
221
|
+
return {auditRef, auditEl, overallImpact, overallLinearImpact, guidanceLevel};
|
|
222
|
+
});
|
|
219
223
|
|
|
220
224
|
// Diagnostics
|
|
221
|
-
const diagnosticAudits =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const auditImpacts = [];
|
|
227
|
-
diagnosticAudits.forEach(audit => {
|
|
228
|
-
const {
|
|
229
|
-
overallImpact: overallImpact,
|
|
230
|
-
overallLinearImpact: overallLinearImpact,
|
|
231
|
-
} = this.overallImpact(audit, metricAudits);
|
|
232
|
-
const guidanceLevel = audit.result.guidanceLevel ?? 1;
|
|
233
|
-
auditImpacts.push({auditRef: audit, overallImpact, overallLinearImpact, guidanceLevel});
|
|
234
|
-
});
|
|
225
|
+
const diagnosticAudits = allInsights
|
|
226
|
+
.filter(audit => !ReportUtils.showAsPassed(audit.auditRef.result));
|
|
227
|
+
|
|
228
|
+
const passedAudits = allInsights
|
|
229
|
+
.filter(audit => ReportUtils.showAsPassed(audit.auditRef.result));
|
|
235
230
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return b.overallImpact * b.guidanceLevel - a.overallImpact * a.guidanceLevel;
|
|
231
|
+
const [groupEl, footerEl] = this.renderAuditGroup(groups['diagnostics']);
|
|
232
|
+
groupEl.classList.add('lh-audit-group--diagnostics');
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @param {string} acronym
|
|
236
|
+
*/
|
|
237
|
+
function refreshFilteredAudits(acronym) {
|
|
238
|
+
for (const audit of allInsights) {
|
|
239
|
+
if (acronym === 'All') {
|
|
240
|
+
audit.auditEl.hidden = false;
|
|
241
|
+
} else {
|
|
242
|
+
const shouldHide = audit.auditRef.result.metricSavings?.[acronym] === undefined;
|
|
243
|
+
audit.auditEl.hidden = shouldHide;
|
|
244
|
+
}
|
|
251
245
|
}
|
|
252
246
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
a
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
247
|
+
diagnosticAudits.sort((a, b) => {
|
|
248
|
+
// Performance diagnostics should only have score display modes of "informative" and "metricSavings"
|
|
249
|
+
// If the score display mode is "metricSavings", the `score` will be a coarse approximation of the overall impact.
|
|
250
|
+
// Therefore, it makes sense to sort audits by score first to ensure visual clarity with the score icons.
|
|
251
|
+
const scoreA = a.auditRef.result.score || 0;
|
|
252
|
+
const scoreB = b.auditRef.result.score || 0;
|
|
253
|
+
if (scoreA !== scoreB) return scoreA - scoreB;
|
|
254
|
+
|
|
255
|
+
// If there is a metric filter applied, we should sort by the impact to that specific metric.
|
|
256
|
+
if (acronym !== 'All') {
|
|
257
|
+
const aSavings = a.auditRef.result.metricSavings?.[acronym] ?? -1;
|
|
258
|
+
const bSavings = b.auditRef.result.metricSavings?.[acronym] ?? -1;
|
|
259
|
+
if (aSavings !== bSavings) return bSavings - aSavings;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Overall impact is the estimated improvement to the performance score
|
|
263
|
+
if (a.overallImpact !== b.overallImpact) {
|
|
264
|
+
return b.overallImpact * b.guidanceLevel - a.overallImpact * a.guidanceLevel;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Fall back to the linear impact if the normal impact is rounded down to 0
|
|
268
|
+
if (
|
|
269
|
+
a.overallImpact === 0 && b.overallImpact === 0 &&
|
|
270
|
+
a.overallLinearImpact !== b.overallLinearImpact
|
|
271
|
+
) {
|
|
272
|
+
return b.overallLinearImpact * b.guidanceLevel - a.overallLinearImpact * a.guidanceLevel;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Audits that have no estimated savings should be prioritized by the guidance level
|
|
276
|
+
return b.guidanceLevel - a.guidanceLevel;
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
for (const audit of diagnosticAudits) {
|
|
280
|
+
groupEl.insertBefore(audit.auditEl, footerEl);
|
|
259
281
|
}
|
|
282
|
+
}
|
|
260
283
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
284
|
+
/** @type {Set<string>} */
|
|
285
|
+
const filterableMetricAcronyms = new Set();
|
|
286
|
+
for (const audit of diagnosticAudits) {
|
|
287
|
+
const metricSavings = audit.auditRef.result.metricSavings || {};
|
|
288
|
+
for (const [key, value] of Object.entries(metricSavings)) {
|
|
289
|
+
if (typeof value === 'number') filterableMetricAcronyms.add(key);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
264
292
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
293
|
+
const filterableMetrics =
|
|
294
|
+
metricAudits.filter(a => a.acronym && filterableMetricAcronyms.has(a.acronym));
|
|
295
|
+
|
|
296
|
+
// TODO: only add if there are opportunities & diagnostics rendered.
|
|
297
|
+
if (filterableMetrics.length) {
|
|
298
|
+
this.renderMetricAuditFilter(filterableMetrics, element, refreshFilteredAudits);
|
|
270
299
|
}
|
|
271
300
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
301
|
+
refreshFilteredAudits('All');
|
|
302
|
+
|
|
303
|
+
if (diagnosticAudits.length) {
|
|
304
|
+
element.append(groupEl);
|
|
305
|
+
}
|
|
276
306
|
|
|
277
307
|
if (!passedAudits.length) return element;
|
|
278
308
|
|
|
279
309
|
const clumpOpts = {
|
|
280
|
-
|
|
310
|
+
auditRefsOrEls: passedAudits.map(audit => audit.auditEl),
|
|
281
311
|
groupDefinitions: groups,
|
|
282
312
|
};
|
|
283
313
|
const passedElem = this.renderClump('passed', clumpOpts);
|
|
@@ -318,16 +348,17 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
|
|
|
318
348
|
* Render the control to filter the audits by metric. The filtering is done at runtime by CSS only
|
|
319
349
|
* @param {LH.ReportResult.AuditRef[]} filterableMetrics
|
|
320
350
|
* @param {HTMLDivElement} categoryEl
|
|
351
|
+
* @param {(acronym: string) => void} onFilterChange
|
|
321
352
|
*/
|
|
322
|
-
renderMetricAuditFilter(filterableMetrics, categoryEl) {
|
|
353
|
+
renderMetricAuditFilter(filterableMetrics, categoryEl, onFilterChange) {
|
|
323
354
|
const metricFilterEl = this.dom.createElement('div', 'lh-metricfilter');
|
|
324
355
|
const textEl = this.dom.createChildOf(metricFilterEl, 'span', 'lh-metricfilter__text');
|
|
325
356
|
textEl.textContent = Globals.strings.showRelevantAudits;
|
|
326
357
|
|
|
327
|
-
const filterChoices =
|
|
328
|
-
({acronym: 'All'}),
|
|
358
|
+
const filterChoices = [
|
|
359
|
+
/** @type {const} */ ({acronym: 'All', id: 'All'}),
|
|
329
360
|
...filterableMetrics,
|
|
330
|
-
]
|
|
361
|
+
];
|
|
331
362
|
|
|
332
363
|
// Form labels need to reference unique IDs, but multiple reports rendered in the same DOM (eg PSI)
|
|
333
364
|
// would mean ID conflict. To address this, we 'scope' these radio inputs with a unique suffix.
|
|
@@ -341,7 +372,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
|
|
|
341
372
|
|
|
342
373
|
const labelEl = this.dom.createChildOf(metricFilterEl, 'label', 'lh-metricfilter__label');
|
|
343
374
|
labelEl.htmlFor = elemId;
|
|
344
|
-
labelEl.title = metric.result
|
|
375
|
+
labelEl.title = 'result' in metric ? metric.result.title : '';
|
|
345
376
|
labelEl.textContent = metric.acronym || metric.id;
|
|
346
377
|
|
|
347
378
|
if (metric.acronym === 'All') {
|
|
@@ -357,17 +388,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
|
|
|
357
388
|
}
|
|
358
389
|
categoryEl.classList.toggle('lh-category--filtered', metric.acronym !== 'All');
|
|
359
390
|
|
|
360
|
-
|
|
361
|
-
if (metric.acronym === 'All') {
|
|
362
|
-
perfAuditEl.hidden = false;
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
perfAuditEl.hidden = true;
|
|
367
|
-
if (metric.relevantAudits && metric.relevantAudits.includes(perfAuditEl.id)) {
|
|
368
|
-
perfAuditEl.hidden = false;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
391
|
+
onFilterChange(metric.acronym || 'All');
|
|
371
392
|
|
|
372
393
|
// Hide groups/clumps if all child audits are also hidden.
|
|
373
394
|
const groupEls = categoryEl.querySelectorAll('div.lh-audit-group, details.lh-audit-group');
|
|
@@ -17,6 +17,12 @@ export class PwaCategoryRenderer extends CategoryRenderer {
|
|
|
17
17
|
render(category, groupDefinitions = {}) {
|
|
18
18
|
const categoryElem = this.dom.createElement('div', 'lh-category');
|
|
19
19
|
categoryElem.id = category.id;
|
|
20
|
+
// Deprecation warning banner.
|
|
21
|
+
const pwaMessageContainer = this.dom.createComponent('warningsToplevel');
|
|
22
|
+
const pwaMessageEl = this.dom.find('.lh-warnings__msg', pwaMessageContainer);
|
|
23
|
+
pwaMessageEl.append(this.dom.convertMarkdownLinkSnippets(Globals.strings.pwaRemovalMessage));
|
|
24
|
+
|
|
25
|
+
categoryElem.append(pwaMessageContainer);
|
|
20
26
|
categoryElem.append(this.renderCategoryHeader(category, groupDefinitions));
|
|
21
27
|
|
|
22
28
|
const auditRefs = category.auditRefs;
|
|
@@ -29,8 +35,11 @@ export class PwaCategoryRenderer extends CategoryRenderer {
|
|
|
29
35
|
|
|
30
36
|
// Manual audits are still in a manual clump.
|
|
31
37
|
const manualAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode === 'manual');
|
|
32
|
-
const manualElem = this.renderClump('manual',
|
|
33
|
-
|
|
38
|
+
const manualElem = this.renderClump('manual', {
|
|
39
|
+
auditRefsOrEls: manualAuditRefs,
|
|
40
|
+
description: category.manualDescription,
|
|
41
|
+
openByDefault: true,
|
|
42
|
+
});
|
|
34
43
|
categoryElem.append(manualElem);
|
|
35
44
|
|
|
36
45
|
return categoryElem;
|
|
@@ -476,6 +476,9 @@ const UIStrings = {
|
|
|
476
476
|
openInANewTabTooltip: 'Open in a new tab',
|
|
477
477
|
/** Generic category name for all resources that could not be attributed to a 1st or 3rd party entity. */
|
|
478
478
|
unattributable: 'Unattributable',
|
|
479
|
+
|
|
480
|
+
/** Message communicating the removal of the PWA category. */
|
|
481
|
+
pwaRemovalMessage: 'Alongside [Chrome’s updated Installability Criteria](https://developer.chrome.com/blog/update-install-criteria), Lighthouse will be deprecating the PWA category in a future release. Please refer to the [updated PWA documentation](https://developer.chrome.com/docs/devtools/progressive-web-apps/) for future PWA testing.',
|
|
479
482
|
};
|
|
480
483
|
|
|
481
484
|
export {
|
|
@@ -1166,6 +1166,30 @@
|
|
|
1166
1166
|
"core/audits/layout-shift-elements.js | title": {
|
|
1167
1167
|
"message": "Avoid large layout shifts"
|
|
1168
1168
|
},
|
|
1169
|
+
"core/audits/layout-shifts.js | columnScore": {
|
|
1170
|
+
"message": "Layout shift score"
|
|
1171
|
+
},
|
|
1172
|
+
"core/audits/layout-shifts.js | description": {
|
|
1173
|
+
"message": "These are the largest layout shifts observed on the page. Each table item represents a single layout shift, and shows the element that shifted the most. Below each item are possible root causes that led to the layout shift. Some of these layout shifts may not be included in the CLS metric value due to [windowing](https://web.dev/articles/cls#what_is_cls). [Learn how to improve CLS](https://web.dev/articles/optimize-cls)"
|
|
1174
|
+
},
|
|
1175
|
+
"core/audits/layout-shifts.js | displayValueShiftsFound": {
|
|
1176
|
+
"message": "{shiftCount, plural, =1 {1 layout shift found} other {# layout shifts found}}"
|
|
1177
|
+
},
|
|
1178
|
+
"core/audits/layout-shifts.js | rootCauseFontChanges": {
|
|
1179
|
+
"message": "Web font loaded"
|
|
1180
|
+
},
|
|
1181
|
+
"core/audits/layout-shifts.js | rootCauseInjectedIframe": {
|
|
1182
|
+
"message": "Injected iframe"
|
|
1183
|
+
},
|
|
1184
|
+
"core/audits/layout-shifts.js | rootCauseRenderBlockingRequest": {
|
|
1185
|
+
"message": "A late network request adjusted the page layout"
|
|
1186
|
+
},
|
|
1187
|
+
"core/audits/layout-shifts.js | rootCauseUnsizedMedia": {
|
|
1188
|
+
"message": "Media element lacking an explicit size"
|
|
1189
|
+
},
|
|
1190
|
+
"core/audits/layout-shifts.js | title": {
|
|
1191
|
+
"message": "Avoid large layout shifts"
|
|
1192
|
+
},
|
|
1169
1193
|
"core/audits/lcp-lazy-loaded.js | description": {
|
|
1170
1194
|
"message": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/articles/lcp-lazy-loading)."
|
|
1171
1195
|
},
|
|
@@ -3374,6 +3398,9 @@
|
|
|
3374
3398
|
"report/renderer/report-utils.js | passedAuditsGroupTitle": {
|
|
3375
3399
|
"message": "Passed audits"
|
|
3376
3400
|
},
|
|
3401
|
+
"report/renderer/report-utils.js | pwaRemovalMessage": {
|
|
3402
|
+
"message": "Alongside [Chrome’s updated Installability Criteria](https://developer.chrome.com/blog/update-install-criteria), Lighthouse will be deprecating the PWA category in a future release. Please refer to the [updated PWA documentation](https://developer.chrome.com/docs/devtools/progressive-web-apps/) for future PWA testing."
|
|
3403
|
+
},
|
|
3377
3404
|
"report/renderer/report-utils.js | runtimeAnalysisWindow": {
|
|
3378
3405
|
"message": "Initial page load"
|
|
3379
3406
|
},
|
|
@@ -1166,6 +1166,30 @@
|
|
|
1166
1166
|
"core/audits/layout-shift-elements.js | title": {
|
|
1167
1167
|
"message": "Âv́ôíd̂ ĺâŕĝé l̂áŷóût́ ŝh́îf́t̂ś"
|
|
1168
1168
|
},
|
|
1169
|
+
"core/audits/layout-shifts.js | columnScore": {
|
|
1170
|
+
"message": "L̂áŷóût́ ŝh́îf́t̂ śĉór̂é"
|
|
1171
|
+
},
|
|
1172
|
+
"core/audits/layout-shifts.js | description": {
|
|
1173
|
+
"message": "T̂h́êśê ár̂é t̂h́ê ĺâŕĝéŝt́ l̂áŷóût́ ŝh́îf́t̂ś ôb́ŝér̂v́êd́ ôń t̂h́ê ṕâǵê. Éâćĥ t́âb́l̂é ît́êḿ r̂ép̂ŕêśêńt̂ś â śîńĝĺê ĺâýôút̂ śĥíf̂t́, âńd̂ śĥóŵś t̂h́ê él̂ém̂én̂t́ t̂h́ât́ ŝh́îf́t̂éd̂ t́ĥé m̂óŝt́. B̂él̂óŵ éâćĥ ít̂ém̂ ár̂é p̂óŝśîb́l̂é r̂óôt́ ĉáûśêś t̂h́ât́ l̂éd̂ t́ô t́ĥé l̂áŷóût́ ŝh́îf́t̂. Śôḿê óf̂ t́ĥéŝé l̂áŷóût́ ŝh́îf́t̂ś m̂áŷ ńôt́ b̂é îńĉĺûd́êd́ îń t̂h́ê ĆL̂Ś m̂ét̂ŕîć v̂ál̂úê d́ûé t̂ó [ŵín̂d́ôẃîńĝ](https://web.dev/articles/cls#what_is_cls). [Ĺêár̂ń ĥóŵ t́ô ím̂ṕr̂óv̂é ĈĹŜ](https://web.dev/articles/optimize-cls)"
|
|
1174
|
+
},
|
|
1175
|
+
"core/audits/layout-shifts.js | displayValueShiftsFound": {
|
|
1176
|
+
"message": "{shiftCount, plural, =1 {1 l̂áŷóût́ ŝh́îf́t̂ f́ôún̂d́} other {# l̂áŷóût́ ŝh́îf́t̂ś f̂óûńd̂}}"
|
|
1177
|
+
},
|
|
1178
|
+
"core/audits/layout-shifts.js | rootCauseFontChanges": {
|
|
1179
|
+
"message": "Ŵéb̂ f́ôńt̂ ĺôád̂éd̂"
|
|
1180
|
+
},
|
|
1181
|
+
"core/audits/layout-shifts.js | rootCauseInjectedIframe": {
|
|
1182
|
+
"message": "Îńĵéĉt́êd́ îf́r̂ám̂é"
|
|
1183
|
+
},
|
|
1184
|
+
"core/audits/layout-shifts.js | rootCauseRenderBlockingRequest": {
|
|
1185
|
+
"message": "Â ĺât́ê ńêt́ŵór̂ḱ r̂éq̂úêśt̂ ád̂j́ûśt̂éd̂ t́ĥé p̂áĝé l̂áŷóût́"
|
|
1186
|
+
},
|
|
1187
|
+
"core/audits/layout-shifts.js | rootCauseUnsizedMedia": {
|
|
1188
|
+
"message": "M̂éd̂íâ él̂ém̂én̂t́ l̂áĉḱîńĝ án̂ éx̂ṕl̂íĉít̂ śîźê"
|
|
1189
|
+
},
|
|
1190
|
+
"core/audits/layout-shifts.js | title": {
|
|
1191
|
+
"message": "Âv́ôíd̂ ĺâŕĝé l̂áŷóût́ ŝh́îf́t̂ś"
|
|
1192
|
+
},
|
|
1169
1193
|
"core/audits/lcp-lazy-loaded.js | description": {
|
|
1170
1194
|
"message": "Âb́ôv́ê-t́ĥé-f̂ól̂d́ îḿâǵêś t̂h́ât́ âŕê ĺâźîĺŷ ĺôád̂éd̂ ŕêńd̂ér̂ ĺât́êŕ îń t̂h́ê ṕâǵê ĺîf́êćŷćl̂é, ŵh́îćĥ ćâń d̂él̂áŷ t́ĥé l̂ár̂ǵêśt̂ ćôńt̂én̂t́f̂úl̂ ṕâín̂t́. [L̂éâŕn̂ ḿôŕê áb̂óût́ ôṕt̂ím̂ál̂ ĺâźŷ ĺôád̂ín̂ǵ](https://web.dev/articles/lcp-lazy-loading)."
|
|
1171
1195
|
},
|
|
@@ -3374,6 +3398,9 @@
|
|
|
3374
3398
|
"report/renderer/report-utils.js | passedAuditsGroupTitle": {
|
|
3375
3399
|
"message": "P̂áŝśêd́ âúd̂ít̂ś"
|
|
3376
3400
|
},
|
|
3401
|
+
"report/renderer/report-utils.js | pwaRemovalMessage": {
|
|
3402
|
+
"message": "Âĺôńĝśîd́ê [Ćĥŕôḿê’ś ûṕd̂át̂éd̂ Ín̂śt̂ál̂ĺâb́îĺît́ŷ Ćr̂ít̂ér̂íâ](https://developer.chrome.com/blog/update-install-criteria), Ĺîǵĥt́ĥóûśê ẃîĺl̂ b́ê d́êṕr̂éĉát̂ín̂ǵ t̂h́ê ṔŴÁ ĉát̂éĝór̂ý îń â f́ût́ûŕê ŕêĺêáŝé. P̂ĺêáŝé r̂éf̂ér̂ t́ô t́ĥé [ûṕd̂át̂éd̂ ṔŴÁ d̂óĉúm̂én̂t́ât́îón̂](https://developer.chrome.com/docs/devtools/progressive-web-apps/) f́ôŕ f̂út̂úr̂é P̂ẂÂ t́êśt̂ín̂ǵ."
|
|
3403
|
+
},
|
|
3377
3404
|
"report/renderer/report-utils.js | runtimeAnalysisWindow": {
|
|
3378
3405
|
"message": "Îńît́îál̂ ṕâǵê ĺôád̂"
|
|
3379
3406
|
},
|
package/types/artifacts.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ import LHResult from './lhr/lhr.js'
|
|
|
23
23
|
import Protocol from './protocol.js';
|
|
24
24
|
import Util from './utility-types.js';
|
|
25
25
|
import Audit from './audit.js';
|
|
26
|
+
import {TraceProcessor, LayoutShiftRootCauses} from './trace-engine.js';
|
|
26
27
|
|
|
27
28
|
export type Artifacts = BaseArtifacts & GathererArtifacts;
|
|
28
29
|
|
|
@@ -142,6 +143,8 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
142
143
|
ResponseCompression: {requestId: string, url: string, mimeType: string, transferSize: number, resourceSize: number, gzipSize?: number}[];
|
|
143
144
|
/** Information on fetching and the content of the /robots.txt file. */
|
|
144
145
|
RobotsTxt: {status: number|null, content: string|null, errorMessage?: string};
|
|
146
|
+
/** The result of calling the shared trace engine root cause analysis. */
|
|
147
|
+
RootCauses: Artifacts.TraceEngineRootCauses;
|
|
145
148
|
/** Information on all scripts in the page. */
|
|
146
149
|
Scripts: Artifacts.Script[];
|
|
147
150
|
/** Version information for all ServiceWorkers active after the first page load. */
|
|
@@ -559,13 +562,19 @@ declare module Artifacts {
|
|
|
559
562
|
}
|
|
560
563
|
|
|
561
564
|
interface TraceElement {
|
|
562
|
-
traceEventType: 'largest-contentful-paint'|'layout-shift'|'animation'|'responsiveness';
|
|
565
|
+
traceEventType: 'largest-contentful-paint'|'layout-shift'|'layout-shift-element'|'animation'|'responsiveness';
|
|
563
566
|
node: NodeDetails;
|
|
564
567
|
nodeId: number;
|
|
565
568
|
animations?: {name?: string, failureReasonsMask?: number, unsupportedProperties?: string[]}[];
|
|
566
569
|
type?: string;
|
|
567
570
|
}
|
|
568
571
|
|
|
572
|
+
type TraceEngineResult = TraceProcessor['data'];
|
|
573
|
+
|
|
574
|
+
interface TraceEngineRootCauses {
|
|
575
|
+
layoutShifts: Record<number, LayoutShiftRootCauses>;
|
|
576
|
+
}
|
|
577
|
+
|
|
569
578
|
interface ViewportDimensions {
|
|
570
579
|
innerWidth: number;
|
|
571
580
|
innerHeight: number;
|
package/types/audit.d.ts
CHANGED
|
@@ -20,6 +20,14 @@ declare module Audit {
|
|
|
20
20
|
export type ScoreDisplayModes = AuditResult.ScoreDisplayModes;
|
|
21
21
|
export type MetricSavings = AuditResult.MetricSavings;
|
|
22
22
|
|
|
23
|
+
export type ProductMetricSavings = {
|
|
24
|
+
FCP?: number;
|
|
25
|
+
LCP?: number;
|
|
26
|
+
TBT?: number;
|
|
27
|
+
CLS?: number;
|
|
28
|
+
INP?: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
23
31
|
type Context = Util.Immutable<{
|
|
24
32
|
/** audit options */
|
|
25
33
|
options: Record<string, any>;
|
|
@@ -87,7 +95,7 @@ declare module Audit {
|
|
|
87
95
|
/** If an audit encounters unusual execution circumstances, strings can be put in this optional array to add top-level warnings to the LHR. */
|
|
88
96
|
runWarnings?: Array<IcuMessage>;
|
|
89
97
|
/** Estimates of how much this audit affects various performance metrics. Values will be in the unit of the respective metrics. */
|
|
90
|
-
metricSavings?:
|
|
98
|
+
metricSavings?: ProductMetricSavings;
|
|
91
99
|
/** Score details including p10 and median for calculating an audit's log-normal score. */
|
|
92
100
|
scoringOptions?: ScoreOptions;
|
|
93
101
|
/** A string identifying how the score should be interpreted for display. Overrides audit meta `scoreDisplayMode` if defined. */
|
package/types/config.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {Audit} from '../core/audits/audit.js';
|
|
|
9
9
|
import {SharedFlagsSettings, ConfigSettings} from './lhr/settings.js';
|
|
10
10
|
import Gatherer from './gatherer.js';
|
|
11
11
|
import {IcuMessage} from './lhr/i18n.js';
|
|
12
|
+
import Result from './lhr/lhr.js';
|
|
12
13
|
|
|
13
14
|
interface ClassOf<T> {
|
|
14
15
|
new (): T;
|
|
@@ -31,13 +31,7 @@ interface ScoreDisplayModes {
|
|
|
31
31
|
|
|
32
32
|
type ScoreDisplayMode = ScoreDisplayModes[keyof ScoreDisplayModes];
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
LCP?: number;
|
|
36
|
-
FCP?: number;
|
|
37
|
-
CLS?: number;
|
|
38
|
-
TBT?: number;
|
|
39
|
-
INP?: number;
|
|
40
|
-
}
|
|
34
|
+
export type MetricSavings = Partial<Record<string, number>>;
|
|
41
35
|
|
|
42
36
|
/** Audit result returned in Lighthouse report. All audits offer a description and score of 0-1. */
|
|
43
37
|
export interface Result {
|