lighthouse 12.5.1-dev.20250424 → 12.5.1-dev.20250426
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/cache-insight.js +5 -6
- package/core/audits/insights/cls-culprits-insight.js +2 -2
- package/core/audits/insights/duplicated-javascript-insight.d.ts +13 -0
- package/core/audits/insights/duplicated-javascript-insight.js +35 -10
- package/core/audits/insights/insight-audit.d.ts +11 -2
- package/core/audits/insights/insight-audit.js +26 -5
- package/core/audits/insights/slow-css-selector-insight.js +2 -0
- package/core/audits/insights/third-parties-insight.d.ts +3 -2
- package/core/audits/insights/third-parties-insight.js +23 -22
- package/core/audits/layout-shifts.js +2 -2
- package/core/audits/third-party-cookies.js +1 -1
- package/core/config/default-config.js +0 -2
- package/core/config/experimental-config.js +0 -1
- package/core/gather/gatherers/trace-elements.js +3 -3
- package/dist/report/bundle.esm.js +50 -10
- package/dist/report/flow.js +53 -13
- package/dist/report/standalone.js +51 -11
- package/flow-report/src/i18n/i18n.d.ts +6 -2
- package/package.json +5 -3
- package/report/assets/styles.css +40 -0
- package/report/assets/templates.html +0 -1
- package/report/clients/standalone.js +6 -4
- package/report/renderer/components.js +2 -8
- package/report/renderer/performance-category-renderer.d.ts +26 -0
- package/report/renderer/performance-category-renderer.js +107 -0
- package/report/renderer/report-utils.d.ts +3 -1
- package/report/renderer/report-utils.js +7 -2
- package/report/renderer/topbar-features.js +1 -9
- package/shared/localization/locales/ar-XB.json +0 -3
- package/shared/localization/locales/ar.json +0 -3
- package/shared/localization/locales/bg.json +0 -3
- package/shared/localization/locales/ca.json +0 -3
- package/shared/localization/locales/cs.json +0 -3
- package/shared/localization/locales/da.json +0 -3
- package/shared/localization/locales/de.json +0 -3
- package/shared/localization/locales/el.json +0 -3
- package/shared/localization/locales/en-GB.json +0 -3
- package/shared/localization/locales/en-US.json +13 -4
- package/shared/localization/locales/en-XA.json +0 -3
- package/shared/localization/locales/en-XL.json +13 -4
- package/shared/localization/locales/es-419.json +0 -3
- package/shared/localization/locales/es.json +0 -3
- package/shared/localization/locales/fi.json +0 -3
- package/shared/localization/locales/fil.json +0 -3
- package/shared/localization/locales/fr.json +0 -3
- package/shared/localization/locales/he.json +0 -3
- package/shared/localization/locales/hi.json +0 -3
- package/shared/localization/locales/hr.json +0 -3
- package/shared/localization/locales/hu.json +0 -3
- package/shared/localization/locales/id.json +0 -3
- package/shared/localization/locales/it.json +0 -3
- package/shared/localization/locales/ja.json +0 -3
- package/shared/localization/locales/ko.json +0 -3
- package/shared/localization/locales/lt.json +0 -3
- package/shared/localization/locales/lv.json +0 -3
- package/shared/localization/locales/nl.json +0 -3
- package/shared/localization/locales/no.json +0 -3
- package/shared/localization/locales/pl.json +0 -3
- package/shared/localization/locales/pt-PT.json +0 -3
- package/shared/localization/locales/pt.json +0 -3
- package/shared/localization/locales/ro.json +0 -3
- package/shared/localization/locales/ru.json +0 -3
- package/shared/localization/locales/sk.json +0 -3
- package/shared/localization/locales/sl.json +0 -3
- package/shared/localization/locales/sr-Latn.json +0 -3
- package/shared/localization/locales/sr.json +0 -3
- package/shared/localization/locales/sv.json +0 -3
- package/shared/localization/locales/ta.json +0 -3
- package/shared/localization/locales/te.json +0 -3
- package/shared/localization/locales/th.json +0 -3
- package/shared/localization/locales/tr.json +0 -3
- package/shared/localization/locales/uk.json +0 -3
- package/shared/localization/locales/vi.json +0 -3
- package/shared/localization/locales/zh-HK.json +0 -3
- package/shared/localization/locales/zh-TW.json +0 -3
- package/shared/localization/locales/zh.json +0 -3
|
@@ -41,20 +41,19 @@ class CacheInsight extends Audit {
|
|
|
41
41
|
/* eslint-disable max-len */
|
|
42
42
|
{key: 'url', valueType: 'url', label: str_(UIStrings.requestColumn)},
|
|
43
43
|
{key: 'cacheLifetimeMs', valueType: 'ms', label: str_(UIStrings.cacheTTL), displayUnit: 'duration'},
|
|
44
|
-
{key: '
|
|
44
|
+
{key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
|
|
45
45
|
/* eslint-enable max-len */
|
|
46
46
|
];
|
|
47
|
-
// TODO: this should be sorting in the model
|
|
48
|
-
const values = insight.requests.sort((a, b) =>
|
|
49
|
-
b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength);
|
|
47
|
+
// TODO: this should be the sorting in the model (instead it sorts by transfer size...)
|
|
48
|
+
const values = insight.requests.sort((a, b) => b.wastedBytes - a.wastedBytes);
|
|
50
49
|
/** @type {LH.Audit.Details.Table['items']} */
|
|
51
50
|
const items = values.map(value => ({
|
|
52
51
|
url: value.request.args.data.url,
|
|
53
52
|
cacheLifetimeMs: value.ttl * 1000,
|
|
54
|
-
|
|
53
|
+
wastedBytes: value.wastedBytes,
|
|
55
54
|
}));
|
|
56
55
|
return Audit.makeTableDetails(headings, items, {
|
|
57
|
-
sortedBy: ['
|
|
56
|
+
sortedBy: ['wastedBytes'],
|
|
58
57
|
skipSumming: ['cacheLifetimeMs'],
|
|
59
58
|
});
|
|
60
59
|
});
|
|
@@ -58,9 +58,9 @@ class CLSCulpritsInsight extends Audit {
|
|
|
58
58
|
|
|
59
59
|
/** @type {SubItem[]} */
|
|
60
60
|
const subItems = [];
|
|
61
|
-
for (const
|
|
61
|
+
for (const unsizedImage of culprits.unsizedImages) {
|
|
62
62
|
subItems.push({
|
|
63
|
-
extra: makeNodeItemForNodeId(TraceElements, backendNodeId),
|
|
63
|
+
extra: makeNodeItemForNodeId(TraceElements, unsizedImage.backendNodeId),
|
|
64
64
|
cause: insightStr_(InsightUIStrings.unsizedImages),
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
export default DuplicatedJavaScriptInsight;
|
|
2
|
+
export type Item = LH.Audit.Details.TableItem & {
|
|
3
|
+
source: string;
|
|
4
|
+
subItems: {
|
|
5
|
+
type: "subitems";
|
|
6
|
+
items: SubItem[];
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export type SubItem = {
|
|
10
|
+
url: string;
|
|
11
|
+
sourceTransferBytes: number | LH.Audit.Details.TextValue;
|
|
12
|
+
};
|
|
13
|
+
/** @typedef {LH.Audit.Details.TableItem & {source: string, subItems: {type: 'subitems', items: SubItem[]}}} Item */
|
|
14
|
+
/** @typedef {{url: string, sourceTransferBytes: number|LH.Audit.Details.TextValue}} SubItem */
|
|
2
15
|
declare class DuplicatedJavaScriptInsight extends Audit {
|
|
3
16
|
/**
|
|
4
17
|
* @param {LH.Artifacts} artifacts
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */ // TODO: remove once implemented.
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* @license
|
|
5
3
|
* Copyright 2025 Google LLC
|
|
@@ -10,11 +8,14 @@ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Duplicate
|
|
|
10
8
|
|
|
11
9
|
import {Audit} from '../audit.js';
|
|
12
10
|
import * as i18n from '../../lib/i18n/i18n.js';
|
|
13
|
-
import {adaptInsightToAuditProduct
|
|
11
|
+
import {adaptInsightToAuditProduct} from './insight-audit.js';
|
|
14
12
|
|
|
15
13
|
// eslint-disable-next-line max-len
|
|
16
14
|
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js', UIStrings);
|
|
17
15
|
|
|
16
|
+
/** @typedef {LH.Audit.Details.TableItem & {source: string, subItems: {type: 'subitems', items: SubItem[]}}} Item */
|
|
17
|
+
/** @typedef {{url: string, sourceTransferBytes: number|LH.Audit.Details.TextValue}} SubItem */
|
|
18
|
+
|
|
18
19
|
class DuplicatedJavaScriptInsight extends Audit {
|
|
19
20
|
/**
|
|
20
21
|
* @return {LH.Audit.Meta}
|
|
@@ -26,9 +27,8 @@ class DuplicatedJavaScriptInsight extends Audit {
|
|
|
26
27
|
failureTitle: str_(UIStrings.title),
|
|
27
28
|
description: str_(UIStrings.description),
|
|
28
29
|
guidanceLevel: 2,
|
|
29
|
-
requiredArtifacts: ['Trace', '
|
|
30
|
-
|
|
31
|
-
// replacesAudits: ['duplicated-javascript'],
|
|
30
|
+
requiredArtifacts: ['Trace', 'SourceMaps'],
|
|
31
|
+
replacesAudits: ['duplicated-javascript'],
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -38,16 +38,41 @@ class DuplicatedJavaScriptInsight extends Audit {
|
|
|
38
38
|
* @return {Promise<LH.Audit.Product>}
|
|
39
39
|
*/
|
|
40
40
|
static async audit(artifacts, context) {
|
|
41
|
-
// TODO: implement.
|
|
42
41
|
return adaptInsightToAuditProduct(artifacts, context, 'DuplicatedJavaScript', (insight) => {
|
|
43
42
|
/** @type {LH.Audit.Details.Table['headings']} */
|
|
44
43
|
const headings = [
|
|
45
44
|
/* eslint-disable max-len */
|
|
45
|
+
{key: 'source', valueType: 'code', subItemsHeading: {key: 'url', valueType: 'url'}, label: str_(i18n.UIStrings.columnSource)},
|
|
46
|
+
{key: 'wastedBytes', valueType: 'bytes', subItemsHeading: {key: 'sourceTransferBytes'}, granularity: 10, label: str_(UIStrings.columnDuplicatedBytes)},
|
|
46
47
|
/* eslint-enable max-len */
|
|
47
48
|
];
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
49
|
+
|
|
50
|
+
const entries = [...insight.duplicationGroupedByNodeModules.entries()].slice(0, 10);
|
|
51
|
+
|
|
52
|
+
/** @type {Item[]} */
|
|
53
|
+
const items = entries.map(([source, data]) => {
|
|
54
|
+
/** @type {Item} */
|
|
55
|
+
const item = {
|
|
56
|
+
source,
|
|
57
|
+
wastedBytes: data.estimatedDuplicateBytes,
|
|
58
|
+
subItems: {
|
|
59
|
+
type: 'subitems',
|
|
60
|
+
items: [],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
for (const [index, {script, attributedSize}] of data.duplicates.entries()) {
|
|
65
|
+
/** @type {SubItem} */
|
|
66
|
+
const subItem = {
|
|
67
|
+
url: script.url ?? '',
|
|
68
|
+
sourceTransferBytes: index === 0 ? {type: 'text', value: '--'} : attributedSize,
|
|
69
|
+
};
|
|
70
|
+
item.subItems.items.push(subItem);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return item;
|
|
74
|
+
});
|
|
75
|
+
|
|
51
76
|
return Audit.makeTableDetails(headings, items);
|
|
52
77
|
});
|
|
53
78
|
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
+
export type CreateDetailsExtras = {
|
|
2
|
+
insights: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightSet;
|
|
3
|
+
parsedTrace: LH.Artifacts.TraceEngineResult["data"];
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* @typedef CreateDetailsExtras
|
|
7
|
+
* @property {import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet} insights
|
|
8
|
+
* @property {LH.Artifacts.TraceEngineResult['data']} parsedTrace
|
|
9
|
+
*/
|
|
1
10
|
/**
|
|
2
11
|
* @param {LH.Artifacts} artifacts
|
|
3
12
|
* @param {LH.Audit.Context} context
|
|
4
13
|
* @param {T} insightName
|
|
5
|
-
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
|
|
14
|
+
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
|
|
6
15
|
* @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
|
|
7
16
|
* @return {Promise<LH.Audit.Product>}
|
|
8
17
|
*/
|
|
9
|
-
export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T]) => LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
|
|
18
|
+
export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
|
|
10
19
|
/**
|
|
11
20
|
* @param {LH.Artifacts.TraceElement[]} traceElements
|
|
12
21
|
* @param {number|null|undefined} nodeId
|
|
@@ -9,11 +9,14 @@ import {NO_NAVIGATION} from '@paulirish/trace_engine/models/trace/types/TraceEve
|
|
|
9
9
|
import {ProcessedTrace} from '../../computed/processed-trace.js';
|
|
10
10
|
import {TraceEngineResult} from '../../computed/trace-engine-result.js';
|
|
11
11
|
import {Audit} from '../audit.js';
|
|
12
|
+
import * as i18n from '../../lib/i18n/i18n.js';
|
|
13
|
+
|
|
14
|
+
const str_ = i18n.createIcuMessageFn(import.meta.url, {});
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* @param {LH.Artifacts} artifacts
|
|
15
18
|
* @param {LH.Audit.Context} context
|
|
16
|
-
* @return {Promise<import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined>}
|
|
19
|
+
* @return {Promise<{insights: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined, parsedTrace: LH.Artifacts.TraceEngineResult['data']}>}
|
|
17
20
|
*/
|
|
18
21
|
async function getInsightSet(artifacts, context) {
|
|
19
22
|
const settings = context.settings;
|
|
@@ -24,20 +27,27 @@ async function getInsightSet(artifacts, context) {
|
|
|
24
27
|
|
|
25
28
|
const navigationId = processedTrace.timeOriginEvt.args.data?.navigationId;
|
|
26
29
|
const key = navigationId ?? NO_NAVIGATION;
|
|
30
|
+
const insights = traceEngineResult.insights.get(key);
|
|
27
31
|
|
|
28
|
-
return traceEngineResult.
|
|
32
|
+
return {insights, parsedTrace: traceEngineResult.data};
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @typedef CreateDetailsExtras
|
|
37
|
+
* @property {import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet} insights
|
|
38
|
+
* @property {LH.Artifacts.TraceEngineResult['data']} parsedTrace
|
|
39
|
+
*/
|
|
40
|
+
|
|
31
41
|
/**
|
|
32
42
|
* @param {LH.Artifacts} artifacts
|
|
33
43
|
* @param {LH.Audit.Context} context
|
|
34
44
|
* @param {T} insightName
|
|
35
|
-
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
|
|
45
|
+
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
|
|
36
46
|
* @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
|
|
37
47
|
* @return {Promise<LH.Audit.Product>}
|
|
38
48
|
*/
|
|
39
49
|
async function adaptInsightToAuditProduct(artifacts, context, insightName, createDetails) {
|
|
40
|
-
const insights = await getInsightSet(artifacts, context);
|
|
50
|
+
const {insights, parsedTrace} = await getInsightSet(artifacts, context);
|
|
41
51
|
if (!insights) {
|
|
42
52
|
return {
|
|
43
53
|
scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
|
|
@@ -54,7 +64,10 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
54
64
|
};
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
const details = createDetails(insight
|
|
67
|
+
const details = createDetails(insight, {
|
|
68
|
+
parsedTrace,
|
|
69
|
+
insights,
|
|
70
|
+
});
|
|
58
71
|
if (!details || (details.type === 'table' && details.headings.length === 0)) {
|
|
59
72
|
return {
|
|
60
73
|
scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
|
|
@@ -73,6 +86,13 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
73
86
|
metricSavings = {...metricSavings, LCP: /** @type {any} */ (0)};
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
// TODO: consider adding a `estimatedSavingsText` to InsightModel, which can capture
|
|
90
|
+
// the exact i18n string used by RPP; and include the same est. timing savings.
|
|
91
|
+
let displayValue;
|
|
92
|
+
if (insight.wastedBytes) {
|
|
93
|
+
displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes: insight.wastedBytes});
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
let score;
|
|
77
97
|
let scoreDisplayMode;
|
|
78
98
|
if (insight.state === 'fail' || insight.state === 'pass') {
|
|
@@ -89,6 +109,7 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
89
109
|
score,
|
|
90
110
|
metricSavings,
|
|
91
111
|
warnings: insight.warnings,
|
|
112
|
+
displayValue,
|
|
92
113
|
details,
|
|
93
114
|
};
|
|
94
115
|
}
|
|
@@ -13,9 +13,10 @@ export type URLSummary = {
|
|
|
13
13
|
declare class ThirdPartiesInsight extends Audit {
|
|
14
14
|
/**
|
|
15
15
|
* @param {LH.Artifacts.Entity} entity
|
|
16
|
-
* @param {import('@paulirish/trace_engine/models/trace/
|
|
17
|
-
* @return {
|
|
16
|
+
* @param {import('@paulirish/trace_engine/models/trace/extras/ThirdParties.js').URLSummary[]} urlSummaries
|
|
17
|
+
* @return {URLSummary[]}
|
|
18
18
|
*/
|
|
19
|
+
static makeSubItems(entity: LH.Artifacts.Entity, urlSummaries: import("@paulirish/trace_engine/models/trace/extras/ThirdParties.js").URLSummary[]): URLSummary[];
|
|
19
20
|
/**
|
|
20
21
|
* @param {LH.Artifacts} artifacts
|
|
21
22
|
* @param {LH.Audit.Context} context
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ThirdParties.js';
|
|
8
|
+
import {summarizeByURL} from '@paulirish/trace_engine/models/trace/extras/ThirdParties.js';
|
|
8
9
|
|
|
9
10
|
import {Audit} from '../audit.js';
|
|
10
11
|
import * as i18n from '../../lib/i18n/i18n.js';
|
|
@@ -38,21 +39,20 @@ class ThirdPartiesInsight extends Audit {
|
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* @param {LH.Artifacts.Entity} entity
|
|
41
|
-
* @param {import('@paulirish/trace_engine/models/trace/
|
|
42
|
-
* @return {
|
|
42
|
+
* @param {import('@paulirish/trace_engine/models/trace/extras/ThirdParties.js').URLSummary[]} urlSummaries
|
|
43
|
+
* @return {URLSummary[]}
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// }
|
|
45
|
+
static makeSubItems(entity, urlSummaries) {
|
|
46
|
+
urlSummaries = urlSummaries.filter(s => s.entity === entity);
|
|
47
|
+
return urlSummaries.filter(s => s.entity === entity)
|
|
48
|
+
.map(s => ({
|
|
49
|
+
url: s.url,
|
|
50
|
+
mainThreadTime: s.mainThreadTime,
|
|
51
|
+
transferSize: s.transferSize,
|
|
52
|
+
}))
|
|
53
|
+
// Sort by main thread time first, then transfer size to break ties.
|
|
54
|
+
.sort((a, b) => (b.mainThreadTime - a.mainThreadTime) || (b.transferSize - a.transferSize));
|
|
55
|
+
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* @param {LH.Artifacts} artifacts
|
|
@@ -60,8 +60,10 @@ class ThirdPartiesInsight extends Audit {
|
|
|
60
60
|
* @return {Promise<LH.Audit.Product>}
|
|
61
61
|
*/
|
|
62
62
|
static async audit(artifacts, context) {
|
|
63
|
-
return adaptInsightToAuditProduct(artifacts, context, 'ThirdParties', (insight) => {
|
|
64
|
-
const
|
|
63
|
+
return adaptInsightToAuditProduct(artifacts, context, 'ThirdParties', (insight, extras) => {
|
|
64
|
+
const urlSummaries = summarizeByURL(extras.parsedTrace, extras.insights.bounds);
|
|
65
|
+
|
|
66
|
+
const thirdPartySummaries = insight.entitySummaries
|
|
65
67
|
.filter(summary => summary.entity !== insight.firstPartyEntity || null)
|
|
66
68
|
.sort((a, b) => b.mainThreadTime - a.mainThreadTime);
|
|
67
69
|
|
|
@@ -77,13 +79,12 @@ class ThirdPartiesInsight extends Audit {
|
|
|
77
79
|
const items = thirdPartySummaries.map((summary) => {
|
|
78
80
|
return {
|
|
79
81
|
entity: summary.entity.name,
|
|
80
|
-
transferSize: summary.transferSize,
|
|
81
82
|
mainThreadTime: summary.mainThreadTime,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
transferSize: summary.transferSize,
|
|
84
|
+
subItems: {
|
|
85
|
+
type: /** @type {const} */ ('subitems'),
|
|
86
|
+
items: ThirdPartiesInsight.makeSubItems(summary.entity, urlSummaries),
|
|
87
|
+
},
|
|
87
88
|
};
|
|
88
89
|
});
|
|
89
90
|
return Audit.makeTableDetails(headings, items, {isEntityGrouped: true});
|
|
@@ -97,9 +97,9 @@ class LayoutShifts extends Audit {
|
|
|
97
97
|
/** @type {SubItem[]} */
|
|
98
98
|
const subItems = [];
|
|
99
99
|
if (rootCauses) {
|
|
100
|
-
for (const
|
|
100
|
+
for (const unsizedImage of rootCauses.unsizedImages) {
|
|
101
101
|
const element = artifacts.TraceElements.find(
|
|
102
|
-
t => t.traceEventType === 'trace-engine' && t.nodeId === backendNodeId);
|
|
102
|
+
t => t.traceEventType === 'trace-engine' && t.nodeId === unsizedImage.backendNodeId);
|
|
103
103
|
subItems.push({
|
|
104
104
|
extra: element ? Audit.makeNodeItem(element.node) : undefined,
|
|
105
105
|
cause: str_(UIStrings.rootCauseUnsizedMedia),
|
|
@@ -18,7 +18,7 @@ const UIStrings = {
|
|
|
18
18
|
/** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page uses third party cookies. */
|
|
19
19
|
failureTitle: 'Uses third-party cookies',
|
|
20
20
|
/** Description of a Lighthouse audit that tells the user why they should not use third party cookies on their 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. */
|
|
21
|
-
description: '
|
|
21
|
+
description: 'Third-party cookies may be blocked in some contexts. [Learn more about preparing for third-party cookie restrictions](https://privacysandbox.google.com/cookies/prepare/overview).',
|
|
22
22
|
/** [ICU Syntax] Label for the audit identifying the number of third-party cookies. */
|
|
23
23
|
displayValue: `{itemCount, plural,
|
|
24
24
|
=1 {1 cookie found}
|
|
@@ -326,7 +326,6 @@ const defaultConfig = {
|
|
|
326
326
|
'insights/modern-http-insight',
|
|
327
327
|
'insights/network-dependency-tree-insight',
|
|
328
328
|
'insights/render-blocking-insight',
|
|
329
|
-
'insights/slow-css-selector-insight',
|
|
330
329
|
'insights/third-parties-insight',
|
|
331
330
|
'insights/viewport-insight',
|
|
332
331
|
],
|
|
@@ -429,7 +428,6 @@ const defaultConfig = {
|
|
|
429
428
|
{id: 'modern-http-insight', weight: 0, group: 'hidden'},
|
|
430
429
|
{id: 'network-dependency-tree-insight', weight: 0, group: 'hidden'},
|
|
431
430
|
{id: 'render-blocking-insight', weight: 0, group: 'hidden'},
|
|
432
|
-
{id: 'slow-css-selector-insight', weight: 0, group: 'hidden'},
|
|
433
431
|
{id: 'third-parties-insight', weight: 0, group: 'hidden'},
|
|
434
432
|
{id: 'viewport-insight', weight: 0, group: 'hidden'},
|
|
435
433
|
|
|
@@ -42,7 +42,6 @@ const config = {
|
|
|
42
42
|
{id: 'modern-http-insight', weight: 0, group: 'insights'},
|
|
43
43
|
{id: 'network-dependency-tree-insight', weight: 0, group: 'insights'},
|
|
44
44
|
{id: 'render-blocking-insight', weight: 0, group: 'insights'},
|
|
45
|
-
{id: 'slow-css-selector-insight', weight: 0, group: 'insights'},
|
|
46
45
|
{id: 'third-parties-insight', weight: 0, group: 'insights'},
|
|
47
46
|
{id: 'viewport-insight', weight: 0, group: 'insights'},
|
|
48
47
|
],
|
|
@@ -132,15 +132,15 @@ class TraceElements extends BaseGatherer {
|
|
|
132
132
|
/** @type {number[]} */
|
|
133
133
|
const nodeIds = [];
|
|
134
134
|
recursiveObjectEnumerate(insightSet.model, (val, key) => {
|
|
135
|
-
const keys = ['nodeId', 'node_id'];
|
|
135
|
+
const keys = ['nodeId', 'node_id', 'backendNodeId'];
|
|
136
136
|
if (typeof val === 'number' && keys.includes(key)) {
|
|
137
137
|
nodeIds.push(val);
|
|
138
138
|
}
|
|
139
139
|
}, new Set());
|
|
140
140
|
|
|
141
|
-
// TODO:
|
|
141
|
+
// TODO: handle digging into Map in recursiveObjectEnumerate.
|
|
142
142
|
for (const shift of insightSet.model.CLSCulprits.shifts.values()) {
|
|
143
|
-
nodeIds.push(...shift.unsizedImages);
|
|
143
|
+
nodeIds.push(...shift.unsizedImages.map(s => s.backendNodeId));
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
return [...new Set(nodeIds)].map(id => ({nodeId: id}));
|