lighthouse 12.4.0-dev.20250312 → 12.4.0-dev.20250314

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.
@@ -2,13 +2,12 @@ export default LegacyJavascript;
2
2
  export type Pattern = {
3
3
  name: string;
4
4
  expression: string;
5
- estimateBytes?: (result: PatternMatchResult) => number;
5
+ estimateBytes?: (content: string) => number;
6
6
  };
7
7
  export type PatternMatchResult = {
8
8
  name: string;
9
9
  line: number;
10
10
  column: number;
11
- count: number;
12
11
  };
13
12
  export type ByteEfficiencyProduct = import("./byte-efficiency-audit.js").ByteEfficiencyProduct;
14
13
  export type Item = LH.Audit.ByteEfficiencyItem & {
@@ -25,8 +24,9 @@ declare class LegacyJavascript extends ByteEfficiencyAudit {
25
24
  /**
26
25
  * @param {string?} object
27
26
  * @param {string} property
27
+ * @param {string} coreJs3Module
28
28
  */
29
- static buildPolyfillExpression(object: string | null, property: string): string;
29
+ static buildPolyfillExpression(object: string | null, property: string, coreJs3Module: string): string;
30
30
  static getPolyfillModuleData(): import("../../scripts/legacy-javascript/create-polyfill-module-data.js").PolyfillModuleData;
31
31
  static getCoreJsPolyfillData(): {
32
32
  name: string;
@@ -50,10 +50,11 @@ declare class LegacyJavascript extends ByteEfficiencyAudit {
50
50
  */
51
51
  static detectAcrossScripts(matcher: CodePatternMatcher, scripts: LH.Artifacts["Scripts"], bundles: LH.Artifacts.Bundle[]): Map<LH.Artifacts.Script, PatternMatchResult[]>;
52
52
  /**
53
+ * @param {LH.Artifacts.Script} script
53
54
  * @param {PatternMatchResult[]} matches
54
55
  * @return {number}
55
56
  */
56
- static estimateWastedBytes(matches: PatternMatchResult[]): number;
57
+ static estimateWastedBytes(script: LH.Artifacts.Script, matches: PatternMatchResult[]): number;
57
58
  /**
58
59
  * @param {LH.Artifacts} artifacts
59
60
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
@@ -70,7 +71,8 @@ export namespace UIStrings {
70
71
  import { ByteEfficiencyAudit } from './byte-efficiency-audit.js';
71
72
  /**
72
73
  * Takes a list of patterns (consisting of a name identifier and a RegExp expression string)
73
- * and returns match results with line / column information for a given code input.
74
+ * and via `match` returns match results with line / column information for a given code input.
75
+ * Only returns the first match per pattern given.
74
76
  */
75
77
  declare class CodePatternMatcher {
76
78
  /**
@@ -11,8 +11,8 @@
11
11
  * ./core/scripts/legacy-javascript - verification tool.
12
12
  */
13
13
 
14
- /** @typedef {{name: string, expression: string, estimateBytes?: (result: PatternMatchResult) => number}} Pattern */
15
- /** @typedef {{name: string, line: number, column: number, count: number}} PatternMatchResult */
14
+ /** @typedef {{name: string, expression: string, estimateBytes?: (content: string) => number}} Pattern */
15
+ /** @typedef {{name: string, line: number, column: number}} PatternMatchResult */
16
16
  /** @typedef {import('./byte-efficiency-audit.js').ByteEfficiencyProduct} ByteEfficiencyProduct */
17
17
  /** @typedef {LH.Audit.ByteEfficiencyItem & {subItems: {type: 'subitems', items: SubItem[]}}} Item */
18
18
  /** @typedef {{signal: string, location: LH.Audit.Details.SourceLocationValue}} SubItem */
@@ -55,7 +55,8 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
55
55
 
56
56
  /**
57
57
  * Takes a list of patterns (consisting of a name identifier and a RegExp expression string)
58
- * and returns match results with line / column information for a given code input.
58
+ * and via `match` returns match results with line / column information for a given code input.
59
+ * Only returns the first match per pattern given.
59
60
  */
60
61
  class CodePatternMatcher {
61
62
  /**
@@ -99,8 +100,6 @@ class CodePatternMatcher {
99
100
  const pattern = this.patterns[patternExpressionMatches.findIndex(Boolean)];
100
101
 
101
102
  if (seen.has(pattern)) {
102
- const existingMatch = matches.find(m => m.name === pattern.name);
103
- if (existingMatch) existingMatch.count += 1;
104
103
  continue;
105
104
  }
106
105
  seen.add(pattern);
@@ -109,7 +108,6 @@ class CodePatternMatcher {
109
108
  name: pattern.name,
110
109
  line,
111
110
  column: result.index - lineBeginsAtIndex,
112
- count: 1,
113
111
  });
114
112
  }
115
113
 
@@ -136,8 +134,9 @@ class LegacyJavascript extends ByteEfficiencyAudit {
136
134
  /**
137
135
  * @param {string?} object
138
136
  * @param {string} property
137
+ * @param {string} coreJs3Module
139
138
  */
140
- static buildPolyfillExpression(object, property) {
139
+ static buildPolyfillExpression(object, property, coreJs3Module) {
141
140
  const qt = (/** @type {string} */ token) =>
142
141
  `['"]${token}['"]`; // don't worry about matching string delims
143
142
 
@@ -189,6 +188,10 @@ class LegacyJavascript extends ByteEfficiencyAudit {
189
188
  // expression += `|collection\\(${qt(property)},`;
190
189
  }
191
190
 
191
+ // Un-minified code may have module names.
192
+ // core-js/modules/es.object.is-frozen
193
+ expression += `|core-js/modules/${coreJs3Module}(?:\\.js)?"`;
194
+
192
195
  return expression;
193
196
  }
194
197
 
@@ -212,13 +215,13 @@ class LegacyJavascript extends ByteEfficiencyAudit {
212
215
  /** @type {Pattern[]} */
213
216
  const patterns = [];
214
217
 
215
- for (const {name} of this.getCoreJsPolyfillData()) {
218
+ for (const {name, coreJs3Module} of this.getCoreJsPolyfillData()) {
216
219
  const parts = name.split('.');
217
220
  const object = parts.length > 1 ? parts.slice(0, parts.length - 1).join('.') : null;
218
221
  const property = parts[parts.length - 1];
219
222
  patterns.push({
220
223
  name,
221
- expression: this.buildPolyfillExpression(object, property),
224
+ expression: this.buildPolyfillExpression(object, property, coreJs3Module),
222
225
  });
223
226
  }
224
227
 
@@ -229,23 +232,74 @@ class LegacyJavascript extends ByteEfficiencyAudit {
229
232
  * @return {Pattern[]}
230
233
  */
231
234
  static getTransformPatterns() {
235
+ /**
236
+ * @param {string} content
237
+ * @param {RegExp|string} pattern
238
+ * @return {number}
239
+ */
240
+ const count = (content, pattern) => {
241
+ // Split is slightly faster than match.
242
+ if (typeof pattern === 'string') {
243
+ return content.split(pattern).length - 1;
244
+ }
245
+
246
+ return (content.match(pattern) ?? []).length;
247
+ };
248
+
249
+ // For expression: prefer a string that is found in the transform runtime support code (those won't ever be minified).
250
+
232
251
  return [
252
+ // @babel/plugin-transform-classes
253
+ //
254
+ // input:
255
+ //
256
+ // class MyTestClass {
257
+ // log() {
258
+ // console.log(1);
259
+ // }
260
+ // };
261
+ //
262
+ // output:
263
+ //
264
+ // function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
265
+ // function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
266
+ // function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
267
+ // function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
268
+ // function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
269
+ // let MyTestClass = function () {
270
+ // function MyTestClass() {
271
+ // _classCallCheck(this, MyTestClass);
272
+ // }
273
+ // return _createClass(MyTestClass, [{
274
+ // key: "log",
275
+ // value: function log() {
276
+ // console.log(1);
277
+ // }
278
+ // }]);
279
+ // }();
233
280
  {
234
281
  name: '@babel/plugin-transform-classes',
235
282
  expression: 'Cannot call a class as a function',
236
- estimateBytes: result => 150 + result.count * '_classCallCheck()'.length,
283
+ estimateBytes: content => {
284
+ return 1000 + (count(content, '_classCallCheck') - 1) * '_classCallCheck()'.length;
285
+ },
237
286
  },
238
287
  {
239
288
  name: '@babel/plugin-transform-regenerator',
240
- expression: /regeneratorRuntime\(?\)?\.a?wrap/.source,
289
+ expression: 'Generator is already running|regeneratorRuntime',
241
290
  // Example of this transform: https://gist.github.com/connorjclark/af8bccfff377ac44efc104a79bc75da2
242
291
  // `regeneratorRuntime.awrap` is generated for every usage of `await`, and adds ~80 bytes each.
243
- estimateBytes: result => result.count * 80,
292
+ estimateBytes: content => {
293
+ return count(content, /regeneratorRuntime\(?\)?\.a?wrap/g) * 80;
294
+ },
244
295
  },
245
296
  {
246
297
  name: '@babel/plugin-transform-spread',
247
- expression: /\.apply\(void 0,\s?_toConsumableArray/.source,
248
- estimateBytes: result => 1169 + result.count * '_toConsumableArray()'.length,
298
+ expression: 'Invalid attempt to spread non-iterable instance',
299
+ estimateBytes: content => {
300
+ const per = '_toConsumableArray()'.length;
301
+ return 1169 + count(content, /\.apply\(void 0,\s?_toConsumableArray/g) * per;
302
+ },
249
303
  },
250
304
  ];
251
305
  }
@@ -283,9 +337,9 @@ class LegacyJavascript extends ByteEfficiencyAudit {
283
337
 
284
338
  const mapping = bundle.map.mappings().find(m => m.sourceURL === source);
285
339
  if (mapping) {
286
- matches.push({name, line: mapping.lineNumber, column: mapping.columnNumber, count: 1});
340
+ matches.push({name, line: mapping.lineNumber, column: mapping.columnNumber});
287
341
  } else {
288
- matches.push({name, line: 0, column: 0, count: 1});
342
+ matches.push({name, line: 0, column: 0});
289
343
  }
290
344
  }
291
345
  }
@@ -298,10 +352,11 @@ class LegacyJavascript extends ByteEfficiencyAudit {
298
352
  }
299
353
 
300
354
  /**
355
+ * @param {LH.Artifacts.Script} script
301
356
  * @param {PatternMatchResult[]} matches
302
357
  * @return {number}
303
358
  */
304
- static estimateWastedBytes(matches) {
359
+ static estimateWastedBytes(script, matches) {
305
360
  // Split up results based on polyfill / transform. Only transforms start with @.
306
361
  const polyfillResults = matches.filter(m => !m.name.startsWith('@'));
307
362
  const transformResults = matches.filter(m => m.name.startsWith('@'));
@@ -325,8 +380,8 @@ class LegacyJavascript extends ByteEfficiencyAudit {
325
380
 
326
381
  for (const result of transformResults) {
327
382
  const pattern = this.getTransformPatterns().find(p => p.name === result.name);
328
- if (!pattern || !pattern.estimateBytes) continue;
329
- estimatedWastedBytesFromTransforms += pattern.estimateBytes(result);
383
+ if (!pattern || !pattern.estimateBytes || !script.content) continue;
384
+ estimatedWastedBytesFromTransforms += pattern.estimateBytes(script.content);
330
385
  }
331
386
 
332
387
  const estimatedWastedBytes =
@@ -363,7 +418,7 @@ class LegacyJavascript extends ByteEfficiencyAudit {
363
418
  for (const [script, matches] of scriptToMatchResults.entries()) {
364
419
  const compressionRatio = estimateCompressionRatioForContent(
365
420
  compressionRatioByUrl, script.url, artifacts, networkRecords);
366
- const wastedBytes = Math.round(this.estimateWastedBytes(matches) * compressionRatio);
421
+ const wastedBytes = Math.round(this.estimateWastedBytes(script, matches) * compressionRatio);
367
422
  /** @type {typeof items[number]} */
368
423
  const item = {
369
424
  url: script.url,
@@ -1,7 +1,7 @@
1
1
  {
2
- "moduleSizes": [26070, 498, 282, 294, 281, 467, 161, 236, 229, 765, 546, 339, 1608, 723, 729, 1545, 438, 214, 657, 111, 759, 537, 209, 281, 685, 217, 757, 631, 293, 182, 475, 79, 407, 140, 366, 792, 269, 222, 158, 280, 188, 137, 158, 105, 189, 543, 160, 742, 1436, 88, 904, 146, 314, 375, 183, 1083, 195, 503, 269, 208, 334, 350, 460, 568, 229, 1155, 334, 266, 30, 120, 309, 370, 358, 1952, 1638, 304, 153, 274, 1288, 192, 543, 74, 144, 137, 33, 336, 457, 2122, 535, 711, 1323, 117, 1961, 244, 557, 318, 119, 124, 108, 144, 96, 133, 441, 210, 1627, 1956, 693, 1426, 863, 637, 301, 51, 708, 583, 119, 600, 221, 370, 728, 1085, 552, 629, 125, 1746, 97, 441, 543, 2756, 371, 447, 548, 243, 266, 217, 99, 440, 183, 546, 137, 464, 207, 983, 171, 992, 503, 237, 382, 249, 675, 402, 254, 223, 164, 214, 191, 831, 218, 202, 232, 124, 249, 160, 251, 217, 717, 78, 561, 1627, 256, 386, 225, 432, 499, 394, 364, 445, 634, 667, 177, 346, 470, 663, 142, 588, 414, 617, 1559, 380, 2520, 1040, 417, 289, 238, 220, 214, 303, 163, 141, 510, 397, 137, 137, 133, 133, 390, 266, 137, 183, 215, 191, 485, 328, 575, 799, 533, 148, 215, 589, 589, 130, 362, 562, 471, 179, 186, 1266, 1456, 521, 1536, 427, 444, 406, 912, 150, 283, 144, 485, 470, 1787, 205, 1268, 796, 658, 306, 3751, 321, 331, 814, 146, 2328, 1226, 922, 237, 206, 198, 250, 283, 46, 59, 53, 52, 60, 49, 54, 56, 3000],
2
+ "moduleSizes": [26070, 498, 282, 294, 281, 467, 161, 236, 229, 765, 546, 339, 1608, 723, 729, 1545, 438, 214, 657, 111, 759, 537, 209, 281, 685, 217, 757, 631, 293, 182, 475, 79, 407, 140, 366, 792, 269, 222, 158, 280, 188, 137, 158, 105, 189, 543, 160, 742, 1436, 88, 904, 146, 314, 375, 183, 1083, 195, 503, 269, 208, 334, 350, 460, 568, 229, 1155, 334, 266, 30, 120, 309, 370, 358, 1952, 1638, 304, 153, 274, 1288, 192, 543, 74, 144, 137, 33, 336, 457, 2122, 535, 711, 1323, 117, 1961, 244, 557, 318, 119, 124, 108, 144, 96, 133, 441, 210, 1627, 1956, 693, 1426, 863, 637, 301, 51, 708, 583, 119, 600, 221, 370, 728, 1085, 552, 629, 125, 1746, 97, 441, 543, 2756, 371, 447, 548, 243, 266, 217, 99, 440, 183, 546, 137, 464, 207, 983, 171, 992, 503, 237, 382, 249, 675, 402, 254, 223, 164, 214, 191, 831, 218, 202, 232, 124, 249, 160, 251, 217, 717, 78, 561, 1627, 256, 386, 225, 432, 499, 394, 364, 445, 634, 667, 177, 346, 470, 663, 142, 588, 414, 617, 1559, 380, 2520, 1040, 417, 289, 238, 220, 214, 303, 163, 141, 510, 397, 137, 137, 133, 133, 390, 266, 137, 183, 215, 191, 485, 328, 575, 799, 533, 148, 215, 589, 589, 130, 362, 562, 471, 179, 186, 1266, 1456, 521, 1536, 427, 444, 406, 912, 150, 283, 144, 485, 470, 1787, 205, 1268, 796, 658, 306, 3751, 321, 331, 814, 146, 2328, 1226, 922, 237, 206, 198, 250, 283, 60, 3000],
3
3
  "dependencies": {
4
- "Array.prototype.at": [0, 5, 69, 105, 106, 116, 166, 257],
4
+ "Array.prototype.at": [0, 5, 69, 105, 106, 116, 166],
5
5
  "Array.prototype.concat": [0, 16, 21, 22, 26, 34, 40, 76, 78, 157, 167],
6
6
  "Array.prototype.copyWithin": [0, 5, 9, 37, 69, 105, 106, 116, 168],
7
7
  "Array.prototype.every": [0, 15, 17, 21, 22, 26, 53, 59, 76, 78, 157, 169],
@@ -9,8 +9,8 @@
9
9
  "Array.prototype.filter": [0, 15, 16, 21, 22, 26, 53, 59, 76, 78, 157, 171],
10
10
  "Array.prototype.find": [0, 5, 15, 21, 22, 26, 53, 59, 69, 76, 78, 105, 106, 116, 157, 175],
11
11
  "Array.prototype.findIndex": [0, 5, 15, 21, 22, 26, 53, 59, 69, 76, 78, 105, 106, 116, 157, 172],
12
- "Array.prototype.findLast": [0, 5, 14, 53, 59, 69, 105, 106, 116, 174, 259],
13
- "Array.prototype.findLastIndex": [0, 5, 14, 53, 59, 69, 105, 106, 116, 173, 258],
12
+ "Array.prototype.findLast": [0, 5, 14, 53, 59, 69, 105, 106, 116, 174],
13
+ "Array.prototype.findLastIndex": [0, 5, 14, 53, 59, 69, 105, 106, 116, 173],
14
14
  "Array.prototype.flat": [0, 21, 22, 26, 40, 50, 53, 59, 76, 78, 157, 177],
15
15
  "Array.prototype.flatMap": [0, 21, 22, 26, 40, 50, 53, 59, 76, 78, 157, 176],
16
16
  "Array.prototype.forEach": [0, 11, 15, 17, 21, 22, 26, 53, 59, 76, 78, 157, 178],
@@ -50,7 +50,7 @@
50
50
  "Object.getOwnPropertyDescriptor": [0, 212],
51
51
  "Object.getOwnPropertyDescriptors": [0, 34, 213],
52
52
  "Object.getPrototypeOf": [0, 29, 112, 214],
53
- "Object.hasOwn": [0, 215, 260],
53
+ "Object.hasOwn": [0, 215],
54
54
  "Object.is": [0, 134, 219],
55
55
  "Object.isExtensible": [0, 8, 113, 216],
56
56
  "Object.isFrozen": [0, 8, 217],
@@ -60,7 +60,7 @@
60
60
  "Object.seal": [0, 8, 19, 51, 73, 109, 113, 222],
61
61
  "Object.setPrototypeOf": [0, 4, 58, 83, 118, 223],
62
62
  "Object.values": [0, 29, 112, 116, 119, 224],
63
- "Promise.any": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 157, 226, 262],
63
+ "Promise.any": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 157, 226],
64
64
  "Reflect.apply": [0, 52, 227],
65
65
  "Reflect.construct": [0, 3, 19, 26, 52, 55, 69, 78, 105, 106, 116, 157, 228],
66
66
  "Reflect.deleteProperty": [0, 229],
@@ -77,20 +77,20 @@
77
77
  "String.prototype.endsWith": [0, 26, 28, 59, 85, 103, 157, 158, 240],
78
78
  "String.fromCodePoint": [0, 241],
79
79
  "String.prototype.includes": [0, 26, 28, 85, 103, 157, 158, 242],
80
- "String.prototype.matchAll": [0, 3, 6, 26, 29, 31, 59, 69, 78, 85, 89, 90, 105, 106, 112, 116, 126, 127, 128, 129, 130, 131, 132, 135, 139, 141, 157, 158, 244, 263],
80
+ "String.prototype.matchAll": [0, 3, 6, 26, 29, 31, 59, 69, 78, 85, 89, 90, 105, 106, 112, 116, 126, 127, 128, 129, 130, 131, 132, 135, 139, 141, 157, 158, 244],
81
81
  "String.prototype.padEnd": [0, 26, 142, 143, 144, 157, 158, 245],
82
82
  "String.prototype.padStart": [0, 26, 142, 143, 144, 157, 158, 246],
83
83
  "String.raw": [0, 26, 157, 158, 247],
84
84
  "String.prototype.repeat": [0, 26, 144, 157, 158, 248],
85
- "String.prototype.replaceAll": [0, 26, 65, 85, 128, 129, 157, 158, 249, 264],
85
+ "String.prototype.replaceAll": [0, 26, 65, 85, 128, 129, 157, 158, 249],
86
86
  "String.prototype.startsWith": [0, 26, 28, 59, 85, 103, 157, 158, 250],
87
87
  "String.prototype.substr": [0, 26, 157, 158, 251],
88
88
  "String.prototype.trim": [0, 26, 146, 148, 157, 158, 165, 256],
89
89
  "String.prototype.trimEnd": [0, 26, 145, 146, 148, 157, 158, 165, 252, 254],
90
90
  "String.prototype.trimStart": [0, 26, 146, 147, 148, 157, 158, 165, 253, 255],
91
91
  "String.prototype.link": [0, 26, 30, 140, 157, 158, 243],
92
- "Promise.allSettled": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 157, 225, 261],
93
- "focus-visible": [265]
92
+ "Promise.allSettled": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 157, 225, 257],
93
+ "focus-visible": [258]
94
94
  },
95
- "maxSize": 159806
95
+ "maxSize": 159437
96
96
  }
@@ -14,7 +14,8 @@
14
14
  {
15
15
  "name": "Array.prototype.at",
16
16
  "modules": [
17
- "es.array.at"
17
+ "es.array.at",
18
+ "esnext.array.at"
18
19
  ],
19
20
  "corejs": true
20
21
  },
@@ -70,14 +71,16 @@
70
71
  {
71
72
  "name": "Array.prototype.findLast",
72
73
  "modules": [
73
- "es.array.find-last"
74
+ "es.array.find-last",
75
+ "esnext.array.find-last"
74
76
  ],
75
77
  "corejs": true
76
78
  },
77
79
  {
78
80
  "name": "Array.prototype.findLastIndex",
79
81
  "modules": [
80
- "es.array.find-last-index"
82
+ "es.array.find-last-index",
83
+ "esnext.array.find-last-index"
81
84
  ],
82
85
  "corejs": true
83
86
  },
@@ -357,7 +360,8 @@
357
360
  {
358
361
  "name": "Object.hasOwn",
359
362
  "modules": [
360
- "es.object.has-own"
363
+ "es.object.has-own",
364
+ "esnext.object.has-own"
361
365
  ],
362
366
  "corejs": true
363
367
  },
@@ -427,7 +431,8 @@
427
431
  {
428
432
  "name": "Promise.any",
429
433
  "modules": [
430
- "es.promise.any"
434
+ "es.promise.any",
435
+ "esnext.promise.any"
431
436
  ],
432
437
  "corejs": true
433
438
  },
@@ -546,7 +551,8 @@
546
551
  {
547
552
  "name": "String.prototype.matchAll",
548
553
  "modules": [
549
- "es.string.match-all"
554
+ "es.string.match-all",
555
+ "esnext.string.match-all"
550
556
  ],
551
557
  "corejs": true
552
558
  },
@@ -581,7 +587,8 @@
581
587
  {
582
588
  "name": "String.prototype.replaceAll",
583
589
  "modules": [
584
- "es.string.replace-all"
590
+ "es.string.replace-all",
591
+ "esnext.string.replace-all"
585
592
  ],
586
593
  "corejs": true
587
594
  },
@@ -627,60 +634,11 @@
627
634
  ],
628
635
  "corejs": true
629
636
  },
630
- {
631
- "name": "Array.prototype.at",
632
- "modules": [
633
- "esnext.array.at"
634
- ],
635
- "corejs": true
636
- },
637
- {
638
- "name": "Array.prototype.findLast",
639
- "modules": [
640
- "esnext.array.find-last"
641
- ],
642
- "corejs": true
643
- },
644
- {
645
- "name": "Array.prototype.findLastIndex",
646
- "modules": [
647
- "esnext.array.find-last-index"
648
- ],
649
- "corejs": true
650
- },
651
- {
652
- "name": "Object.hasOwn",
653
- "modules": [
654
- "esnext.object.has-own"
655
- ],
656
- "corejs": true
657
- },
658
637
  {
659
638
  "name": "Promise.allSettled",
660
639
  "modules": [
661
640
  "esnext.promise.all-settled"
662
641
  ],
663
642
  "corejs": true
664
- },
665
- {
666
- "name": "Promise.any",
667
- "modules": [
668
- "esnext.promise.any"
669
- ],
670
- "corejs": true
671
- },
672
- {
673
- "name": "String.prototype.matchAll",
674
- "modules": [
675
- "esnext.string.match-all"
676
- ],
677
- "corejs": true
678
- },
679
- {
680
- "name": "String.prototype.replaceAll",
681
- "modules": [
682
- "esnext.string.replace-all"
683
- ],
684
- "corejs": true
685
643
  }
686
644
  ]
@@ -122,13 +122,14 @@ class RenderBlockingResources extends Audit {
122
122
  * @return {Promise<{fcpWastedMs: number, lcpWastedMs: number, results: Array<{url: string, totalBytes: number, wastedMs: number}>}>}
123
123
  */
124
124
  static async computeResults(artifacts, context) {
125
+ const settings = context.settings;
125
126
  const gatherContext = artifacts.GatherContext;
126
127
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
127
128
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
128
129
  const simulatorData = {devtoolsLog, settings: context.settings};
129
130
  const simulator = await LoadSimulator.request(simulatorData, context);
130
131
  const wastedCssBytes = await RenderBlockingResources.computeWastedCSSBytes(artifacts, context);
131
- const navInsights = await NavigationInsights.request(trace, context);
132
+ const navInsights = await NavigationInsights.request({trace, settings}, context);
132
133
 
133
134
  const renderBlocking = navInsights.model.RenderBlocking;
134
135
  if (renderBlocking instanceof Error) throw renderBlocking;
@@ -168,10 +168,11 @@ class CriticalRequestChains extends Audit {
168
168
  * @return {Promise<LH.Audit.Product>}
169
169
  */
170
170
  static async audit(artifacts, context) {
171
+ const settings = context.settings;
171
172
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
172
173
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
173
174
  const URL = artifacts.URL;
174
- const chains = await ComputedChains.request({devtoolsLog, trace, URL}, context);
175
+ const chains = await ComputedChains.request({settings, devtoolsLog, trace, URL}, context);
175
176
  let chainCount = 0;
176
177
  /**
177
178
  * @param {LH.Audit.Details.SimpleCriticalRequestNode} node
@@ -16,9 +16,10 @@ import {Audit} from '../audit.js';
16
16
  * @return {Promise<import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined>}
17
17
  */
18
18
  async function getInsightSet(artifacts, context) {
19
+ const settings = context.settings;
19
20
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
20
21
  const processedTrace = await ProcessedTrace.request(trace, context);
21
- const traceEngineResult = await TraceEngineResult.request({trace}, context);
22
+ const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
22
23
 
23
24
  const navigationId = processedTrace.timeOriginEvt.args.data?.navigationId;
24
25
  const key = navigationId ?? NO_NAVIGATION;
@@ -57,8 +57,9 @@ class LayoutShifts extends Audit {
57
57
  * @return {Promise<LH.Audit.Product>}
58
58
  */
59
59
  static async audit(artifacts, context) {
60
+ const settings = context.settings;
60
61
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
61
- const traceEngineResult = await TraceEngineResult.request({trace}, context);
62
+ const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
62
63
  const clusters = traceEngineResult.data.LayoutShifts.clusters ?? [];
63
64
  const {cumulativeLayoutShift: clsSavings, impactByNodeId} =
64
65
  await CumulativeLayoutShiftComputed.request(trace, context);
@@ -192,7 +192,8 @@ class LongTasks extends Audit {
192
192
  taskTimingsByEvent = new Map();
193
193
 
194
194
  const simulatorOptions = {devtoolsLog, settings: context.settings};
195
- const pageGraph = await PageDependencyGraph.request({trace, devtoolsLog, URL}, context);
195
+ const pageGraph =
196
+ await PageDependencyGraph.request({settings, trace, devtoolsLog, URL}, context);
196
197
  const simulator = await LoadSimulator.request(simulatorOptions, context);
197
198
  const simulation = await simulator.simulate(pageGraph, {label: 'long-tasks-diagnostic'});
198
199
  for (const [node, timing] of simulation.nodeTimings.entries()) {
@@ -114,8 +114,12 @@ class ScriptTreemapDataAudit extends Audit {
114
114
  */
115
115
  function collapseAll(node) {
116
116
  while (node.children && node.children.length === 1) {
117
- node.name += '/' + node.children[0].name;
118
- node.children = node.children[0].children;
117
+ const child = node.children[0];
118
+ node.name += '/' + child.name;
119
+ if (child.duplicatedNormalizedModuleName) {
120
+ node.duplicatedNormalizedModuleName = child.duplicatedNormalizedModuleName;
121
+ }
122
+ node.children = child.children;
119
123
  }
120
124
 
121
125
  if (node.children) {
@@ -137,7 +137,7 @@ class UsesRelPreconnectAudit extends Audit {
137
137
  MainResource.request({devtoolsLog, URL: artifacts.URL}, context),
138
138
  LoadSimulator.request({devtoolsLog, settings}, context),
139
139
  ProcessedNavigation.request(trace, context),
140
- PageDependencyGraph.request({trace, devtoolsLog, URL: artifacts.URL}, context),
140
+ PageDependencyGraph.request({settings, trace, devtoolsLog, URL: artifacts.URL}, context),
141
141
  ]);
142
142
 
143
143
  const {rtt, additionalRttByOrigin} = loadSimulator.getOptions();
@@ -212,6 +212,7 @@ class UsesRelPreloadAudit extends Audit {
212
212
  * @return {Promise<LH.Audit.Product>}
213
213
  */
214
214
  static async audit(artifacts, context) {
215
+ const settings = context.settings;
215
216
  const trace = artifacts.traces[UsesRelPreloadAudit.DEFAULT_PASS];
216
217
  const devtoolsLog = artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
217
218
  const URL = artifacts.URL;
@@ -219,7 +220,7 @@ class UsesRelPreloadAudit extends Audit {
219
220
 
220
221
  const [mainResource, graph, simulator] = await Promise.all([
221
222
  MainResource.request({devtoolsLog, URL}, context),
222
- PageDependencyGraph.request({trace, devtoolsLog, URL}, context),
223
+ PageDependencyGraph.request({settings, trace, devtoolsLog, URL}, context),
223
224
  LoadSimulator.request(simulatorOptions, context),
224
225
  ]);
225
226
 
@@ -4,6 +4,7 @@ declare const CriticalRequestChainsComputed: typeof CriticalRequestChains & {
4
4
  URL: LH.Artifacts["URL"];
5
5
  devtoolsLog: LH.DevtoolsLog;
6
6
  trace: LH.Trace;
7
+ settings: LH.Audit.Context["settings"];
7
8
  }, context: LH.Artifacts.ComputedContext) => ReturnType<typeof CriticalRequestChains.compute_>;
8
9
  };
9
10
  declare class CriticalRequestChains {
@@ -24,7 +25,7 @@ declare class CriticalRequestChains {
24
25
  */
25
26
  static extractChainsFromGraph(mainResource: LH.Artifacts.NetworkRequest, graph: LH.Gatherer.Simulation.GraphNode): LH.Artifacts.CriticalRequestNode;
26
27
  /**
27
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace}} data
28
+ * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
28
29
  * @param {LH.Artifacts.ComputedContext} context
29
30
  * @return {Promise<LH.Artifacts.CriticalRequestNode>}
30
31
  */
@@ -32,6 +33,7 @@ declare class CriticalRequestChains {
32
33
  URL: LH.Artifacts["URL"];
33
34
  devtoolsLog: LH.DevtoolsLog;
34
35
  trace: LH.Trace;
36
+ settings: LH.Audit.Context["settings"];
35
37
  }, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.CriticalRequestNode>;
36
38
  }
37
39
  import * as Lantern from '../lib/lantern/lantern.js';
@@ -126,7 +126,7 @@ class CriticalRequestChains {
126
126
  }
127
127
 
128
128
  /**
129
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace}} data
129
+ * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
130
130
  * @param {LH.Artifacts.ComputedContext} context
131
131
  * @return {Promise<LH.Artifacts.CriticalRequestNode>}
132
132
  */
@@ -139,5 +139,5 @@ class CriticalRequestChains {
139
139
  }
140
140
 
141
141
  const CriticalRequestChainsComputed =
142
- makeComputedArtifact(CriticalRequestChains, ['URL', 'devtoolsLog', 'trace']);
142
+ makeComputedArtifact(CriticalRequestChains, ['URL', 'devtoolsLog', 'trace', 'settings']);
143
143
  export {CriticalRequestChainsComputed as CriticalRequestChains};
@@ -1,6 +1,9 @@
1
1
  export { NavigationInsightsComputed as NavigationInsights };
2
2
  declare const NavigationInsightsComputed: typeof NavigationInsights & {
3
- request: (dependencies: import("../index.js").Trace, context: LH.Artifacts.ComputedContext) => ReturnType<typeof NavigationInsights.compute_>;
3
+ request: (dependencies: {
4
+ trace: LH.Trace;
5
+ settings: LH.Audit.Context["settings"];
6
+ }, context: LH.Artifacts.ComputedContext) => ReturnType<typeof NavigationInsights.compute_>;
4
7
  };
5
8
  /**
6
9
  * @fileoverview Gets insights from the shared trace engine for the navigation audited by Lighthouse.
@@ -8,9 +11,12 @@ declare const NavigationInsightsComputed: typeof NavigationInsights & {
8
11
  */
9
12
  declare class NavigationInsights {
10
13
  /**
11
- * @param {LH.Trace} trace
14
+ * @param {{trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
12
15
  * @param {LH.Artifacts.ComputedContext} context
13
16
  */
14
- static compute_(trace: LH.Trace, context: LH.Artifacts.ComputedContext): Promise<import("@paulirish/trace_engine/models/trace/insights/types.js").InsightSet>;
17
+ static compute_(data: {
18
+ trace: LH.Trace;
19
+ settings: LH.Audit.Context["settings"];
20
+ }, context: LH.Artifacts.ComputedContext): Promise<import("@paulirish/trace_engine/models/trace/insights/types.js").InsightSet>;
15
21
  }
16
22
  //# sourceMappingURL=navigation-insights.d.ts.map
@@ -14,12 +14,13 @@ import {TraceEngineResult} from './trace-engine-result.js';
14
14
  */
15
15
  class NavigationInsights {
16
16
  /**
17
- * @param {LH.Trace} trace
17
+ * @param {{trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
18
18
  * @param {LH.Artifacts.ComputedContext} context
19
19
  */
20
- static async compute_(trace, context) {
20
+ static async compute_(data, context) {
21
+ const {trace, settings} = data;
21
22
  const processedTrace = await ProcessedTrace.request(trace, context);
22
- const traceEngineResult = await TraceEngineResult.request({trace}, context);
23
+ const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
23
24
 
24
25
  const navigationId = processedTrace.timeOriginEvt.args.data?.navigationId;
25
26
  if (!navigationId) throw new Error('No navigationId found');
@@ -31,5 +32,5 @@ class NavigationInsights {
31
32
  }
32
33
  }
33
34
 
34
- const NavigationInsightsComputed = makeComputedArtifact(NavigationInsights, null);
35
+ const NavigationInsightsComputed = makeComputedArtifact(NavigationInsights, ['trace', 'settings']);
35
36
  export {NavigationInsightsComputed as NavigationInsights};
@@ -3,19 +3,21 @@ declare const PageDependencyGraphComputed: typeof PageDependencyGraph & {
3
3
  request: (dependencies: {
4
4
  trace: LH.Trace;
5
5
  devtoolsLog: LH.DevtoolsLog;
6
+ settings: LH.Audit.Context["settings"];
6
7
  URL: LH.Artifacts["URL"];
7
8
  fromTrace?: boolean;
8
9
  }, context: LH.Artifacts.ComputedContext) => ReturnType<typeof PageDependencyGraph.compute_>;
9
10
  };
10
11
  declare class PageDependencyGraph {
11
12
  /**
12
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
13
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings'], URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
13
14
  * @param {LH.Artifacts.ComputedContext} context
14
15
  * @return {Promise<LH.Gatherer.Simulation.GraphNode>}
15
16
  */
16
17
  static compute_(data: {
17
18
  trace: LH.Trace;
18
19
  devtoolsLog: LH.DevtoolsLog;
20
+ settings: LH.Audit.Context["settings"];
19
21
  URL: LH.Artifacts["URL"];
20
22
  fromTrace?: boolean;
21
23
  }, context: LH.Artifacts.ComputedContext): Promise<LH.Gatherer.Simulation.GraphNode>;
@@ -13,19 +13,19 @@ import {TraceEngineResult} from './trace-engine-result.js';
13
13
 
14
14
  class PageDependencyGraph {
15
15
  /**
16
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
16
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings'], URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
17
17
  * @param {LH.Artifacts.ComputedContext} context
18
18
  * @return {Promise<LH.Gatherer.Simulation.GraphNode>}
19
19
  */
20
20
  static async compute_(data, context) {
21
- const {trace, devtoolsLog, URL} = data;
21
+ const {trace, settings, devtoolsLog, URL} = data;
22
22
  const [{mainThreadEvents}, networkRecords] = await Promise.all([
23
23
  ProcessedTrace.request(trace, context),
24
24
  NetworkRecords.request(devtoolsLog, context),
25
25
  ]);
26
26
 
27
27
  if (data.fromTrace) {
28
- const traceEngineResult = await TraceEngineResult.request({trace}, context);
28
+ const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
29
29
  const traceEngineData = traceEngineResult.data;
30
30
  const requests =
31
31
  Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData);
@@ -40,6 +40,6 @@ class PageDependencyGraph {
40
40
  }
41
41
  }
42
42
 
43
- const PageDependencyGraphComputed =
44
- makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL', 'fromTrace']);
43
+ const PageDependencyGraphComputed = makeComputedArtifact(PageDependencyGraph,
44
+ ['devtoolsLog', 'settings', 'trace', 'URL', 'fromTrace']);
45
45
  export {PageDependencyGraphComputed as PageDependencyGraph};
@@ -2,6 +2,7 @@ export { TraceEngineResultComputed as TraceEngineResult };
2
2
  declare const TraceEngineResultComputed: typeof TraceEngineResult & {
3
3
  request: (dependencies: {
4
4
  trace: LH.Trace;
5
+ settings: LH.Audit.Context["settings"];
5
6
  }, context: LH.Artifacts.ComputedContext) => ReturnType<typeof TraceEngineResult.compute_>;
6
7
  };
7
8
  /**
@@ -10,9 +11,10 @@ declare const TraceEngineResultComputed: typeof TraceEngineResult & {
10
11
  declare class TraceEngineResult {
11
12
  /**
12
13
  * @param {LH.TraceEvent[]} traceEvents
14
+ * @param {LH.Audit.Context['settings']} settings
13
15
  * @return {Promise<LH.Artifacts.TraceEngineResult>}
14
16
  */
15
- static runTraceEngine(traceEvents: LH.TraceEvent[]): Promise<LH.Artifacts.TraceEngineResult>;
17
+ static runTraceEngine(traceEvents: LH.TraceEvent[], settings: LH.Audit.Context["settings"]): Promise<LH.Artifacts.TraceEngineResult>;
16
18
  /**
17
19
  * Adapts the given DevTools function that returns a localized string to one
18
20
  * that returns a LH.IcuMessage.
@@ -45,12 +47,13 @@ declare class TraceEngineResult {
45
47
  */
46
48
  static localizeInsights(insightSets: import("@paulirish/trace_engine/models/trace/insights/types.js").TraceInsightSets): void;
47
49
  /**
48
- * @param {{trace: LH.Trace}} data
50
+ * @param {{trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
49
51
  * @param {LH.Artifacts.ComputedContext} context
50
52
  * @return {Promise<LH.Artifacts.TraceEngineResult>}
51
53
  */
52
54
  static compute_(data: {
53
55
  trace: LH.Trace;
56
+ settings: LH.Audit.Context["settings"];
54
57
  }, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.TraceEngineResult>;
55
58
  }
56
59
  import * as LH from '../../types/lh.js';
@@ -4,6 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import log from 'lighthouse-logger';
8
+
7
9
  import * as i18n from '../lib/i18n/i18n.js';
8
10
  import * as TraceEngine from '../lib/trace-engine.js';
9
11
  import {makeComputedArtifact} from './computed-artifact.js';
@@ -17,15 +19,35 @@ import * as LH from '../../types/lh.js';
17
19
  class TraceEngineResult {
18
20
  /**
19
21
  * @param {LH.TraceEvent[]} traceEvents
22
+ * @param {LH.Audit.Context['settings']} settings
20
23
  * @return {Promise<LH.Artifacts.TraceEngineResult>}
21
24
  */
22
- static async runTraceEngine(traceEvents) {
25
+ static async runTraceEngine(traceEvents, settings) {
23
26
  const processor = new TraceEngine.TraceProcessor(TraceEngine.TraceHandlers);
24
27
 
28
+ const lanternSettings = {};
29
+ if (settings.throttlingMethod) lanternSettings.throttlingMethod = settings.throttlingMethod;
30
+ if (settings.throttling) lanternSettings.throttling = settings.throttling;
31
+ if (settings.precomputedLanternData) {
32
+ lanternSettings.precomputedLanternData = settings.precomputedLanternData;
33
+ }
34
+
25
35
  // eslint-disable-next-line max-len
26
36
  await processor.parse(/** @type {import('@paulirish/trace_engine').Types.Events.Event[]} */ (
27
37
  traceEvents
28
- ), {});
38
+ ), {
39
+ logger: {
40
+ start(id) {
41
+ const logId = `lh:computed:TraceEngineResult:${id}`;
42
+ log.time({msg: `Trace Engine ${id}`, id: logId});
43
+ },
44
+ end(id) {
45
+ const logId = `lh:computed:TraceEngineResult:${id}`;
46
+ log.timeEnd({msg: `Trace Engine ${id}`, id: logId});
47
+ },
48
+ },
49
+ lanternSettings,
50
+ });
29
51
  if (!processor.parsedTrace) throw new Error('No data');
30
52
  if (!processor.insights) throw new Error('No insights');
31
53
  this.localizeInsights(processor.insights);
@@ -177,7 +199,7 @@ class TraceEngineResult {
177
199
  }
178
200
 
179
201
  /**
180
- * @param {{trace: LH.Trace}} data
202
+ * @param {{trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
181
203
  * @param {LH.Artifacts.ComputedContext} context
182
204
  * @return {Promise<LH.Artifacts.TraceEngineResult>}
183
205
  */
@@ -207,10 +229,10 @@ class TraceEngineResult {
207
229
  }
208
230
  }
209
231
 
210
- const result = await TraceEngineResult.runTraceEngine(traceEvents);
232
+ const result = await TraceEngineResult.runTraceEngine(traceEvents, data.settings);
211
233
  return result;
212
234
  }
213
235
  }
214
236
 
215
- const TraceEngineResultComputed = makeComputedArtifact(TraceEngineResult, ['trace']);
237
+ const TraceEngineResultComputed = makeComputedArtifact(TraceEngineResult, ['trace', 'settings']);
216
238
  export {TraceEngineResultComputed as TraceEngineResult};
@@ -386,7 +386,8 @@ class TraceElements extends BaseGatherer {
386
386
  const session = context.driver.defaultSession;
387
387
 
388
388
  const trace = context.dependencies.Trace;
389
- const traceEngineResult = await TraceEngineResult.request({trace}, context);
389
+ const settings = context.settings;
390
+ const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
390
391
  const rootCauses = context.dependencies.RootCauses;
391
392
 
392
393
  const processedTrace = await ProcessedTrace.request(trace, context);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "12.4.0-dev.20250312",
4
+ "version": "12.4.0-dev.20250314",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -184,7 +184,7 @@
184
184
  "webtreemap-cdt": "^3.2.1"
185
185
  },
186
186
  "dependencies": {
187
- "@paulirish/trace_engine": "0.0.47",
187
+ "@paulirish/trace_engine": "0.0.48",
188
188
  "@sentry/node": "^7.0.0",
189
189
  "axe-core": "^4.10.2",
190
190
  "chrome-launcher": "^1.1.2",