lighthouse 12.5.1-dev.20250413 → 12.5.1-dev.20250415

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.
Files changed (61) hide show
  1. package/cli/test/smokehouse/config/exclusions.js +2 -0
  2. package/core/audits/insights/{use-cache-insight.d.ts → cache-insight.d.ts} +3 -3
  3. package/core/audits/insights/{use-cache-insight.js → cache-insight.js} +13 -10
  4. package/core/audits/insights/duplicated-javascript-insight.js +3 -1
  5. package/core/audits/insights/legacy-javascript-insight.d.ts +23 -0
  6. package/core/audits/insights/legacy-javascript-insight.js +101 -0
  7. package/core/audits/insights/modern-http-insight.d.ts +11 -0
  8. package/core/audits/insights/modern-http-insight.js +53 -0
  9. package/core/audits/insights/third-parties-insight.d.ts +0 -1
  10. package/core/audits/insights/third-parties-insight.js +27 -23
  11. package/core/config/default-config.js +6 -2
  12. package/core/config/experimental-config.js +3 -1
  13. package/core/gather/gatherers/dobetterweb/optimized-images.js +3 -10
  14. package/package.json +2 -2
  15. package/shared/localization/locales/ar-XB.json +66 -0
  16. package/shared/localization/locales/ar.json +66 -0
  17. package/shared/localization/locales/bg.json +66 -0
  18. package/shared/localization/locales/ca.json +66 -0
  19. package/shared/localization/locales/cs.json +66 -0
  20. package/shared/localization/locales/da.json +66 -0
  21. package/shared/localization/locales/de.json +66 -0
  22. package/shared/localization/locales/el.json +66 -0
  23. package/shared/localization/locales/en-GB.json +66 -0
  24. package/shared/localization/locales/en-US.json +55 -22
  25. package/shared/localization/locales/en-XL.json +55 -22
  26. package/shared/localization/locales/es-419.json +66 -0
  27. package/shared/localization/locales/es.json +67 -1
  28. package/shared/localization/locales/fi.json +66 -0
  29. package/shared/localization/locales/fil.json +66 -0
  30. package/shared/localization/locales/fr.json +66 -0
  31. package/shared/localization/locales/he.json +66 -0
  32. package/shared/localization/locales/hi.json +66 -0
  33. package/shared/localization/locales/hr.json +66 -0
  34. package/shared/localization/locales/hu.json +66 -0
  35. package/shared/localization/locales/id.json +66 -0
  36. package/shared/localization/locales/it.json +67 -1
  37. package/shared/localization/locales/ja.json +66 -0
  38. package/shared/localization/locales/ko.json +66 -0
  39. package/shared/localization/locales/lt.json +66 -0
  40. package/shared/localization/locales/lv.json +66 -0
  41. package/shared/localization/locales/nl.json +66 -0
  42. package/shared/localization/locales/no.json +66 -0
  43. package/shared/localization/locales/pl.json +66 -0
  44. package/shared/localization/locales/pt-PT.json +66 -0
  45. package/shared/localization/locales/pt.json +67 -1
  46. package/shared/localization/locales/ro.json +66 -0
  47. package/shared/localization/locales/ru.json +66 -0
  48. package/shared/localization/locales/sk.json +66 -0
  49. package/shared/localization/locales/sl.json +66 -0
  50. package/shared/localization/locales/sr-Latn.json +66 -0
  51. package/shared/localization/locales/sr.json +66 -0
  52. package/shared/localization/locales/sv.json +66 -0
  53. package/shared/localization/locales/ta.json +69 -3
  54. package/shared/localization/locales/te.json +66 -0
  55. package/shared/localization/locales/th.json +66 -0
  56. package/shared/localization/locales/tr.json +66 -0
  57. package/shared/localization/locales/uk.json +66 -0
  58. package/shared/localization/locales/vi.json +66 -0
  59. package/shared/localization/locales/zh-HK.json +67 -1
  60. package/shared/localization/locales/zh-TW.json +67 -1
  61. package/shared/localization/locales/zh.json +66 -0
