lighthouse 11.5.0 → 11.6.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/core/audits/layout-shifts.js +5 -2
- package/core/computed/metrics/cumulative-layout-shift.js +7 -1
- package/core/computed/trace-engine-result.d.ts +2 -16
- package/core/computed/trace-engine-result.js +12 -3
- package/core/gather/driver/wait-for-condition.js +15 -0
- package/core/gather/gatherers/root-causes.js +22 -9
- package/core/gather/gatherers/trace-elements.js +6 -2
- package/core/gather/gatherers/trace.js +2 -1
- package/core/gather/runner-helpers.js +4 -1
- package/core/lib/trace-engine.d.ts +10 -6
- package/core/lib/trace-engine.js +3 -4
- package/dist/report/bundle.esm.js +1 -1
- package/dist/report/flow.js +1 -1
- package/dist/report/standalone.js +1 -1
- package/package.json +8 -8
- package/report/renderer/report-utils.js +1 -1
- package/shared/localization/locales/ar-XB.json +45 -3
- package/shared/localization/locales/ar.json +45 -3
- package/shared/localization/locales/bg.json +45 -3
- package/shared/localization/locales/ca.json +45 -3
- package/shared/localization/locales/cs.json +45 -3
- package/shared/localization/locales/da.json +52 -10
- package/shared/localization/locales/de.json +45 -3
- package/shared/localization/locales/el.json +45 -3
- package/shared/localization/locales/en-GB.json +45 -3
- package/shared/localization/locales/en-US.json +1 -1
- package/shared/localization/locales/en-XA.json +45 -3
- package/shared/localization/locales/en-XL.json +1 -1
- package/shared/localization/locales/es-419.json +45 -3
- package/shared/localization/locales/es.json +45 -3
- package/shared/localization/locales/fi.json +45 -3
- package/shared/localization/locales/fil.json +45 -3
- package/shared/localization/locales/fr.json +48 -6
- package/shared/localization/locales/he.json +45 -3
- package/shared/localization/locales/hi.json +45 -3
- package/shared/localization/locales/hr.json +45 -3
- package/shared/localization/locales/hu.json +45 -3
- package/shared/localization/locales/id.json +45 -3
- package/shared/localization/locales/it.json +45 -3
- package/shared/localization/locales/ja.json +45 -3
- package/shared/localization/locales/ko.json +45 -3
- package/shared/localization/locales/lt.json +45 -3
- package/shared/localization/locales/lv.json +45 -3
- package/shared/localization/locales/nl.json +45 -3
- package/shared/localization/locales/no.json +45 -3
- package/shared/localization/locales/pl.json +45 -3
- package/shared/localization/locales/pt-PT.json +45 -3
- package/shared/localization/locales/pt.json +50 -8
- package/shared/localization/locales/ro.json +45 -3
- package/shared/localization/locales/ru.json +45 -3
- package/shared/localization/locales/sk.json +45 -3
- package/shared/localization/locales/sl.json +45 -3
- package/shared/localization/locales/sr-Latn.json +45 -3
- package/shared/localization/locales/sr.json +45 -3
- package/shared/localization/locales/sv.json +45 -3
- package/shared/localization/locales/ta.json +45 -3
- package/shared/localization/locales/te.json +45 -3
- package/shared/localization/locales/th.json +46 -4
- package/shared/localization/locales/tr.json +46 -4
- package/shared/localization/locales/uk.json +45 -3
- package/shared/localization/locales/vi.json +45 -3
- package/shared/localization/locales/zh-HK.json +45 -3
- package/shared/localization/locales/zh-TW.json +45 -3
- package/shared/localization/locales/zh.json +49 -7
- package/types/artifacts.d.ts +4 -3
- package/types/internal/rxjs.d.ts +4 -0
- package/types/trace-engine.d.ts +0 -1516
|
@@ -69,13 +69,16 @@ class LayoutShifts extends Audit {
|
|
|
69
69
|
|
|
70
70
|
/** @type {Item[]} */
|
|
71
71
|
const items = [];
|
|
72
|
-
const layoutShiftEvents =
|
|
72
|
+
const layoutShiftEvents =
|
|
73
|
+
/** @type {import('../lib/trace-engine.js').SaneSyntheticLayoutShift[]} */(
|
|
74
|
+
clusters.flatMap(c => c.events)
|
|
75
|
+
);
|
|
73
76
|
const topLayoutShiftEvents = layoutShiftEvents
|
|
74
77
|
.sort((a, b) => b.args.data.weighted_score_delta - a.args.data.weighted_score_delta)
|
|
75
78
|
.slice(0, MAX_LAYOUT_SHIFTS);
|
|
76
79
|
for (const event of topLayoutShiftEvents) {
|
|
77
80
|
const biggestImpactNodeId = TraceElements.getBiggestImpactNodeForShiftEvent(
|
|
78
|
-
event.args.data.impacted_nodes, impactByNodeId);
|
|
81
|
+
event.args.data.impacted_nodes || [], impactByNodeId);
|
|
79
82
|
const biggestImpactElement = traceElements.find(t => t.nodeId === biggestImpactNodeId);
|
|
80
83
|
|
|
81
84
|
// Turn root causes into sub-items.
|
|
@@ -159,7 +159,13 @@ class CumulativeLayoutShift {
|
|
|
159
159
|
LayoutShifts: TraceEngine.TraceHandlers.LayoutShifts,
|
|
160
160
|
Screenshots: TraceEngine.TraceHandlers.Screenshots,
|
|
161
161
|
});
|
|
162
|
-
|
|
162
|
+
// eslint-disable-next-line max-len
|
|
163
|
+
await processor.parse(/** @type {import('@paulirish/trace_engine').Types.TraceEvents.TraceEventData[]} */ (
|
|
164
|
+
events
|
|
165
|
+
));
|
|
166
|
+
if (!processor.data) {
|
|
167
|
+
throw new Error('null trace engine result');
|
|
168
|
+
}
|
|
163
169
|
return processor.data.LayoutShifts.sessionMaxScore;
|
|
164
170
|
};
|
|
165
171
|
const cumulativeLayoutShift = await run(allFrameShiftEvents.map(e => e.event));
|
|
@@ -4,14 +4,7 @@ declare const TraceEngineResultComputed: typeof TraceEngineResult & {
|
|
|
4
4
|
trace: LH.Trace;
|
|
5
5
|
}, context: import("../../types/utility-types.js").default.ImmutableObject<{
|
|
6
6
|
computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
|
|
7
|
-
}>) => Promise<
|
|
8
|
-
LayoutShifts: {
|
|
9
|
-
clusters: {
|
|
10
|
-
events: import("../../types/trace-engine.js").LayoutShiftTraceEvent[];
|
|
11
|
-
}[];
|
|
12
|
-
sessionMaxScore: number;
|
|
13
|
-
};
|
|
14
|
-
}>;
|
|
7
|
+
}>) => Promise<Readonly<import("@paulirish/trace_engine/models/trace/handlers/types.js").EnabledHandlerDataWithMeta<typeof import("@paulirish/trace_engine/models/trace/handlers/ModelHandlers.js")>>>;
|
|
15
8
|
};
|
|
16
9
|
/**
|
|
17
10
|
* @fileoverview Processes trace with the shared trace engine.
|
|
@@ -20,14 +13,7 @@ declare class TraceEngineResult {
|
|
|
20
13
|
/**
|
|
21
14
|
* @param {LH.TraceEvent[]} traceEvents
|
|
22
15
|
*/
|
|
23
|
-
static runTraceEngine(traceEvents: LH.TraceEvent[]): Promise<
|
|
24
|
-
LayoutShifts: {
|
|
25
|
-
clusters: {
|
|
26
|
-
events: import("../../types/trace-engine.js").LayoutShiftTraceEvent[];
|
|
27
|
-
}[];
|
|
28
|
-
sessionMaxScore: number;
|
|
29
|
-
};
|
|
30
|
-
}>;
|
|
16
|
+
static runTraceEngine(traceEvents: LH.TraceEvent[]): Promise<Readonly<import("@paulirish/trace_engine/models/trace/handlers/types.js").EnabledHandlerDataWithMeta<typeof import("@paulirish/trace_engine/models/trace/handlers/ModelHandlers.js")>>>;
|
|
31
17
|
/**
|
|
32
18
|
* @param {{trace: LH.Trace}} data
|
|
33
19
|
* @param {LH.Artifacts.ComputedContext} context
|
|
@@ -26,8 +26,13 @@ class TraceEngineResult {
|
|
|
26
26
|
Samples: TraceEngine.TraceHandlers.Samples,
|
|
27
27
|
Screenshots: TraceEngine.TraceHandlers.Screenshots,
|
|
28
28
|
});
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// eslint-disable-next-line max-len
|
|
30
|
+
await engine.parse(/** @type {import('@paulirish/trace_engine').Types.TraceEvents.TraceEventData[]} */ (
|
|
31
|
+
traceEvents
|
|
32
|
+
));
|
|
33
|
+
// TODO: use TraceEngine.TraceProcessor.createWithAllHandlers above.
|
|
34
|
+
return /** @type {import('@paulirish/trace_engine').Handlers.Types.TraceParseData} */(
|
|
35
|
+
engine.data);
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
/**
|
|
@@ -61,7 +66,11 @@ class TraceEngineResult {
|
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
const result = await TraceEngineResult.runTraceEngine(traceEvents);
|
|
70
|
+
if (!result) {
|
|
71
|
+
throw new Error('null trace engine result');
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -446,6 +446,21 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
|
|
|
446
446
|
// CPU listener. Resolves when the CPU has been idle for cpuQuietThresholdMs after network idle.
|
|
447
447
|
let resolveOnCPUIdle = waitForNothing();
|
|
448
448
|
|
|
449
|
+
if (log.isVerbose()) {
|
|
450
|
+
resolveOnFcp.promise.then(() => {
|
|
451
|
+
log.verbose('waitFor', 'resolveOnFcp fired');
|
|
452
|
+
});
|
|
453
|
+
resolveOnLoadEvent.promise.then(() => {
|
|
454
|
+
log.verbose('waitFor', 'resolveOnLoadEvent fired');
|
|
455
|
+
});
|
|
456
|
+
resolveOnNetworkIdle.promise.then(() => {
|
|
457
|
+
log.verbose('waitFor', 'resolveOnNetworkIdle fired');
|
|
458
|
+
});
|
|
459
|
+
resolveOnCriticalNetworkIdle.promise.then(() => {
|
|
460
|
+
log.verbose('waitFor', 'resolveOnCriticalNetworkIdle fired');
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
449
464
|
// Wait for all initial load promises. Resolves on cleanup function the clears load
|
|
450
465
|
// timeout timer.
|
|
451
466
|
/** @type {Promise<() => Promise<{timedOut: boolean}>>} */
|
|
@@ -32,26 +32,33 @@ class RootCauses extends BaseGatherer {
|
|
|
32
32
|
// nodeIds if the DOM domain was enabled before this gatherer, invoke it to be safe.
|
|
33
33
|
await driver.defaultSession.sendCommand('DOM.getDocument', {depth: -1, pierce: true});
|
|
34
34
|
|
|
35
|
+
/** @type {import('@paulirish/trace_engine').RootCauses.RootCauses.RootCauseProtocolInterface} */
|
|
35
36
|
const protocolInterface = {
|
|
36
37
|
/** @param {string} url */
|
|
37
38
|
// eslint-disable-next-line no-unused-vars
|
|
38
39
|
getInitiatorForRequest(url) {
|
|
39
40
|
return null;
|
|
40
41
|
},
|
|
41
|
-
/** @param {
|
|
42
|
+
/** @param {import('@paulirish/trace_engine/generated/protocol.js').DOM.BackendNodeId[]} backendNodeIds */
|
|
42
43
|
async pushNodesByBackendIdsToFrontend(backendNodeIds) {
|
|
43
44
|
const response = await driver.defaultSession.sendCommand(
|
|
44
45
|
'DOM.pushNodesByBackendIdsToFrontend', {backendNodeIds});
|
|
45
|
-
|
|
46
|
+
const nodeIds =
|
|
47
|
+
/** @type {import('@paulirish/trace_engine/generated/protocol.js').DOM.NodeId[]} */(
|
|
48
|
+
response.nodeIds);
|
|
49
|
+
return nodeIds;
|
|
46
50
|
},
|
|
47
|
-
/** @param {
|
|
51
|
+
/** @param {import('@paulirish/trace_engine/generated/protocol.js').DOM.NodeId} nodeId */
|
|
48
52
|
async getNode(nodeId) {
|
|
49
53
|
try {
|
|
50
54
|
const response = await driver.defaultSession.sendCommand('DOM.describeNode', {nodeId});
|
|
51
55
|
// This always zero, so let's fix it here.
|
|
52
56
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1515175
|
|
53
57
|
response.node.nodeId = nodeId;
|
|
54
|
-
|
|
58
|
+
const node =
|
|
59
|
+
/** @type {import('@paulirish/trace_engine/generated/protocol.js').DOM.Node} */(
|
|
60
|
+
response.node);
|
|
61
|
+
return node;
|
|
55
62
|
} catch (err) {
|
|
56
63
|
if (err.message.includes('Could not find node with given id')) {
|
|
57
64
|
// TODO: when injecting an iframe, the engine gets the node of that frame's document element.
|
|
@@ -64,7 +71,8 @@ class RootCauses extends BaseGatherer {
|
|
|
64
71
|
// When this is fixed, remove this try/catch.
|
|
65
72
|
// Note: this could be buggy by giving the wrong node detail if a node id meant for a non-main frame
|
|
66
73
|
// happens to match one from the main frame ... which is pretty likely...
|
|
67
|
-
|
|
74
|
+
// TODO: fix trace engine type to allow returning null.
|
|
75
|
+
return /** @type {any} */(null);
|
|
68
76
|
}
|
|
69
77
|
throw err;
|
|
70
78
|
}
|
|
@@ -79,17 +87,20 @@ class RootCauses extends BaseGatherer {
|
|
|
79
87
|
return [];
|
|
80
88
|
}
|
|
81
89
|
},
|
|
82
|
-
/** @param {
|
|
90
|
+
/** @param {import('@paulirish/trace_engine/generated/protocol.js').DOM.NodeId} nodeId */
|
|
83
91
|
async getMatchedStylesForNode(nodeId) {
|
|
84
92
|
try {
|
|
85
93
|
const response = await driver.defaultSession.sendCommand(
|
|
86
94
|
'CSS.getMatchedStylesForNode', {nodeId});
|
|
87
|
-
return response;
|
|
88
|
-
} catch {
|
|
89
|
-
return
|
|
95
|
+
return {...response, getError() {}};
|
|
96
|
+
} catch (err) {
|
|
97
|
+
return /** @type {any} */({getError() {
|
|
98
|
+
return err.toString();
|
|
99
|
+
}});
|
|
90
100
|
}
|
|
91
101
|
},
|
|
92
102
|
/** @param {string} url */
|
|
103
|
+
// @ts-expect-error not using, dont care about type error.
|
|
93
104
|
// eslint-disable-next-line no-unused-vars
|
|
94
105
|
async fontFaceForSource(url) {
|
|
95
106
|
return null;
|
|
@@ -104,6 +115,8 @@ class RootCauses extends BaseGatherer {
|
|
|
104
115
|
const layoutShiftEvents = traceEngineResult.LayoutShifts.clusters.flatMap(c => c.events);
|
|
105
116
|
for (const event of layoutShiftEvents) {
|
|
106
117
|
const r = await rootCausesEngine.layoutShifts.rootCausesForEvent(traceEngineResult, event);
|
|
118
|
+
if (!r) continue;
|
|
119
|
+
|
|
107
120
|
for (const cause of r.fontChanges) {
|
|
108
121
|
// TODO: why isn't trace engine unwrapping this promise ...
|
|
109
122
|
cause.fontFace = await cause.fontFace;
|
|
@@ -117,15 +117,19 @@ class TraceElements extends BaseGatherer {
|
|
|
117
117
|
static async getTopLayoutShifts(trace, traceEngineResult, rootCauses, context) {
|
|
118
118
|
const {impactByNodeId} = await CumulativeLayoutShift.request(trace, context);
|
|
119
119
|
const clusters = traceEngineResult.LayoutShifts.clusters ?? [];
|
|
120
|
-
const layoutShiftEvents =
|
|
120
|
+
const layoutShiftEvents =
|
|
121
|
+
/** @type {import('../../lib/trace-engine.js').SaneSyntheticLayoutShift[]} */(
|
|
122
|
+
clusters.flatMap(c => c.events)
|
|
123
|
+
);
|
|
121
124
|
|
|
122
125
|
return layoutShiftEvents
|
|
123
126
|
.sort((a, b) => b.args.data.weighted_score_delta - a.args.data.weighted_score_delta)
|
|
124
127
|
.slice(0, MAX_LAYOUT_SHIFTS)
|
|
125
128
|
.flatMap(event => {
|
|
126
129
|
const nodeIds = [];
|
|
130
|
+
const impactedNodes = event.args.data.impacted_nodes || [];
|
|
127
131
|
const biggestImpactedNodeId =
|
|
128
|
-
this.getBiggestImpactNodeForShiftEvent(
|
|
132
|
+
this.getBiggestImpactNodeForShiftEvent(impactedNodes, impactByNodeId);
|
|
129
133
|
if (biggestImpactedNodeId !== undefined) {
|
|
130
134
|
nodeIds.push(biggestImpactedNodeId);
|
|
131
135
|
}
|
|
@@ -61,7 +61,8 @@ class Trace extends BaseGatherer {
|
|
|
61
61
|
|
|
62
62
|
// Not used by Lighthouse (yet) but included for users that want JS samples when looking at
|
|
63
63
|
// a trace collected by Lighthouse (e.g. "View Trace" workflow in DevTools)
|
|
64
|
-
|
|
64
|
+
// TODO: Re-enable after investigating b/325659693
|
|
65
|
+
// 'disabled-by-default-v8.cpu_profiler',
|
|
65
66
|
];
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -33,7 +33,10 @@ import {Sentry} from '../lib/sentry.js';
|
|
|
33
33
|
* @param {Error} error
|
|
34
34
|
*/
|
|
35
35
|
function createDependencyError(dependency, error) {
|
|
36
|
-
|
|
36
|
+
const err = new Error(`Dependency "${dependency.id}" failed with exception: ${error.message}`);
|
|
37
|
+
// @ts-expect-error - We already reported the original error to Sentry, don't do it again.
|
|
38
|
+
err.expected = true;
|
|
39
|
+
return err;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/** @return {ArtifactState} */
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export type SyntheticLayoutShift = import('@paulirish/trace_engine').Types.TraceEvents.SyntheticLayoutShift;
|
|
2
|
+
export type SaneSyntheticLayoutShift = SyntheticLayoutShift & {
|
|
3
|
+
args: {
|
|
4
|
+
data: NonNullable<SyntheticLayoutShift['args']['data']>;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
export const TraceProcessor: typeof TraceEngine.Processor.TraceProcessor;
|
|
8
|
+
export const TraceHandlers: typeof TraceEngine.Handlers.ModelHandlers;
|
|
9
|
+
export const RootCauses: typeof TraceEngine.RootCauses.RootCauses.RootCauses;
|
|
10
|
+
import * as TraceEngine from '@paulirish/trace_engine';
|
|
7
11
|
//# sourceMappingURL=trace-engine.d.ts.map
|
package/core/lib/trace-engine.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
// @ts-expect-error missing types
|
|
2
1
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
3
2
|
|
|
4
3
|
import {polyfillDOMRect} from './polyfill-dom-rect.js';
|
|
5
4
|
|
|
5
|
+
/** @typedef {import('@paulirish/trace_engine').Types.TraceEvents.SyntheticLayoutShift} SyntheticLayoutShift */
|
|
6
|
+
/** @typedef {SyntheticLayoutShift & {args: {data: NonNullable<SyntheticLayoutShift['args']['data']>}}} SaneSyntheticLayoutShift */
|
|
7
|
+
|
|
6
8
|
polyfillDOMRect();
|
|
7
9
|
|
|
8
|
-
/** @type {import('../../types/trace-engine.js').TraceProcessor & typeof import('../../types/trace-engine.js').TraceProcessor} */
|
|
9
10
|
const TraceProcessor = TraceEngine.Processor.TraceProcessor;
|
|
10
|
-
/** @type {import('../../types/trace-engine.js').TraceHandlers} */
|
|
11
11
|
const TraceHandlers = TraceEngine.Handlers.ModelHandlers;
|
|
12
|
-
/** @type {import('../../types/trace-engine.js').RootCauses & typeof import('../../types/trace-engine.js').RootCauses} */
|
|
13
12
|
const RootCauses = TraceEngine.RootCauses.RootCauses.RootCauses;
|
|
14
13
|
|
|
15
14
|
export {
|