lighthouse 9.5.0-dev.20230122 → 9.5.0-dev.20230124

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 (131) hide show
  1. package/.codecov.yml +0 -5
  2. package/core/audits/audit.js +1 -1
  3. package/core/audits/bf-cache.js +1 -1
  4. package/core/audits/byte-efficiency/legacy-javascript.d.ts +1 -0
  5. package/core/audits/byte-efficiency/legacy-javascript.js +7 -3
  6. package/core/audits/dobetterweb/uses-http2.d.ts +5 -2
  7. package/core/audits/dobetterweb/uses-http2.js +12 -7
  8. package/core/audits/screenshot-thumbnails.d.ts +2 -1
  9. package/core/audits/screenshot-thumbnails.js +14 -9
  10. package/core/audits/third-party-facades.d.ts +3 -2
  11. package/core/audits/third-party-facades.js +12 -9
  12. package/core/audits/third-party-summary.d.ts +7 -6
  13. package/core/audits/third-party-summary.js +16 -14
  14. package/core/audits/valid-source-maps.d.ts +5 -3
  15. package/core/audits/valid-source-maps.js +11 -9
  16. package/core/computed/entity-classification.d.ts +29 -0
  17. package/core/computed/entity-classification.js +102 -0
  18. package/core/computed/processed-navigation.d.ts +12 -6
  19. package/core/computed/processed-navigation.js +19 -6
  20. package/core/computed/resource-summary.d.ts +4 -2
  21. package/core/computed/resource-summary.js +8 -5
  22. package/core/lib/url-utils.js +1 -1
  23. package/core/runner.d.ts +10 -0
  24. package/core/runner.js +48 -0
  25. package/core/util.cjs +43 -10
  26. package/core/util.d.cts +114 -2
  27. package/dist/report/bundle.esm.js +858 -883
  28. package/dist/report/flow.js +33 -23
  29. package/dist/report/standalone.js +27 -17
  30. package/flow-report/assets/standalone-flow-template.html +1 -1
  31. package/flow-report/src/common.tsx +1 -1
  32. package/flow-report/src/i18n/i18n.d.ts +103 -100
  33. package/flow-report/src/i18n/i18n.tsx +23 -18
  34. package/flow-report/src/sidebar/sidebar.tsx +3 -3
  35. package/flow-report/src/summary/category.tsx +7 -7
  36. package/flow-report/src/summary/summary.tsx +2 -2
  37. package/flow-report/src/topbar.tsx +4 -28
  38. package/package.json +5 -5
  39. package/readme.md +1 -1
  40. package/report/assets/standalone-template.html +1 -1
  41. package/report/assets/styles.css +3 -3
  42. package/report/assets/templates.html +4 -28
  43. package/report/renderer/category-renderer.js +19 -17
  44. package/report/renderer/components.js +119 -202
  45. package/report/renderer/crc-details-renderer.js +7 -6
  46. package/report/renderer/details-renderer.js +7 -6
  47. package/report/renderer/dom.js +1 -1
  48. package/report/renderer/element-screenshot-renderer.js +3 -3
  49. package/report/renderer/{i18n.d.ts → i18n-formatter.d.ts} +3 -9
  50. package/report/renderer/{i18n.js → i18n-formatter.js} +2 -11
  51. package/report/renderer/performance-category-renderer.js +17 -15
  52. package/report/renderer/pwa-category-renderer.js +5 -4
  53. package/report/renderer/report-globals.d.ts +21 -0
  54. package/report/renderer/report-globals.js +49 -0
  55. package/report/renderer/report-renderer.js +22 -24
  56. package/report/renderer/report-ui-features.js +9 -8
  57. package/report/renderer/report-utils.d.ts +116 -0
  58. package/report/renderer/{util.js → report-utils.js} +100 -415
  59. package/report/renderer/snippet-renderer.js +3 -2
  60. package/report/test/renderer/category-renderer-test.js +10 -5
  61. package/report/test/renderer/crc-details-renderer-test.js +8 -4
  62. package/report/test/renderer/details-renderer-test.js +8 -4
  63. package/report/test/renderer/dom-test.js +8 -4
  64. package/report/test/renderer/element-screenshot-renderer-test.js +9 -5
  65. package/report/test/renderer/{i18n-test.js → i18n-formatter-test.js} +15 -21
  66. package/report/test/renderer/performance-category-renderer-test.js +15 -10
  67. package/report/test/renderer/pwa-category-renderer-test.js +11 -6
  68. package/report/test/renderer/report-renderer-test.js +2 -2
  69. package/report/test/renderer/report-ui-features-test.js +3 -3
  70. package/report/test/renderer/{util-test.js → report-utils-test.js} +37 -235
  71. package/report/test/renderer/snippet-renderer-test.js +8 -4
  72. package/report/test-assets/lhr-3.0.0.json +2332 -0
  73. package/report/test-assets/lhr-4.3.0.json +4754 -0
  74. package/report/test-assets/lhr-5.0.0.json +5994 -0
  75. package/report/test-assets/lhr-6.0.0.json +7222 -0
  76. package/report/test-assets/lhr-8.5.0.json +8679 -0
  77. package/shared/localization/format.js +5 -2
  78. package/shared/localization/locales/ar-XB.json +50 -50
  79. package/shared/localization/locales/ar.json +50 -50
  80. package/shared/localization/locales/bg.json +50 -50
  81. package/shared/localization/locales/ca.json +50 -50
  82. package/shared/localization/locales/cs.json +50 -50
  83. package/shared/localization/locales/da.json +50 -50
  84. package/shared/localization/locales/de.json +50 -50
  85. package/shared/localization/locales/el.json +50 -50
  86. package/shared/localization/locales/en-GB.json +50 -50
  87. package/shared/localization/locales/en-US.json +55 -55
  88. package/shared/localization/locales/en-XA.json +50 -50
  89. package/shared/localization/locales/en-XL.json +55 -55
  90. package/shared/localization/locales/es-419.json +50 -50
  91. package/shared/localization/locales/es.json +50 -50
  92. package/shared/localization/locales/fi.json +50 -50
  93. package/shared/localization/locales/fil.json +50 -50
  94. package/shared/localization/locales/fr.json +50 -50
  95. package/shared/localization/locales/he.json +50 -50
  96. package/shared/localization/locales/hi.json +50 -50
  97. package/shared/localization/locales/hr.json +50 -50
  98. package/shared/localization/locales/hu.json +50 -50
  99. package/shared/localization/locales/id.json +50 -50
  100. package/shared/localization/locales/it.json +50 -50
  101. package/shared/localization/locales/ja.json +50 -50
  102. package/shared/localization/locales/ko.json +50 -50
  103. package/shared/localization/locales/lt.json +50 -50
  104. package/shared/localization/locales/lv.json +50 -50
  105. package/shared/localization/locales/nl.json +50 -50
  106. package/shared/localization/locales/no.json +50 -50
  107. package/shared/localization/locales/pl.json +50 -50
  108. package/shared/localization/locales/pt-PT.json +50 -50
  109. package/shared/localization/locales/pt.json +50 -50
  110. package/shared/localization/locales/ro.json +50 -50
  111. package/shared/localization/locales/ru.json +50 -50
  112. package/shared/localization/locales/sk.json +50 -50
  113. package/shared/localization/locales/sl.json +50 -50
  114. package/shared/localization/locales/sr-Latn.json +50 -50
  115. package/shared/localization/locales/sr.json +50 -50
  116. package/shared/localization/locales/sv.json +50 -50
  117. package/shared/localization/locales/ta.json +50 -50
  118. package/shared/localization/locales/te.json +50 -50
  119. package/shared/localization/locales/th.json +50 -50
  120. package/shared/localization/locales/tr.json +50 -50
  121. package/shared/localization/locales/uk.json +50 -50
  122. package/shared/localization/locales/vi.json +50 -50
  123. package/shared/localization/locales/zh-HK.json +50 -50
  124. package/shared/localization/locales/zh-TW.json +50 -50
  125. package/shared/localization/locales/zh.json +50 -50
  126. package/shared/test/util-test.js +214 -0
  127. package/shared/util.d.ts +122 -0
  128. package/shared/util.js +332 -0
  129. package/types/artifacts.d.ts +14 -0
  130. package/types/lhr/lhr.d.ts +33 -0
  131. package/report/renderer/util.d.ts +0 -230
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @license Copyright 2022 The Lighthouse Authors. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
+ */
6
+
7
+ import {makeComputedArtifact} from './computed-artifact.js';
8
+ import {NetworkRecords} from './network-records.js';
9
+ import {Util} from '../util.cjs';
10
+ import UrlUtils from '../lib/url-utils.js';
11
+ import thirdPartyWeb from '../lib/third-party-web.js';
12
+
13
+ /** @typedef {Map<string, LH.Artifacts.Entity>} EntityCache */
14
+
15
+ class EntityClassification {
16
+ /**
17
+ * @param {EntityCache} entityCache
18
+ * @param {string} url
19
+ * @return {LH.Artifacts.Entity | undefined}
20
+ */
21
+ static makeUpAnEntity(entityCache, url) {
22
+ if (!UrlUtils.isValid(url)) return;
23
+ // We can make up an entity only for those URLs with a valid domain attached.
24
+ // So we further restrict from allowed URLs to (http/https).
25
+ if (!Util.createOrReturnURL(url).protocol.startsWith('http')) return;
26
+
27
+ const rootDomain = Util.getRootDomain(url);
28
+ if (!rootDomain) return;
29
+ if (entityCache.has(rootDomain)) return entityCache.get(rootDomain);
30
+
31
+ const unrecognizedEntity = {
32
+ name: rootDomain,
33
+ company: rootDomain,
34
+ category: '',
35
+ categories: [],
36
+ domains: [rootDomain],
37
+ averageExecutionTime: 0,
38
+ totalExecutionTime: 0,
39
+ totalOccurrences: 0,
40
+ isUnrecognized: true,
41
+ };
42
+ entityCache.set(rootDomain, unrecognizedEntity);
43
+ return unrecognizedEntity;
44
+ }
45
+
46
+ /**
47
+ * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
48
+ * @param {LH.Artifacts.ComputedContext} context
49
+ * @return {Promise<LH.Artifacts.EntityClassification>}
50
+ */
51
+ static async compute_(data, context) {
52
+ const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
53
+ /** @type {EntityCache} */
54
+ const madeUpEntityCache = new Map();
55
+ /** @type {Map<string, LH.Artifacts.Entity>} */
56
+ const entityByUrl = new Map();
57
+ /** @type {Map<LH.Artifacts.Entity, Set<string>>} */
58
+ const urlsByEntity = new Map();
59
+
60
+ for (const record of networkRecords) {
61
+ const {url} = record;
62
+ if (entityByUrl.has(url)) continue;
63
+
64
+ const entity = thirdPartyWeb.getEntity(url) ||
65
+ EntityClassification.makeUpAnEntity(madeUpEntityCache, url);
66
+ if (!entity) continue;
67
+
68
+ const entityURLs = urlsByEntity.get(entity) || new Set();
69
+ entityURLs.add(url);
70
+ urlsByEntity.set(entity, entityURLs);
71
+ entityByUrl.set(url, entity);
72
+ }
73
+
74
+ // When available, first party identification will be done via
75
+ // `mainDocumentUrl` (for navigations), and falls back to `finalDisplayedUrl` (for timespan/snapshot).
76
+ // See https://github.com/GoogleChrome/lighthouse/issues/13706
77
+ const firstPartyUrl = data.URL.mainDocumentUrl || data.URL.finalDisplayedUrl;
78
+ const firstParty = thirdPartyWeb.getEntity(firstPartyUrl) ||
79
+ EntityClassification.makeUpAnEntity(madeUpEntityCache, firstPartyUrl);
80
+
81
+ /**
82
+ * Convenience function to check if a URL belongs to first party.
83
+ * @param {string} url
84
+ * @return {boolean}
85
+ */
86
+ function isFirstParty(url) {
87
+ const entityUrl = entityByUrl.get(url);
88
+ if (!entityUrl) throw new Error('A url not in devtoolsLog was used for first-party check.');
89
+ return entityUrl === firstParty;
90
+ }
91
+
92
+ return {
93
+ entityByUrl,
94
+ urlsByEntity,
95
+ firstParty,
96
+ isFirstParty,
97
+ };
98
+ }
99
+ }
100
+
101
+ const EntityClassificationComputed = makeComputedArtifact(EntityClassification, null);
102
+ export {EntityClassificationComputed as EntityClassification};
@@ -1,15 +1,21 @@
1
1
  export { ProcessedNavigationComputed as ProcessedNavigation };