@@ -28,6 +28,8 @@ const exclusions = {
28
28
  'byte-efficiency', 'byte-gzip', 'perf-preload',
29
29
  // Disabled because a renderer crash also breaks devtools frontend
30
30
  'crash',
31
+ // Disabled because is timing out.
32
+ 'oopif-scripts',
31
33
  ],
32
34
  };
33
35
 
@@ -1,5 +1,5 @@
1
- export default UseCacheInsight;
2
- declare class UseCacheInsight extends Audit {
1
+ export default CacheInsight;
2
+ declare class CacheInsight extends Audit {
3
3
  /**
4
4
  * @param {LH.Artifacts} artifacts
5
5
  * @param {LH.Audit.Context} context
@@ -8,4 +8,4 @@ declare class UseCacheInsight extends Audit {
8
8
  static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
9
  }
10
10
  import { Audit } from '../audit.js';
11
- //# sourceMappingURL=use-cache-insight.d.ts.map
11
+ //# sourceMappingURL=cache-insight.d.ts.map
@@ -4,22 +4,22 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/UseCache.js';
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Cache.js';
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
11
  import {adaptInsightToAuditProduct} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
- const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/UseCache.js', UIStrings);
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js', UIStrings);
15
15
 
16
- class UseCacheInsight extends Audit {
16
+ class CacheInsight extends Audit {
17
17
  /**
18
18
  * @return {LH.Audit.Meta}
19
19
  */
20
20
  static get meta() {
21
21
  return {
22
- id: 'use-cache-insight',
22
+ id: 'cache-insight',
23
23
  title: str_(UIStrings.title),
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
@@ -35,7 +35,7 @@ class UseCacheInsight extends Audit {
35
35
  * @return {Promise<LH.Audit.Product>}
36
36
  */
37
37
  static async audit(artifacts, context) {
38
- return adaptInsightToAuditProduct(artifacts, context, 'UseCache', (insight) => {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'Cache', (insight) => {
39
39
  /** @type {LH.Audit.Details.Table['headings']} */
40
40
  const headings = [
41
41
  /* eslint-disable max-len */
@@ -44,11 +44,14 @@ class UseCacheInsight extends Audit {
44
44
  {key: 'totalBytes', 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
50
  /** @type {LH.Audit.Details.Table['items']} */
48
- const items = insight.requests.map(request => ({
49
- url: request.request.args.data.url,
50
- cacheLifetimeMs: request.ttl * 1000,
51
- totalBytes: request.request.args.data.encodedDataLength,
51
+ const items = values.map(value => ({
52
+ url: value.request.args.data.url,
53
+ cacheLifetimeMs: value.ttl * 1000,
54
+ totalBytes: value.request.args.data.encodedDataLength,
52
55
  }));
53
56
  return Audit.makeTableDetails(headings, items, {
54
57
  sortedBy: ['totalBytes'],
@@ -58,4 +61,4 @@ class UseCacheInsight extends Audit {
58
61
  }
59
62
  }
60
63
 
61
- export default UseCacheInsight;
64
+ export default CacheInsight;
@@ -25,8 +25,10 @@ class DuplicatedJavaScriptInsight extends Audit {
25
25
  title: str_(UIStrings.title),
26
26
  failureTitle: str_(UIStrings.title),
27
27
  description: str_(UIStrings.description),
28
- guidanceLevel: 3, // TODO: confirm/change.
28
+ guidanceLevel: 2,
29
29
  requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
30
+ // TODO: enable when implemented.
31
+ // replacesAudits: ['duplicated-javascript'],
30
32
  };
31
33
  }
32
34
 
@@ -0,0 +1,23 @@
1
+ export default LegacyJavaScriptInsight;
2
+ export type Item = LH.Audit.Details.TableItem & {
3
+ subItems: {
4
+ type: "subitems";
5
+ items: SubItem[];
6
+ };
7
+ };
8
+ export type SubItem = {
9
+ signal: string;
10
+ location: LH.Audit.Details.SourceLocationValue;
11
+ };
12
+ /** @typedef {LH.Audit.Details.TableItem & {subItems: {type: 'subitems', items: SubItem[]}}} Item */
13
+ /** @typedef {{signal: string, location: LH.Audit.Details.SourceLocationValue}} SubItem */
14
+ declare class LegacyJavaScriptInsight extends Audit {
15
+ /**
16
+ * @param {LH.Artifacts} artifacts
17
+ * @param {LH.Audit.Context} context
18
+ * @return {Promise<LH.Audit.Product>}
19
+ */
20
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
21
+ }
22
+ import { Audit } from '../audit.js';
23
+ //# sourceMappingURL=legacy-javascript-insight.d.ts.map
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {JSBundles} from '../../computed/js-bundles.js';
12
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
13
+
14
+ // eslint-disable-next-line max-len
15
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js', UIStrings);
16
+
17
+ /** @typedef {LH.Audit.Details.TableItem & {subItems: {type: 'subitems', items: SubItem[]}}} Item */
18
+ /** @typedef {{signal: string, location: LH.Audit.Details.SourceLocationValue}} SubItem */
19
+
20
+ class LegacyJavaScriptInsight extends Audit {
21
+ /**
22
+ * @return {LH.Audit.Meta}
23
+ */
24
+ static get meta() {
25
+ return {
26
+ id: 'legacy-javascript-insight',
27
+ title: str_(UIStrings.title),
28
+ failureTitle: str_(UIStrings.title),
29
+ description: str_(UIStrings.description),
30
+ guidanceLevel: 2,
31
+ requiredArtifacts: ['traces', 'Scripts', 'SourceMaps'],
32
+ };
33
+ }
34
+
35
+ /**
36
+ * @param {LH.Artifacts} artifacts
37
+ * @param {LH.Audit.Context} context
38
+ * @return {Promise<LH.Audit.Product>}
39
+ */
40
+ static async audit(artifacts, context) {
41
+ const bundles = await JSBundles.request(artifacts, context);
42
+
43
+ return adaptInsightToAuditProduct(artifacts, context, 'LegacyJavaScript', (insight) => {
44
+ /** @type {LH.Audit.Details.Table['headings']} */
45
+ const headings = [
46
+ /* eslint-disable max-len */
47
+ {key: 'url', valueType: 'url', subItemsHeading: {key: 'location', valueType: 'source-location'}, label: str_(i18n.UIStrings.columnURL)},
48
+ {key: null, valueType: 'code', subItemsHeading: {key: 'signal'}, label: ''},
49
+ {key: 'wastedBytes', valueType: 'bytes', label: str_(UIStrings.columnWastedBytes)},
50
+ /* eslint-enable max-len */
51
+ ];
52
+
53
+ /** @type {Item[]} */
54
+ const items = [];
55
+
56
+ for (const [script, result] of insight.legacyJavaScriptResults) {
57
+ const bundle = bundles.find(bundle => bundle.script.scriptId === script.scriptId);
58
+
59
+ /** @type {Item} */
60
+ const item = {
61
+ url: script.url ?? '',
62
+ wastedBytes: result.estimatedByteSavings,
63
+ subItems: {
64
+ type: 'subitems',
65
+ items: [],
66
+ },
67
+ };
68
+
69
+ for (const match of result.matches) {
70
+ const {name, line, column} = match;
71
+ /** @type {SubItem} */
72
+ const subItem = {
73
+ signal: name,
74
+ location: Audit.makeSourceLocation(script.url ?? '', line, column, bundle),
75
+ };
76
+ item.subItems.items.push(subItem);
77
+ }
78
+
79
+ items.push(item);
80
+ }
81
+
82
+ // TODO: add this warning to the insight.
83
+ // for (const bundle of bundles) {
84
+ // if (classifiedEntities.isFirstParty(bundle.script.url)) {
85
+ // if (bundle.rawMap.sources.some(s => s.match(/node_modules\/core-js\/modules\/es[67]/))) {
86
+ // if (!insight.warnings) {
87
+ // insight.warnings = [];
88
+ // }
89
+
90
+ // insight.warnings.push(str_(UIStrings.detectedCoreJs2Warning));
91
+ // break;
92
+ // }
93
+ // }
94
+ // }
95
+
96
+ return Audit.makeTableDetails(headings, items);
97
+ });
98
+ }
99
+ }
100
+
101
+ export default LegacyJavaScriptInsight;
@@ -0,0 +1,11 @@
1
+ export default ModernHTTPInsight;
2
+ declare class ModernHTTPInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=modern-http-insight.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ModernHTTP.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js', UIStrings);
15
+
16
+ class ModernHTTPInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'modern-http-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'SourceMaps'],
28
+ };
29
+ }
30
+
31
+ /**
32
+ * @param {LH.Artifacts} artifacts
33
+ * @param {LH.Audit.Context} context
34
+ * @return {Promise<LH.Audit.Product>}
35
+ */
36
+ static async audit(artifacts, context) {
37
+ return adaptInsightToAuditProduct(artifacts, context, 'ModernHTTP', (insight) => {
38
+ /** @type {LH.Audit.Details.Table['headings']} */
39
+ const headings = [
40
+ /* eslint-disable max-len */
41
+ {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
42
+ {key: 'protocol', valueType: 'text', label: str_(UIStrings.protocol)},
43
+ /* eslint-enable max-len */
44
+ ];
45
+ /** @type {LH.Audit.Details.Table['items']} */
46
+ const items =
47
+ insight.requests.map(r => ({url: r.args.data.url, protocol: r.args.data.protocol}));
48
+ return Audit.makeTableDetails(headings, items);
49
+ });
50
+ }
51
+ }
52
+
53
+ export default ModernHTTPInsight;
@@ -16,7 +16,6 @@ declare class ThirdPartiesInsight extends Audit {
16
16
  * @param {import('@paulirish/trace_engine/models/trace/insights/ThirdParties.js').ThirdPartiesInsightModel} insight
17
17
  * @return {Array<URLSummary>}
18
18
  */
19
- static makeSubItems(entity: LH.Artifacts.Entity, insight: import("@paulirish/trace_engine/models/trace/insights/ThirdParties.js").ThirdPartiesInsightModel): Array<URLSummary>;
20
19
  /**
21
20
  * @param {LH.Artifacts} artifacts
22
21
  * @param {LH.Audit.Context} context
@@ -41,18 +41,18 @@ class ThirdPartiesInsight extends Audit {
41
41
  * @param {import('@paulirish/trace_engine/models/trace/insights/ThirdParties.js').ThirdPartiesInsightModel} insight
42
42
  * @return {Array<URLSummary>}
43
43
  */
44
- static makeSubItems(entity, insight) {
45
- const urls = [...insight.urlsByEntity.get(entity) ?? []];
46
- return urls
47
- .map(url => ({
48
- url,
49
- mainThreadTime: 0,
50
- transferSize: 0,
51
- ...insight.summaryByUrl.get(url),
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
- }
44
+ // static makeSubItems(entity, insight) {
45
+ // const urls = [...insight.urlsByEntity.get(entity) ?? []];
46
+ // return urls
47
+ // .map(url => ({
48
+ // url,
49
+ // mainThreadTime: 0,
50
+ // transferSize: 0,
51
+ // ...insight.summaryByUrl.get(url),
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
@@ -61,8 +61,9 @@ class ThirdPartiesInsight extends Audit {
61
61
  */
62
62
  static async audit(artifacts, context) {
63
63
  return adaptInsightToAuditProduct(artifacts, context, 'ThirdParties', (insight) => {
64
- const thirdPartyEntities = [...insight.summaryByEntity.entries()]
65
- .filter((([entity, _]) => entity !== insight.firstPartyEntity));
64
+ const thirdPartySummaries = insight.summaries
65
+ .filter(summary => summary.entity !== insight.firstPartyEntity || null)
66
+ .sort((a, b) => b.mainThreadTime - a.mainThreadTime);
66
67
 
67
68
  /** @type {LH.Audit.Details.Table['headings']} */
68
69
  const headings = [
@@ -73,15 +74,18 @@ class ThirdPartiesInsight extends Audit {
73
74
  /* eslint-enable max-len */
74
75
  ];
75
76
  /** @type {LH.Audit.Details.Table['items']} */
76
- const items = thirdPartyEntities.map(([entity, summary]) => ({
77
- entity: entity.name,
78
- transferSize: summary.transferSize,
79
- mainThreadTime: summary.mainThreadTime,
80
- subItems: {
81
- type: /** @type {const} */ ('subitems'),
82
- items: ThirdPartiesInsight.makeSubItems(entity, insight),
83
- },
84
- }));
77
+ const items = thirdPartySummaries.map((summary) => {
78
+ return {
79
+ entity: summary.entity.name,
80
+ transferSize: summary.transferSize,
81
+ mainThreadTime: summary.mainThreadTime,
82
+ // TODO: fix this! we lost all the data ... https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6341914
83
+ // subItems: {
84
+ // type: /** @type {const} */ ('subitems'),
85
+ // items: ThirdPartiesInsight.makeSubItems(summary.entity, insight),
86
+ // },
87
+ };
88
+ });
85
89
  return Audit.makeTableDetails(headings, items, {isEntityGrouped: true});
86
90
  });
87
91
  }
@@ -309,6 +309,7 @@ const defaultConfig = {
309
309
  'seo/manual/structured-data',
310
310
  'work-during-interaction',
311
311
  'bf-cache',
312
+ 'insights/cache-insight',
312
313
  'insights/cls-culprits-insight',
313
314
  'insights/document-latency-insight',
314
315
  'insights/dom-size-insight',
@@ -319,11 +320,12 @@ const defaultConfig = {
319
320
  'insights/interaction-to-next-paint-insight',
320
321
  'insights/lcp-discovery-insight',
321
322
  'insights/lcp-phases-insight',
323
+ 'insights/legacy-javascript-insight',
324
+ 'insights/modern-http-insight',
322
325
  'insights/network-dependency-tree-insight',
323
326
  'insights/render-blocking-insight',
324
327
  'insights/slow-css-selector-insight',
325
328
  'insights/third-parties-insight',
326
- 'insights/use-cache-insight',
327
329
  'insights/viewport-insight',
328
330
  ],
329
331
  groups: {
@@ -409,6 +411,7 @@ const defaultConfig = {
409
411
  {id: 'interaction-to-next-paint', weight: 0, group: 'metrics', acronym: 'INP'},
410
412
 
411
413
  // Insight audits.
414
+ {id: 'cache-insight', weight: 0, group: 'hidden'},
412
415
  {id: 'cls-culprits-insight', weight: 0, group: 'hidden'},
413
416
  {id: 'document-latency-insight', weight: 0, group: 'hidden'},
414
417
  {id: 'dom-size-insight', weight: 0, group: 'hidden'},
@@ -419,11 +422,12 @@ const defaultConfig = {
419
422
  {id: 'interaction-to-next-paint-insight', weight: 0, group: 'hidden'},
420
423
  {id: 'lcp-discovery-insight', weight: 0, group: 'hidden'},
421
424
  {id: 'lcp-phases-insight', weight: 0, group: 'hidden'},
425
+ {id: 'legacy-javascript-insight', weight: 0, group: 'hidden'},
426
+ {id: 'modern-http-insight', weight: 0, group: 'hidden'},
422
427
  {id: 'network-dependency-tree-insight', weight: 0, group: 'hidden'},
423
428
  {id: 'render-blocking-insight', weight: 0, group: 'hidden'},
424
429
  {id: 'slow-css-selector-insight', weight: 0, group: 'hidden'},
425
430
  {id: 'third-parties-insight', weight: 0, group: 'hidden'},
426
- {id: 'use-cache-insight', weight: 0, group: 'hidden'},
427
431
  {id: 'viewport-insight', weight: 0, group: 'hidden'},
428
432
 
429
433
  // These are our "invisible" metrics. Not displayed, but still in the LHR.
@@ -27,6 +27,7 @@ const config = {
27
27
 
28
28
  // TODO: Remove this when insights aren't hidden by default
29
29
  // Insight audits.
30
+ {id: 'cache-insight', weight: 0, group: 'insights'},
30
31
  {id: 'cls-culprits-insight', weight: 0, group: 'insights'},
31
32
  {id: 'document-latency-insight', weight: 0, group: 'insights'},
32
33
  {id: 'dom-size-insight', weight: 0, group: 'insights'},
@@ -37,11 +38,12 @@ const config = {
37
38
  {id: 'interaction-to-next-paint-insight', weight: 0, group: 'insights'},
38
39
  {id: 'lcp-discovery-insight', weight: 0, group: 'insights'},
39
40
  {id: 'lcp-phases-insight', weight: 0, group: 'insights'},
41
+ {id: 'legacy-javascript-insight', weight: 0, group: 'insights'},
42
+ {id: 'modern-http-insight', weight: 0, group: 'insights'},
40
43
  {id: 'network-dependency-tree-insight', weight: 0, group: 'insights'},
41
44
  {id: 'render-blocking-insight', weight: 0, group: 'insights'},
42
45
  {id: 'slow-css-selector-insight', weight: 0, group: 'insights'},
43
46
  {id: 'third-parties-insight', weight: 0, group: 'insights'},
44
- {id: 'use-cache-insight', weight: 0, group: 'insights'},
45
47
  {id: 'viewport-insight', weight: 0, group: 'insights'},
46
48
  ],
47
49
  },
@@ -5,11 +5,9 @@
5
5
  */
6
6
 
7
7
  /**
8
- * @fileoverview Determines optimized jpeg/webp filesizes for all same-origin and dataURI images by
9
- * running the images through canvas in the browser context.
8
+ * @fileoverview Determines optimized jpeg/webp filesizes for all same-origin and dataURI images
10
9
  */
11
10
 
12
-
13
11
  import log from 'lighthouse-logger';
14
12
 
15
13
  import BaseGatherer from '../../base-gatherer.js';
@@ -133,7 +131,7 @@ class OptimizedImages extends BaseGatherer {
133
131
  const image = {failed: false, ...stats, ...record};
134
132
  results.push(image);
135
133
  } catch (err) {
136
- log.warn('optimized-images', err.message);
134
+ log.warn('optimized-images', err.message, record.url);
137
135
 
138
136
  // Track this with Sentry since these errors aren't surfaced anywhere else, but we don't
139
137
  // want to tank the entire run due to a single image.
@@ -164,12 +162,7 @@ class OptimizedImages extends BaseGatherer {
164
162
  .filterImageRequests(networkRecords)
165
163
  .sort((a, b) => b.resourceSize - a.resourceSize);
166
164
 
167
- const results = await this.computeOptimizedImages(context.driver.defaultSession, imageRecords);
168
- const successfulResults = results.filter(result => !result.failed);
169
- if (results.length && !successfulResults.length) {
170
- throw new Error('All image optimizations failed');
171
- }
172
- return results;
165
+ return await this.computeOptimizedImages(context.driver.defaultSession, imageRecords);
173
166
  }
174
167
  }
175
168
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "12.5.1-dev.20250413",
4
+ "version": "12.5.1-dev.20250415",
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.50",
187
+ "@paulirish/trace_engine": "0.0.51",
188
188
  "@sentry/node": "^7.0.0",
189
189
  "axe-core": "^4.10.3",
190
190
  "chrome-launcher": "^1.1.2",
@@ -2210,9 +2210,15 @@
2210
2210
  "node_modules/@paulirish/trace_engine/generated/Deprecation.js | GetUserMediaInsecureOrigin": {
2211
2211
  "message": "لم تعد الميزة getUserMedia() متوافقة مع المصادر غير الآمنة. لاستخدام هذه الميزة، يجب مراعاة نقل تطبيقك إلى مصدر آمن مثل HTTPS. لمعرفة مزيد من التفاصيل، يُرجى الاطّلاع على https://goo.gle/chrome-insecure-origins."
2212
2212
  },
2213
+ "node_modules/@paulirish/trace_engine/generated/Deprecation.js | H1UserAgentFontSizeInSection": {
2214
+ "message": "تم العثور على علامة <h1> ضِمن <article> أو <aside> أو <nav> أو <section>، ولا يتضمّن هذا العنصر حجمًا محدّدًا للخط. سيتم تغيير حجم نص هذا العنوان في هذا المتصفِّح قريبًا. يُرجى الاطّلاع على https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#specifying_a_uniform_font_size_for_h1 لمزيد من المعلومات."
2215
+ },
2213
2216
  "node_modules/@paulirish/trace_engine/generated/Deprecation.js | HostCandidateAttributeGetter": {
2214
2217
  "message": "تم إيقاف RTCPeerConnectionIceErrorEvent.hostCandidate نهائيًا. يُرجى استخدام RTCPeerConnectionIceErrorEvent.address أو RTCPeerConnectionIceErrorEvent.port بدلاً منها."
2215
2218
  },
2219
+ "node_modules/@paulirish/trace_engine/generated/Deprecation.js | IdentityDigitalCredentials": {
2220
+ "message": "تم إيقاف تنسيق طلب navigator.credentials.get()‎ لبيانات الاعتماد الرقمية نهائيًا، لذا يُرجى تعديل طلبك لاستخدام التنسيق الجديد."
2221
+ },
2216
2222
  "node_modules/@paulirish/trace_engine/generated/Deprecation.js | IdentityInCanMakePaymentEvent": {
2217
2223
  "message": "إنّ أصل التاجر والبيانات العشوائية من حدث مشغّل الخدمات في canmakepayment تم إيقافهما نهائيًا وستتم إزالتهما: topOrigin وpaymentRequestOrigin وmethodData وmodifiers."
2218
2224
  },
@@ -2363,6 +2369,24 @@
2363
2369
  "node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js | worstLayoutShiftCluster": {
2364
2370
  "message": "أسوأ مجموعة لمتغيّرات التصميم"
2365
2371
  },
2372
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | cacheTTL": {
2373
+ "message": "مدة البقاء (TTL) في ذاكرة التخزين المؤقت"
2374
+ },
2375
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | description": {
2376
+ "message": "يمكن لفترة التخزين المؤقت الطويلة زيادة سرعة الزيارات المتكررة إلى صفحتك. [مزيد من المعلومات](https://web.dev/uses-long-cache-ttl/)"
2377
+ },
2378
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | noRequestsToCache": {
2379
+ "message": "ما مِن طلبات تتضمّن سياسات ذاكرة تخزين مؤقت غير فعّالة"
2380
+ },
2381
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | others": {
2382
+ "message": "عدد العناصر المتبقية: {PH1}"
2383
+ },
2384
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | requestColumn": {
2385
+ "message": "طلب"
2386
+ },
2387
+ "node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js | title": {
2388
+ "message": "استخدام فترات التخزين المؤقت الفعّالة"
2389
+ },
2366
2390
  "node_modules/@paulirish/trace_engine/models/trace/insights/DOMSize.js | description": {
2367
2391
  "message": "إنّ الحجم الكبير لنموذج العناصر في المستند (DOM) يمكن أن يؤدي إلى زيادة مدة عمليات احتساب الأنماط وإعادة تدفق التنسيقات، ما يؤثر في سرعة استجابة الصفحة. وسيزيد هذا الحجم الكبير أيضًا من استخدام الذاكرة. [التعرّف على كيفية تجنُّب زيادة حجم DOM](https://developer.chrome.com/docs/lighthouse/performance/dom-size/)"
2368
2392
  },
@@ -2420,6 +2444,18 @@
2420
2444
  "node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js | uncompressedDownload": {
2421
2445
  "message": "عملية تنزيل غير مضغوطة"
2422
2446
  },
2447
+ "node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js | columnDuplicatedBytes": {
2448
+ "message": "وحدات البايت المكرّرة"
2449
+ },
2450
+ "node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js | columnSource": {
2451
+ "message": "المصدر"
2452
+ },
2453
+ "node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js | description": {
2454
+ "message": "يمكنك إزالة وحدات JavaScript الكبيرة المكرّرة من الحِزم لتقليل وحدات البايت غير الضرورية التي يستهلكها نشاط الشبكة."
2455
+ },
2456
+ "node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js | title": {
2457
+ "message": "مصادر JavaScript المكرّرة"
2458
+ },
2423
2459
  "node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js | description": {
2424
2460
  "message": "يمكنك ضبط [font-display](https://developer.chrome.com/blog/font-display) على swap أو optional لضمان ظهور النص بشكل ثابت. ويمكن تحسين swap بشكل أكبر للتخفيف من تغييرات التصميم باستخدام [إجراءات تجاوز مقاييس الخطوط](https://developer.chrome.com/blog/font-fallbacks)."
2425
2461
  },
@@ -2447,6 +2483,9 @@
2447
2483
  "node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js | totalReflowTime": {
2448
2484
  "message": "إجمالي مدة إعادة التدفق"
2449
2485
  },
2486
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js | unattributed": {
2487
+ "message": "مهام غير منسوبة لأي رموز برمجية"
2488
+ },
2450
2489
  "node_modules/@paulirish/trace_engine/models/trace/insights/ImageDelivery.js | description": {
2451
2490
  "message": "يمكن أن يؤدي تقليل وقت تنزيل الصور إلى تحسين مدّة التحميل المُدرَكة للصفحة، بالإضافة إلى تحسين سرعة عرض أكبر محتوى مرئي. [مزيد من المعلومات حول تحسين حجم الصورة](https://developer.chrome.com/docs/lighthouse/performance/uses-optimized-images/)"
2452
2491
  },
@@ -2558,6 +2597,33 @@
2558
2597
  "node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js | title": {
2559
2598
  "message": "سرعة عرض أكبر محتوى مرئي (LCP) حسب المرحلة"
2560
2599
  },
2600
+ "node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js | columnScript": {
2601
+ "message": "النص البرمجي"
2602
+ },
2603
+ "node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js | columnWastedBytes": {
2604
+ "message": "وحدات البايت المُهدرة"
2605
+ },
2606
+ "node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js | description": {
2607
+ "message": "تساعد الرموز البرمجية polyfill وtransform المتصفّحات القديمة في استخدام ميزات JavaScript الجديدة. ومع ذلك، يكون العديد منها غير ضروري للمتصفّحات الحديثة. من الأفضل تعديل عملية إنشاء رموز JavaScript لتجنُّب تحويل رموز ميزات [Baseline](https://web.dev/articles/baseline-and-polyfills)، إلّا في حال ضرورة دعم المتصفِّحات القديمة. [التعرُّف على سبب إمكانية نشر معظم المواقع الإلكترونية لرمز ES6+‎ بدون تحويله](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)"
2608
+ },
2609
+ "node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js | title": {
2610
+ "message": "ميزات JavaScript القديمة"
2611
+ },
2612
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js | description": {
2613
+ "message": "يوفِّر البروتوكولان HTTP/2 وHTTP/3 العديد من المزايا أكثر من بروتوكول HTTP/1.1، مثل الإرسال المتعدّد. [مزيد من المعلومات حول استخدام HTTP الحديث](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/)"
2614
+ },
2615
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js | noOldProtocolRequests": {
2616
+ "message": "لم يتم استخدام بروتوكول HTTP/1.1 في أي طلب"
2617
+ },
2618
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js | protocol": {
2619
+ "message": "البروتوكول"
2620
+ },
2621
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js | request": {
2622
+ "message": "طلب"
2623
+ },
2624
+ "node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js | title": {
2625
+ "message": "بروتوكول HTTP الحديث"
2626
+ },
2561
2627
  "node_modules/@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js | description": {
2562
2628
  "message": "يُمكن [تجنُّب تقييد الطلبات المهمة](https://developer.chrome.com/docs/lighthouse/performance/critical-request-chains) عن طريق تقليل طول السلاسل أو تقليل حجم تنزيل الموارد أو تأجيل تنزيل الموارد غير الضرورية لتحسين تحميل الصفحة."
2563
2629
  },