lighthouse 12.6.1-dev.20250603 → 12.6.1-dev.20250604
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/cls-culprits-insight.js +1 -1
- package/core/audits/layout-shifts.js +1 -1
- package/core/gather/gatherers/trace-elements.d.ts +1 -2
- package/core/gather/gatherers/trace-elements.js +10 -40
- package/core/lib/asset-saver.d.ts +1 -1
- package/core/lib/asset-saver.js +20 -8
- package/core/runner.js +11 -7
- package/package.json +1 -1
- package/types/lhr/lhr.d.ts +8 -1
|
@@ -114,7 +114,7 @@ class CLSCulpritsInsight extends Audit {
|
|
|
114
114
|
/** @type {LH.Audit.Details.Table['items']} */
|
|
115
115
|
const items = events.map(event => {
|
|
116
116
|
const biggestImpactNodeId = TraceElements.getBiggestImpactNodeForShiftEvent(
|
|
117
|
-
event.args.data.impacted_nodes || [], impactByNodeId
|
|
117
|
+
event.args.data.impacted_nodes || [], impactByNodeId);
|
|
118
118
|
return {
|
|
119
119
|
node: makeNodeItemForNodeId(artifacts.TraceElements, biggestImpactNodeId),
|
|
120
120
|
score: event.args.data?.weighted_score_delta,
|
|
@@ -89,7 +89,7 @@ class LayoutShifts extends Audit {
|
|
|
89
89
|
.slice(0, MAX_LAYOUT_SHIFTS);
|
|
90
90
|
for (const event of topLayoutShiftEvents) {
|
|
91
91
|
const biggestImpactNodeId = TraceElements.getBiggestImpactNodeForShiftEvent(
|
|
92
|
-
event.args.data.impacted_nodes || [], impactByNodeId
|
|
92
|
+
event.args.data.impacted_nodes || [], impactByNodeId);
|
|
93
93
|
const biggestImpactElement = traceElements.find(t => t.nodeId === biggestImpactNodeId);
|
|
94
94
|
|
|
95
95
|
// Turn root causes into sub-items.
|
|
@@ -23,10 +23,9 @@ declare class TraceElements extends BaseGatherer {
|
|
|
23
23
|
*
|
|
24
24
|
* @param {LH.Artifacts.TraceImpactedNode[]} impactedNodes
|
|
25
25
|
* @param {Map<number, number>} impactByNodeId
|
|
26
|
-
* @param {import('../../lib/trace-engine.js').SaneSyntheticLayoutShift} event Only for debugging
|
|
27
26
|
* @return {number|undefined}
|
|
28
27
|
*/
|
|
29
|
-
static getBiggestImpactNodeForShiftEvent(impactedNodes: LH.Artifacts.TraceImpactedNode[], impactByNodeId: Map<number, number
|
|
28
|
+
static getBiggestImpactNodeForShiftEvent(impactedNodes: LH.Artifacts.TraceImpactedNode[], impactByNodeId: Map<number, number>): number | undefined;
|
|
30
29
|
/**
|
|
31
30
|
* This function finds the top (up to 15) layout shifts on the page, and returns
|
|
32
31
|
* the id of the largest impacted node of each shift, along with any related nodes
|
|
@@ -152,49 +152,19 @@ class TraceElements extends BaseGatherer {
|
|
|
152
152
|
*
|
|
153
153
|
* @param {LH.Artifacts.TraceImpactedNode[]} impactedNodes
|
|
154
154
|
* @param {Map<number, number>} impactByNodeId
|
|
155
|
-
* @param {import('../../lib/trace-engine.js').SaneSyntheticLayoutShift} event Only for debugging
|
|
156
155
|
* @return {number|undefined}
|
|
157
156
|
*/
|
|
158
|
-
static getBiggestImpactNodeForShiftEvent(impactedNodes, impactByNodeId
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
biggestImpactNodeScore = impactScore;
|
|
167
|
-
}
|
|
157
|
+
static getBiggestImpactNodeForShiftEvent(impactedNodes, impactByNodeId) {
|
|
158
|
+
let biggestImpactNodeId;
|
|
159
|
+
let biggestImpactNodeScore = Number.NEGATIVE_INFINITY;
|
|
160
|
+
for (const node of impactedNodes) {
|
|
161
|
+
const impactScore = impactByNodeId.get(node.node_id);
|
|
162
|
+
if (impactScore !== undefined && impactScore > biggestImpactNodeScore) {
|
|
163
|
+
biggestImpactNodeId = node.node_id;
|
|
164
|
+
biggestImpactNodeScore = impactScore;
|
|
168
165
|
}
|
|
169
|
-
return biggestImpactNodeId;
|
|
170
|
-
} catch (err) {
|
|
171
|
-
// See https://github.com/GoogleChrome/lighthouse/issues/15870
|
|
172
|
-
// `impactedNodes` should always be an array here, but it can randomly be something else for
|
|
173
|
-
// currently unknown reasons. This exception handling will help us identify what
|
|
174
|
-
// `impactedNodes` really is and also prevent the error from being fatal.
|
|
175
|
-
|
|
176
|
-
// It's possible `impactedNodes` is not JSON serializable, so let's add more supplemental
|
|
177
|
-
// fields just in case.
|
|
178
|
-
const impactedNodesType = typeof impactedNodes;
|
|
179
|
-
const impactedNodesClassName = impactedNodes?.constructor?.name;
|
|
180
|
-
|
|
181
|
-
let impactedNodesJson;
|
|
182
|
-
let eventJson;
|
|
183
|
-
try {
|
|
184
|
-
impactedNodesJson = JSON.parse(JSON.stringify(impactedNodes));
|
|
185
|
-
eventJson = JSON.parse(JSON.stringify(event));
|
|
186
|
-
} catch {}
|
|
187
|
-
|
|
188
|
-
Sentry.captureException(err, {
|
|
189
|
-
extra: {
|
|
190
|
-
impactedNodes: impactedNodesJson,
|
|
191
|
-
event: eventJson,
|
|
192
|
-
impactedNodesType,
|
|
193
|
-
impactedNodesClassName,
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
return;
|
|
197
166
|
}
|
|
167
|
+
return biggestImpactNodeId;
|
|
198
168
|
}
|
|
199
169
|
|
|
200
170
|
/**
|
|
@@ -222,7 +192,7 @@ class TraceElements extends BaseGatherer {
|
|
|
222
192
|
const nodeIds = [];
|
|
223
193
|
const impactedNodes = event.args.data.impacted_nodes || [];
|
|
224
194
|
const biggestImpactedNodeId =
|
|
225
|
-
this.getBiggestImpactNodeForShiftEvent(impactedNodes, impactByNodeId
|
|
195
|
+
this.getBiggestImpactNodeForShiftEvent(impactedNodes, impactByNodeId);
|
|
226
196
|
if (biggestImpactedNodeId !== undefined) {
|
|
227
197
|
nodeIds.push(biggestImpactedNodeId);
|
|
228
198
|
}
|
|
@@ -102,5 +102,5 @@ export function normalizeTimingEntries(timings: LH.Result.MeasureEntry[]): void;
|
|
|
102
102
|
/**
|
|
103
103
|
* @param {LH.Result} lhr
|
|
104
104
|
*/
|
|
105
|
-
export function
|
|
105
|
+
export function elideLhrErrorStacks(lhr: LH.Result): void;
|
|
106
106
|
//# sourceMappingURL=asset-saver.d.ts.map
|
package/core/lib/asset-saver.js
CHANGED
|
@@ -515,19 +515,31 @@ function normalizeTimingEntries(timings) {
|
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
/**
|
|
518
|
-
* @param {
|
|
518
|
+
* @param {string} errorStack
|
|
519
|
+
* @return {string}
|
|
519
520
|
*/
|
|
520
|
-
function
|
|
521
|
+
function elideErrorStack(errorStack) {
|
|
521
522
|
const baseCallFrameUrl = url.pathToFileURL(LH_ROOT);
|
|
523
|
+
return errorStack
|
|
524
|
+
// Make paths relative to the repo root.
|
|
525
|
+
.replaceAll(baseCallFrameUrl.pathname, '')
|
|
526
|
+
// Remove line/col info.
|
|
527
|
+
.replaceAll(/:\d+:\d+/g, '');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* @param {LH.Result} lhr
|
|
532
|
+
*/
|
|
533
|
+
function elideLhrErrorStacks(lhr) {
|
|
522
534
|
for (const auditResult of Object.values(lhr.audits)) {
|
|
523
535
|
if (auditResult.errorStack) {
|
|
524
|
-
auditResult.errorStack = auditResult.errorStack
|
|
525
|
-
// Make paths relative to the repo root.
|
|
526
|
-
.replaceAll(baseCallFrameUrl.pathname, '')
|
|
527
|
-
// Remove line/col info.
|
|
528
|
-
.replaceAll(/:\d+:\d+/g, '');
|
|
536
|
+
auditResult.errorStack = elideErrorStack(auditResult.errorStack);
|
|
529
537
|
}
|
|
530
538
|
}
|
|
539
|
+
|
|
540
|
+
if (lhr.runtimeError?.errorStack) {
|
|
541
|
+
lhr.runtimeError.errorStack = elideErrorStack(lhr.runtimeError.errorStack);
|
|
542
|
+
}
|
|
531
543
|
}
|
|
532
544
|
|
|
533
545
|
export {
|
|
@@ -543,5 +555,5 @@ export {
|
|
|
543
555
|
saveLanternNetworkData,
|
|
544
556
|
stringifyReplacer,
|
|
545
557
|
normalizeTimingEntries,
|
|
546
|
-
|
|
558
|
+
elideLhrErrorStacks,
|
|
547
559
|
};
|
package/core/runner.js
CHANGED
|
@@ -312,10 +312,8 @@ class Runner {
|
|
|
312
312
|
if (!isEqual(normalizedGatherSettings[k], normalizedAuditSettings[k])) {
|
|
313
313
|
throw new Error(
|
|
314
314
|
`Cannot change settings between gathering and auditing…
|
|
315
|
-
Difference found at: \`${k}
|
|
316
|
-
|
|
317
|
-
vs
|
|
318
|
-
${normalizedAuditSettings[k]}`);
|
|
315
|
+
Difference found at: \`${k}\`: ${JSON.stringify(normalizedGatherSettings[k], null, 2)}
|
|
316
|
+
vs: ${JSON.stringify(normalizedAuditSettings[k], null, 2)}`);
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
319
|
|
|
@@ -451,21 +449,27 @@ vs
|
|
|
451
449
|
* @return {LH.RawIcu<LH.Result['runtimeError']>|undefined}
|
|
452
450
|
*/
|
|
453
451
|
static getArtifactRuntimeError(artifacts) {
|
|
452
|
+
/** @type {Array<[string, LighthouseError|object]>} */
|
|
454
453
|
const possibleErrorArtifacts = [
|
|
455
|
-
artifacts.PageLoadError, // Preferentially use `PageLoadError`, if it exists.
|
|
456
|
-
...Object.
|
|
454
|
+
['PageLoadError', artifacts.PageLoadError], // Preferentially use `PageLoadError`, if it exists.
|
|
455
|
+
...Object.entries(artifacts), // Otherwise check amongst all artifacts.
|
|
457
456
|
];
|
|
458
457
|
|
|
459
|
-
for (const possibleErrorArtifact of possibleErrorArtifacts) {
|
|
458
|
+
for (const [artifactKey, possibleErrorArtifact] of possibleErrorArtifacts) {
|
|
460
459
|
const isError = possibleErrorArtifact instanceof LighthouseError;
|
|
461
460
|
|
|
462
461
|
// eslint-disable-next-line max-len
|
|
463
462
|
if (isError && possibleErrorArtifact.lhrRuntimeError) {
|
|
464
463
|
const errorMessage = possibleErrorArtifact.friendlyMessage || possibleErrorArtifact.message;
|
|
464
|
+
// Prefer the stack trace closest to the error.
|
|
465
|
+
const stack =
|
|
466
|
+
/** @type {any} */ (possibleErrorArtifact.cause)?.stack ?? possibleErrorArtifact.stack;
|
|
465
467
|
|
|
466
468
|
return {
|
|
467
469
|
code: possibleErrorArtifact.code,
|
|
468
470
|
message: errorMessage,
|
|
471
|
+
errorStack: stack,
|
|
472
|
+
artifactKey,
|
|
469
473
|
};
|
|
470
474
|
}
|
|
471
475
|
}
|
package/package.json
CHANGED
package/types/lhr/lhr.d.ts
CHANGED
|
@@ -41,7 +41,14 @@ interface Result {
|
|
|
41
41
|
/** List of top-level warnings for this Lighthouse run. */
|
|
42
42
|
runWarnings: string[];
|
|
43
43
|
/** A top-level error message that, if present, indicates a serious enough problem that this Lighthouse result may need to be discarded. */
|
|
44
|
-
runtimeError?: {
|
|
44
|
+
runtimeError?: {
|
|
45
|
+
code: string;
|
|
46
|
+
message: string;
|
|
47
|
+
/** Error stack from any fatal error. */
|
|
48
|
+
errorStack?: string;
|
|
49
|
+
/** Artifact the threw the fatal error. */
|
|
50
|
+
artifactKey?: string;
|
|
51
|
+
};
|
|
45
52
|
/** The User-Agent string of the browser used run Lighthouse for these results. */
|
|
46
53
|
userAgent: string;
|
|
47
54
|
/** Information about the environment in which Lighthouse was run. */
|