2
2
  declare const ProcessedNavigationComputed: typeof ProcessedNavigation & {
3
- request: (dependencies: import("../index.js").Trace, context: import("../../types/utility-types.js").default.ImmutableObject<{
3
+ request: (dependencies: import("../index.js").Trace | import("../index.js").Artifacts.ProcessedTrace, context: import("../../types/utility-types.js").default.ImmutableObject<{
4
4
  computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
5
5
  }>) => Promise<import("../index.js").Artifacts.ProcessedNavigation>;
6
6
  };
7
7
  declare class ProcessedNavigation {
8
8
  /**
9
- * @param {LH.Trace} trace
10
- * @param {LH.Artifacts.ComputedContext} context
11
- * @return {Promise<LH.Artifacts.ProcessedNavigation>}
12
- */
13
- static compute_(trace: LH.Trace, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.ProcessedNavigation>;
9
+ * @param {LH.Trace | LH.Artifacts.ProcessedTrace} traceOrProcessedTrace
10
+ * @return {traceOrProcessedTrace is LH.Artifacts.ProcessedTrace}
11
+ */
12
+ static isProcessedTrace(traceOrProcessedTrace: LH.Trace | LH.Artifacts.ProcessedTrace): traceOrProcessedTrace is import("../index.js").Artifacts.ProcessedTrace;
13
+ /**
14
+ * @param {LH.Trace | LH.Artifacts.ProcessedTrace} traceOrProcessedTrace
15
+ * @param {LH.Artifacts.ComputedContext} context
16
+ * @return {Promise<LH.Artifacts.ProcessedNavigation>}
17
+ */
18
+ static compute_(traceOrProcessedTrace: LH.Trace | LH.Artifacts.ProcessedTrace, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.ProcessedNavigation>;
14
19
  }
20
+ import { ProcessedTrace } from "./processed-trace.js";
15
21
  //# sourceMappingURL=processed-navigation.d.ts.map
@@ -10,12 +10,25 @@ import LHTraceProcessor from '../lib/lh-trace-processor.js';
10
10
 
11
11
  class ProcessedNavigation {
12
12
  /**
13
- * @param {LH.Trace} trace
14
- * @param {LH.Artifacts.ComputedContext} context
15
- * @return {Promise<LH.Artifacts.ProcessedNavigation>}
16
- */
17
- static async compute_(trace, context) {
18
- const processedTrace = await ProcessedTrace.request(trace, context);
13
+ * @param {LH.Trace | LH.Artifacts.ProcessedTrace} traceOrProcessedTrace
14
+ * @return {traceOrProcessedTrace is LH.Artifacts.ProcessedTrace}
15
+ */
16
+ static isProcessedTrace(traceOrProcessedTrace) {
17
+ return 'timeOriginEvt' in traceOrProcessedTrace;
18
+ }
19
+
20
+ /**
21
+ * @param {LH.Trace | LH.Artifacts.ProcessedTrace} traceOrProcessedTrace
22
+ * @param {LH.Artifacts.ComputedContext} context
23
+ * @return {Promise<LH.Artifacts.ProcessedNavigation>}
24
+ */
25
+ static async compute_(traceOrProcessedTrace, context) {
26
+ // TODO: Remove this backport once pubads passes in a raw trace.
27
+ if (this.isProcessedTrace(traceOrProcessedTrace)) {
28
+ return LHTraceProcessor.processNavigation(traceOrProcessedTrace);
29
+ }
30
+
31
+ const processedTrace = await ProcessedTrace.request(traceOrProcessedTrace, context);
19
32
  return LHTraceProcessor.processNavigation(processedTrace);
20
33
  }
21
34
  }
@@ -24,9 +24,10 @@ declare class ResourceSummary {
24
24
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
25
25
  * @param {LH.Artifacts.URL} URLArtifact
26
26
  * @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
27
+ * @param {LH.Artifacts.EntityClassification} classifiedEntities
27
28
  * @return {Record<LH.Budget.ResourceType, ResourceEntry>}
28
29
  */
29
- static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, budgets: LH.Util.ImmutableObject<LH.Budget[] | null>): Record<LH.Budget.ResourceType, ResourceEntry>;
30
+ static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, budgets: LH.Util.ImmutableObject<LH.Budget[] | null>, classifiedEntities: LH.Artifacts.EntityClassification): Record<LH.Budget.ResourceType, ResourceEntry>;
30
31
  /**
31
32
  * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, budgets: LH.Util.ImmutableObject<LH.Budget[]|null>}} data
32
33
  * @param {LH.Artifacts.ComputedContext} context
@@ -38,7 +39,8 @@ declare class ResourceSummary {
38
39
  budgets: LH.Util.ImmutableObject<LH.Budget[] | null>;
39
40
  }, context: LH.Artifacts.ComputedContext): Promise<Record<LH.Budget.ResourceType, ResourceEntry>>;
40
41
  }
41
- import { Util } from "../util.cjs";
42
+ import { Util } from "../../shared/util.js";
42
43
  import { Budget } from "../config/budget.js";
43
44
  import { NetworkRequest } from "../lib/network-request.js";
45
+ import { EntityClassification } from "./entity-classification.js";
44
46
  //# sourceMappingURL=resource-summary.d.ts.map
@@ -4,11 +4,12 @@
4
4
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
5
  */
6
6
 
7
+ import {EntityClassification} from './entity-classification.js';
7
8
  import {makeComputedArtifact} from './computed-artifact.js';
8
9
  import {NetworkRecords} from './network-records.js';
9
10
  import {NetworkRequest} from '../lib/network-request.js';
10
11
  import {Budget} from '../config/budget.js';
11
- import {Util} from '../util.cjs';
12
+ import {Util} from '../../shared/util.js';
12
13
 
13
14
  /** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
14
15
 
@@ -35,9 +36,10 @@ class ResourceSummary {
35
36
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
36
37
  * @param {LH.Artifacts.URL} URLArtifact
37
38
  * @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
39
+ * @param {LH.Artifacts.EntityClassification} classifiedEntities
38
40
  * @return {Record<LH.Budget.ResourceType, ResourceEntry>}
39
41
  */
40
- static summarize(networkRecords, URLArtifact, budgets) {
42
+ static summarize(networkRecords, URLArtifact, budgets, classifiedEntities) {
41
43
  /** @type {Record<LH.Budget.ResourceType, ResourceEntry>} */
42
44
  const resourceSummary = {
43
45
  'stylesheet': {count: 0, resourceSize: 0, transferSize: 0},
@@ -56,8 +58,8 @@ class ResourceSummary {
56
58
  if (budget?.options?.firstPartyHostnames) {
57
59
  firstPartyHosts = budget.options.firstPartyHostnames;
58
60
  } else {
59
- const rootDomain = Util.getRootDomain(URLArtifact.finalDisplayedUrl);
60
- firstPartyHosts = [`*.${rootDomain}`];
61
+ firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
62
+ [`*.${Util.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
61
63
  }
62
64
 
63
65
  networkRecords.filter(record => {
@@ -105,7 +107,8 @@ class ResourceSummary {
105
107
  */
106
108
  static async compute_(data, context) {
107
109
  const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
108
- return ResourceSummary.summarize(networkRecords, data.URL, data.budgets);
110
+ const classifiedEntities = await EntityClassification.request(data, context);
111
+ return ResourceSummary.summarize(networkRecords, data.URL, data.budgets, classifiedEntities);
109
112
  }
110
113
  }
111
114
 
@@ -4,7 +4,7 @@
4
4
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
5
  */
6
6
 
7
- import {Util} from '../util.cjs';
7
+ import {Util} from '../../shared/util.js';
8
8
  import {LighthouseError} from './lh-error.js';
9
9
 
10
10
  /** @typedef {import('./network-request.js').NetworkRequest} NetworkRequest */
package/core/runner.d.ts CHANGED
@@ -16,6 +16,16 @@ export class Runner {
16
16
  driverMock?: Driver | undefined;
17
17
  computedCache: Map<string, ArbitraryEqualityMap>;
18
18
  }): Promise<LH.RunnerResult | undefined>;
19
+ /**
20
+ * @param {LH.Artifacts} artifacts
21
+ * @param {LH.Artifacts.ComputedContext} context
22
+ */
23
+ static getEntityClassification(artifacts: LH.Artifacts, context: LH.Artifacts.ComputedContext): Promise<{
24
+ list: import("../types/lhr/lhr.js").default.LhrEntity[];
25
+ firstParty: string | undefined;
26
+ entityIndexByOrigin: Record<string, number>;
27
+ entityIndexByName: Record<string, number>;
28
+ } | undefined>;
19
29
  /**
20
30
  * User can run -G solo, -A solo, or -GA together
21
31
  * -G and -A will run partial lighthouse pipelines,
package/core/runner.js CHANGED
@@ -23,6 +23,8 @@ import {ReportGenerator} from '../report/generator/report-generator.js';
23
23
  import {LighthouseError} from './lib/lh-error.js';
24
24
  import {lighthouseVersion} from '../root.js';
25
25
  import {getModuleDirectory} from '../esm-utils.js';
26
+ import {EntityClassification} from './computed/entity-classification.js';
27
+ import UrlUtils from './lib/url-utils.js';
26
28
 
27
29
  const moduleDir = getModuleDirectory(import.meta);
28
30
 
@@ -110,6 +112,7 @@ class Runner {
110
112
  categories,
111
113
  categoryGroups: resolvedConfig.groups || undefined,
112
114
  stackPacks: stackPacks.getStackPacks(artifacts.Stacks),
115
+ entities: await Runner.getEntityClassification(artifacts, {computedCache}),
113
116
  fullPageScreenshot: resolvedConfig.settings.disableFullPageScreenshot ?
114
117
  undefined : artifacts.FullPageScreenshot,
115
118
  timing: this._getTiming(artifacts),
@@ -139,6 +142,51 @@ class Runner {
139
142
  }
140
143
  }
141
144
 
145
+ /**
146
+ * @param {LH.Artifacts} artifacts
147
+ * @param {LH.Artifacts.ComputedContext} context
148
+ */
149
+ static async getEntityClassification(artifacts, context) {
150
+ const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
151
+ if (!devtoolsLog) return;
152
+ const classifiedEntities = await EntityClassification.request(
153
+ {URL: artifacts.URL, devtoolsLog}, context);
154
+
155
+ /** @type {Array<LH.Result.LhrEntity>} */
156
+ const entities = [];
157
+ /** @type {Record<string, number>} */
158
+ const entityIndexByOrigin = {};
159
+ /** @type {Record<string, number>} */
160
+ const entityIndexByName = {};
161
+
162
+ for (const [entity, entityUrls] of classifiedEntities.urlsByEntity) {
163
+ /** @type {LH.Result.LhrEntity} */
164
+ const shortEntity = {
165
+ name: entity.name,
166
+ homepage: entity.homepage,
167
+ };
168
+
169
+ // Reduce payload size in LHR JSON by omitting whats falsy.
170
+ if (entity === classifiedEntities.firstParty) shortEntity.isFirstParty = true;
171
+ if (entity.isUnrecognized) shortEntity.isUnrecognized = true;
172
+
173
+ const id = entities.push(shortEntity) - 1;
174
+ for (const url of entityUrls) {
175
+ const origin = UrlUtils.getOrigin(url);
176
+ if (!origin) continue;
177
+ entityIndexByOrigin[origin] = id;
178
+ }
179
+ entityIndexByName[shortEntity.name] = id;
180
+ }
181
+
182
+ return {
183
+ list: entities,
184
+ firstParty: classifiedEntities.firstParty?.name,
185
+ entityIndexByOrigin,
186
+ entityIndexByName,
187
+ };
188
+ }
189
+
142
190
  /**
143
191
  * User can run -G solo, -A solo, or -GA together
144
192
  * -G and -A will run partial lighthouse pipelines,
package/core/util.cjs CHANGED
@@ -19,7 +19,7 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- /** @template T @typedef {import('./i18n').I18n<T>} I18n */
22
+ /** @typedef {import('./i18n-formatter').I18nFormatter} I18nFormatter */
23
23
 
24
24
  const ELLIPSIS = '\u2026';
25
25
  const NBSP = '\xa0';
@@ -42,9 +42,21 @@ const listOfTlds = [
42
42
  ];
43
43
 
44
44
  class Util {
45
- /** @type {I18n<typeof UIStrings>} */
45
+ /** @type {I18nFormatter} */
46
46
  // @ts-expect-error: Is set in report renderer.
47
47
  static i18n = null;
48
+ static strings = /** @type {typeof UIStrings} */ ({});
49
+
50
+ /**
51
+ * @param {Record<string, string>} providedStrings
52
+ */
53
+ static applyStrings(providedStrings) {
54
+ this.strings = {
55
+ // Set missing renderer strings to default (english) values.
56
+ ...UIStrings,
57
+ ...providedStrings,
58
+ };
59
+ }
48
60
 
49
61
  static get PASS_THRESHOLD() {
50
62
  return PASS_THRESHOLD;
@@ -154,6 +166,10 @@ class Util {
154
166
  }
155
167
  }
156
168
  }
169
+
170
+ // TODO: convert printf-style displayValue.
171
+ // Added: #5099, v3
172
+ // Removed: #6767, v4
157
173
  }
158
174
  }
159
175
 
@@ -216,6 +232,20 @@ class Util {
216
232
  });
217
233
  }
218
234
 
235
+ // Add some minimal stuff so older reports still work.
236
+ if (!clone.environment) {
237
+ // @ts-expect-error
238
+ clone.environment = {benchmarkIndex: 0};
239
+ }
240
+ if (!clone.configSettings.screenEmulation) {
241
+ // @ts-expect-error
242
+ clone.configSettings.screenEmulation = {};
243
+ }
244
+ if (!clone.i18n) {
245
+ // @ts-expect-error
246
+ clone.i18n = {};
247
+ }
248
+
219
249
  // In 10.0, full-page-screenshot became a top-level property on the LHR.
220
250
  if (clone.audits['full-page-screenshot']) {
221
251
  const details = /** @type {LH.Result.FullPageScreenshot=} */ (
@@ -511,7 +541,7 @@ class Util {
511
541
 
512
542
  switch (settings.throttlingMethod) {
513
543
  case 'provided':
514
- summary = networkThrottling = cpuThrottling = Util.i18n.strings.throttlingProvided;
544
+ summary = networkThrottling = cpuThrottling = Util.strings.throttlingProvided;
515
545
  break;
516
546
  case 'devtools': {
517
547
  const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
@@ -526,7 +556,8 @@ class Util {
526
556
  throttling.downloadThroughputKbps === 1.6 * 1024 * 0.9 &&
527
557
  throttling.uploadThroughputKbps === 750 * 0.9;
528
558
  };
529
- summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
559
+ summary = isSlow4G() ?
560
+ Util.strings.runtimeSlow4g : Util.strings.runtimeCustom;
530
561
  break;
531
562
  }
532
563
  case 'simulate': {
@@ -539,11 +570,12 @@ class Util {
539
570
  const isSlow4G = () => {
540
571
  return rttMs === 150 && throughputKbps === 1.6 * 1024;
541
572
  };
542
- summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
573
+ summary = isSlow4G() ?
574
+ Util.strings.runtimeSlow4g : Util.strings.runtimeCustom;
543
575
  break;
544
576
  }
545
577
  default:
546
- summary = cpuThrottling = networkThrottling = Util.i18n.strings.runtimeUnknown;
578
+ summary = cpuThrottling = networkThrottling = Util.strings.runtimeUnknown;
547
579
  }
548
580
 
549
581
  // devtools-entry.js always sets `screenEmulation.disabled` when using mobile emulation,
@@ -556,11 +588,11 @@ class Util {
556
588
  settings.formFactor === 'mobile' :
557
589
  settings.screenEmulation.mobile;
558
590
 
559
- let deviceEmulation = Util.i18n.strings.runtimeMobileEmulation;
591
+ let deviceEmulation = Util.strings.runtimeMobileEmulation;
560
592
  if (isScreenEmulationDisabled) {
561
- deviceEmulation = Util.i18n.strings.runtimeNoEmulation;
593
+ deviceEmulation = Util.strings.runtimeNoEmulation;
562
594
  } else if (!isScreenEmulationMobile) {
563
- deviceEmulation = Util.i18n.strings.runtimeDesktopEmulation;
595
+ deviceEmulation = Util.strings.runtimeDesktopEmulation;
564
596
  }
565
597
 
566
598
  const screenEmulation = isScreenEmulationDisabled ?
@@ -765,7 +797,7 @@ const UIStrings = {
765
797
  /** Label for a row in a table that shows the User Agent that was used to send out all network requests during the Lighthouse run. */
766
798
  runtimeSettingsUANetwork: 'User agent (network)',
767
799
  /** Label for a row in a table that shows the estimated CPU power of the machine running Lighthouse. Example row values: 532, 1492, 783. */
768
- runtimeSettingsBenchmark: 'CPU/Memory Power',
800
+ runtimeSettingsBenchmark: 'Unthrottled CPU/Memory Power',
769
801
  /** Label for a row in a table that shows the version of the Axe library used. Example row values: 2.1.0, 3.2.3 */
770
802
  runtimeSettingsAxeVersion: 'Axe version',
771
803
  /** Label for a row in a table that shows the screen resolution and DPR that was emulated for the Lighthouse run. Example values: '800x600, DPR: 3' */
@@ -805,6 +837,7 @@ const UIStrings = {
805
837
  runtimeCustom: 'Custom throttling',
806
838
  };
807
839
  Util.UIStrings = UIStrings;
840
+ Util.strings = {...UIStrings};
808
841
 
809
842
  module.exports = {
810
843
  Util,
package/core/util.d.cts CHANGED
@@ -1,7 +1,119 @@
1
- export type I18n<T> = any;
1
+ export type I18nFormatter = any;
2
2
  export class Util {
3
- /** @type {I18n<typeof UIStrings>} */
3
+ /** @type {I18nFormatter} */
4
4
  static i18n: any;
5
+ static strings: {
6
+ /** Disclaimer shown to users below the metric values (First Contentful Paint, Time to Interactive, etc) to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. */
7
+ varianceDisclaimer: string;
8
+ /** Text link pointing to an interactive calculator that explains Lighthouse scoring. The link text should be fairly short. */
9
+ calculatorLink: string;
10
+ /** Label preceding a radio control for filtering the list of audits. The radio choices are various performance metrics (FCP, LCP, TBT), and if chosen, the audits in the report are hidden if they are not relevant to the selected metric. */
11
+ showRelevantAudits: string;
12
+ /** Column heading label for the listing of opportunity audits. Each audit title represents an opportunity. There are only 2 columns, so no strict character limit. */
13
+ opportunityResourceColumnLabel: string;
14
+ /** Column heading label for the estimated page load savings of opportunity audits. Estimated Savings is the total amount of time (in seconds) that Lighthouse computed could be reduced from the total page load time, if the suggested action is taken. There are only 2 columns, so no strict character limit. */
15
+ opportunitySavingsColumnLabel: string;
16
+ /** An error string displayed next to a particular audit when it has errored, but not provided any specific error message. */
17
+ errorMissingAuditInfo: string;
18
+ /** A label, shown next to an audit title or metric title, indicating that there was an error computing it. The user can hover on the label to reveal a tooltip with the extended error message. Translation should be short (< 20 characters). */
19
+ errorLabel: string;
20
+ /** This label is shown above a bulleted list of warnings. It is shown directly below an audit that produced warnings. Warnings describe situations the user should be aware of, as Lighthouse was unable to complete all the work required on this audit. For example, The 'Unable to decode image (biglogo.jpg)' warning may show up below an image encoding audit. */
21
+ warningHeader: string;
22
+ /** Section heading shown above a list of passed audits that contain warnings. Audits under this section do not negatively impact the score, but Lighthouse has generated some potentially actionable suggestions that should be reviewed. This section is expanded by default and displays after the failing audits. */
23
+ warningAuditsGroupTitle: string;
24
+ /** Section heading shown above a list of audits that are passing. 'Passed' here refers to a passing grade. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list. */
25
+ passedAuditsGroupTitle: string;
26
+ /** Section heading shown above a list of audits that do not apply to the page. For example, if an audit is 'Are images optimized?', but the page has no images on it, the audit will be marked as not applicable. This is neither passing or failing. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list. */
27
+ notApplicableAuditsGroupTitle: string;
28
+ /** Section heading shown above a list of audits that were not computed by Lighthouse. They serve as a list of suggestions for the user to go and manually check. For example, Lighthouse can't automate testing cross-browser compatibility, so that is listed within this section, so the user is reminded to test it themselves. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list. */
29
+ manualAuditsGroupTitle: string;
30
+ /** Label shown preceding any important warnings that may have invalidated the entire report. For example, if the user has Chrome extensions installed, they may add enough performance overhead that Lighthouse's performance metrics are unreliable. If shown, this will be displayed at the top of the report UI. */
31
+ toplevelWarningsMessage: string;
32
+ /** String of text shown in a graphical representation of the flow of network requests for the web page. This label represents the initial network request that fetches an HTML page. This navigation may be redirected (eg. Initial navigation to http://example.com redirects to https://www.example.com). */
33
+ crcInitialNavigation: string;
34
+ /** Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms */
35
+ crcLongestDurationLabel: string;
36
+ /** Label for button that shows all lines of the snippet when clicked */
37
+ snippetExpandButtonLabel: string;
38
+ /** Label for button that only shows a few lines of the snippet when clicked */
39
+ snippetCollapseButtonLabel: string;
40
+ /** Explanation shown to users below performance results to inform them that the test was done with a 4G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation. */
41
+ lsPerformanceCategoryDescription: string;
42
+ /** Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. "Lab" is an abbreviated form of "laboratory", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site. */
43
+ labDataTitle: string;
44
+ /** This label is for a checkbox above a table of items loaded by a web page. The checkbox is used to show or hide third-party (or "3rd-party") resources in the table, where "third-party resources" refers to items loaded by a web page from URLs that aren't controlled by the owner of the web page. */
45
+ thirdPartyResourcesLabel: string;
46
+ /** This label is for a button that opens a new tab to a webapp called "Treemap", which is a nested visual representation of a heierarchy of data related to the reports (script bytes and coverage, resource breakdown, etc.) */
47
+ viewTreemapLabel: string;
48
+ /** This label is for a button that will show the user a trace of the page. */
49
+ viewTraceLabel: string;
50
+ /** This label is for a button that will show the user a trace of the page. */
51
+ viewOriginalTraceLabel: string;
52
+ /** Option in a dropdown menu that opens a small, summary report in a print dialog. */
53
+ dropdownPrintSummary: string;
54
+ /** Option in a dropdown menu that opens a full Lighthouse report in a print dialog. */
55
+ dropdownPrintExpanded: string;
56
+ /** Option in a dropdown menu that copies the Lighthouse JSON object to the system clipboard. */
57
+ dropdownCopyJSON: string;
58
+ /** Option in a dropdown menu that saves the Lighthouse report HTML locally to the system as a '.html' file. */
59
+ dropdownSaveHTML: string;
60
+ /** Option in a dropdown menu that saves the Lighthouse JSON object to the local system as a '.json' file. */
61
+ dropdownSaveJSON: string;
62
+ /** Option in a dropdown menu that opens the current report in the Lighthouse Viewer Application. */
63
+ dropdownViewer: string;
64
+ /** Option in a dropdown menu that saves the current report as a new GitHub Gist. */
65
+ dropdownSaveGist: string;
66
+ /** Option in a dropdown menu that toggles the themeing of the report between Light(default) and Dark themes. */
67
+ dropdownDarkTheme: string;
68
+ /** Label for a row in a table that describes the kind of device that was emulated for the Lighthouse run. Example values for row elements: 'No Emulation', 'Emulated Desktop', etc. */
69
+ runtimeSettingsDevice: string;
70
+ /** Label for a row in a table that describes the network throttling conditions that were used during a Lighthouse run, if any. */
71
+ runtimeSettingsNetworkThrottling: string;
72
+ /** Label for a row in a table that describes the CPU throttling conditions that were used during a Lighthouse run, if any.*/
73
+ runtimeSettingsCPUThrottling: string;
74
+ /** Label for a row in a table that shows the User Agent that was used to send out all network requests during the Lighthouse run. */
75
+ runtimeSettingsUANetwork: string;
76
+ /** Label for a row in a table that shows the estimated CPU power of the machine running Lighthouse. Example row values: 532, 1492, 783. */
77
+ runtimeSettingsBenchmark: string;
78
+ /** Label for a row in a table that shows the version of the Axe library used. Example row values: 2.1.0, 3.2.3 */
79
+ runtimeSettingsAxeVersion: string;
80
+ /** Label for a row in a table that shows the screen resolution and DPR that was emulated for the Lighthouse run. Example values: '800x600, DPR: 3' */
81
+ runtimeSettingsScreenEmulation: string;
82
+ /** Label for button to create an issue against the Lighthouse GitHub project. */
83
+ footerIssue: string;
84
+ /** Descriptive explanation for emulation setting when no device emulation is set. */
85
+ runtimeNoEmulation: string;
86
+ /** Descriptive explanation for emulation setting when emulating a Moto G4 mobile device. */
87
+ runtimeMobileEmulation: string;
88
+ /** Descriptive explanation for emulation setting when emulating a generic desktop form factor, as opposed to a mobile-device like form factor. */
89
+ runtimeDesktopEmulation: string;
90
+ /** Descriptive explanation for a runtime setting that is set to an unknown value. */
91
+ runtimeUnknown: string;
92
+ /** Descriptive label that this analysis run was from a single pageload of a browser (not a summary of hundreds of loads) */
93
+ runtimeSingleLoad: string;
94
+ /** Descriptive label that this analysis only considers the initial load of the page, and no interaction beyond when the page had "fully loaded" */
95
+ runtimeAnalysisWindow: string;
96
+ /** Descriptive explanation that this analysis run was from a single pageload of a browser, whereas field data often summarizes hundreds+ of page loads */
97
+ runtimeSingleLoadTooltip: string;
98
+ /** Descriptive explanation for environment throttling that was provided by the runtime environment instead of provided by Lighthouse throttling. */
99
+ throttlingProvided: string;
100
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
101
+ show: string;
102
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
103
+ hide: string;
104
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
105
+ expandView: string;
106
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
107
+ collapseView: string;
108
+ /** Label indicating that Lighthouse throttled the page to emulate a slow 4G network connection. */
109
+ runtimeSlow4g: string;
110
+ /** Label indicating that Lighthouse throttled the page using custom throttling settings. */
111
+ runtimeCustom: string;
112
+ };
113
+ /**
114
+ * @param {Record<string, string>} providedStrings
115
+ */
116
+ static applyStrings(providedStrings: Record<string, string>): void;
5
117
  static get PASS_THRESHOLD(): number;
6
118
  static get MS_DISPLAY_VALUE(): string;
7
119
  /**