lighthouse 11.7.0-dev.20240416 → 11.7.0-dev.20240417

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 (94) hide show
  1. package/cli/bin.js +0 -7
  2. package/cli/cli-flags.d.ts +1 -5
  3. package/cli/cli-flags.js +1 -5
  4. package/cli/test/smokehouse/core-tests.js +0 -2
  5. package/core/audits/byte-efficiency/render-blocking-resources.js +3 -1
  6. package/core/audits/byte-efficiency/unminified-css.js +2 -2
  7. package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
  8. package/core/audits/font-display.js +2 -2
  9. package/core/audits/resource-summary.d.ts +2 -0
  10. package/core/audits/resource-summary.js +5 -4
  11. package/core/computed/resource-summary.d.ts +10 -12
  12. package/core/computed/resource-summary.js +12 -19
  13. package/core/computed/unused-css.d.ts +3 -1
  14. package/core/computed/unused-css.js +6 -5
  15. package/core/config/config-helpers.js +0 -4
  16. package/core/config/constants.js +0 -1
  17. package/core/config/default-config.js +1 -14
  18. package/core/gather/gatherers/css-usage.d.ts +0 -21
  19. package/core/gather/gatherers/css-usage.js +9 -119
  20. package/core/gather/gatherers/stylesheets.d.ts +26 -0
  21. package/core/gather/gatherers/stylesheets.js +138 -0
  22. package/core/lib/i18n/i18n.d.ts +0 -1
  23. package/core/lib/i18n/i18n.js +0 -2
  24. package/core/runner.js +0 -1
  25. package/dist/report/bundle.esm.js +2 -19
  26. package/dist/report/flow.js +5 -22
  27. package/dist/report/standalone.js +3 -20
  28. package/package.json +1 -1
  29. package/readme.md +2 -2
  30. package/report/assets/styles.css +0 -17
  31. package/report/renderer/components.js +1 -1
  32. package/report/renderer/dom.d.ts +1 -1
  33. package/report/renderer/dom.js +1 -1
  34. package/report/renderer/performance-category-renderer.js +0 -21
  35. package/shared/localization/locales/ar-XB.json +61 -91
  36. package/shared/localization/locales/ar.json +61 -91
  37. package/shared/localization/locales/bg.json +61 -91
  38. package/shared/localization/locales/ca.json +61 -91
  39. package/shared/localization/locales/cs.json +61 -91
  40. package/shared/localization/locales/da.json +61 -91
  41. package/shared/localization/locales/de.json +61 -91
  42. package/shared/localization/locales/el.json +61 -91
  43. package/shared/localization/locales/en-GB.json +61 -91
  44. package/shared/localization/locales/en-US.json +0 -30
  45. package/shared/localization/locales/en-XA.json +61 -91
  46. package/shared/localization/locales/en-XL.json +0 -30
  47. package/shared/localization/locales/es-419.json +61 -91
  48. package/shared/localization/locales/es.json +61 -91
  49. package/shared/localization/locales/fi.json +61 -91
  50. package/shared/localization/locales/fil.json +60 -90
  51. package/shared/localization/locales/fr.json +61 -91
  52. package/shared/localization/locales/he.json +61 -91
  53. package/shared/localization/locales/hi.json +61 -91
  54. package/shared/localization/locales/hr.json +62 -92
  55. package/shared/localization/locales/hu.json +61 -91
  56. package/shared/localization/locales/id.json +61 -91
  57. package/shared/localization/locales/it.json +61 -91
  58. package/shared/localization/locales/ja.json +61 -91
  59. package/shared/localization/locales/ko.json +61 -91
  60. package/shared/localization/locales/lt.json +61 -91
  61. package/shared/localization/locales/lv.json +61 -91
  62. package/shared/localization/locales/nl.json +61 -91
  63. package/shared/localization/locales/no.json +61 -91
  64. package/shared/localization/locales/pl.json +60 -90
  65. package/shared/localization/locales/pt-PT.json +61 -91
  66. package/shared/localization/locales/pt.json +63 -93
  67. package/shared/localization/locales/ro.json +61 -91
  68. package/shared/localization/locales/ru.json +61 -91
  69. package/shared/localization/locales/sk.json +61 -91
  70. package/shared/localization/locales/sl.json +61 -91
  71. package/shared/localization/locales/sr-Latn.json +61 -91
  72. package/shared/localization/locales/sr.json +61 -91
  73. package/shared/localization/locales/sv.json +61 -91
  74. package/shared/localization/locales/ta.json +60 -90
  75. package/shared/localization/locales/te.json +61 -91
  76. package/shared/localization/locales/th.json +61 -91
  77. package/shared/localization/locales/tr.json +61 -91
  78. package/shared/localization/locales/uk.json +61 -91
  79. package/shared/localization/locales/vi.json +60 -90
  80. package/shared/localization/locales/zh-HK.json +61 -91
  81. package/shared/localization/locales/zh-TW.json +60 -90
  82. package/shared/localization/locales/zh.json +61 -91
  83. package/tsconfig.json +0 -1
  84. package/types/artifacts.d.ts +3 -1
  85. package/types/externs.d.ts +0 -2
  86. package/types/lh.d.ts +0 -2
  87. package/types/lhr/settings.d.ts +0 -4
  88. package/core/audits/performance-budget.d.ts +0 -39
  89. package/core/audits/performance-budget.js +0 -154
  90. package/core/audits/timing-budget.d.ts +0 -43
  91. package/core/audits/timing-budget.js +0 -175
  92. package/core/config/budget.d.ts +0 -74
  93. package/core/config/budget.js +0 -340
  94. package/types/lhr/budget.d.ts +0 -60
package/cli/bin.js CHANGED
@@ -79,13 +79,6 @@ async function begin() {
79
79
  config = (await import(`../core/config/${cliFlags.preset}-config.js`)).default;
80
80
  }
81
81
 
82
- if (cliFlags.budgetPath) {
83
- cliFlags.budgetPath = path.resolve(process.cwd(), cliFlags.budgetPath);
84
- /** @type {Array<LH.Budget>} */
85
- const parsedBudget = JSON.parse(fs.readFileSync(cliFlags.budgetPath, 'utf8'));
86
- cliFlags.budgets = parsedBudget;
87
- }
88
-
89
82
  // set logging preferences
90
83
  cliFlags.logLevel = 'info';
91
84
  if (cliFlags.verbose) {
@@ -24,7 +24,7 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
24
24
  default: boolean;
25
25
  describe: string;
26
26
  };
27
- }>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "budget-path" | "disable-full-page-screenshot" | "ignore-status-code"> & yargs.InferredOptionTypes<{
27
+ }>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "disable-full-page-screenshot" | "ignore-status-code"> & yargs.InferredOptionTypes<{
28
28
  'save-assets': {
29
29
  type: "boolean";
30
30
  default: boolean;
@@ -125,10 +125,6 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
125
125
  coerce: typeof splitCommaSeparatedValues;
126
126
  describe: string;
127
127
  };
128
- 'budget-path': {
129
- type: "string";
130
- describe: string;
131
- };
132
128
  'disable-full-page-screenshot': {
133
129
  type: "boolean";
134
130
  describe: string;
package/cli/cli-flags.js CHANGED
@@ -196,10 +196,6 @@ function getYargsParser(manualArgv) {
196
196
  coerce: splitCommaSeparatedValues,
197
197
  describe: 'Run everything except these audits',
198
198
  },
199
- 'budget-path': {
200
- type: 'string',
201
- describe: 'The path to the budget.json file for LightWallet.',
202
- },
203
199
  'disable-full-page-screenshot': {
204
200
  type: 'boolean',
205
201
  describe: 'Disables collection of the full page screenshot, which can be quite large',
@@ -213,7 +209,7 @@ function getYargsParser(manualArgv) {
213
209
  'save-assets', 'list-all-audits', 'list-locales', 'list-trace-categories', 'additional-trace-categories',
214
210
  'config-path', 'preset', 'chrome-flags', 'port', 'hostname', 'form-factor', 'screenEmulation', 'emulatedUserAgent',
215
211
  'max-wait-for-load', 'enable-error-reporting', 'gather-mode', 'audit-mode',
216
- 'only-audits', 'only-categories', 'skip-audits', 'budget-path', 'disable-full-page-screenshot', 'ignore-status-code',
212
+ 'only-audits', 'only-categories', 'skip-audits', 'disable-full-page-screenshot', 'ignore-status-code',
217
213
  ], 'Configuration:')
218
214
 
219
215
  // Output
@@ -35,7 +35,6 @@ import metricsTrickyTti from './test-definitions/metrics-tricky-tti.js';
35
35
  import metricsTrickyTtiLateFcp from './test-definitions/metrics-tricky-tti-late-fcp.js';
36
36
  import oopifRequests from './test-definitions/oopif-requests.js';
37
37
  import oopifScripts from './test-definitions/oopif-scripts.js';
38
- import perfBudgets from './test-definitions/perf-budgets.js';
39
38
  import perfDebug from './test-definitions/perf-debug.js';
40
39
  import perfDiagnosticsAnimations from './test-definitions/perf-diagnostics-animations.js';
41
40
  import perfDiagnosticsThirdParty from './test-definitions/perf-diagnostics-third-party.js';
@@ -94,7 +93,6 @@ const smokeTests = [
94
93
  metricsTrickyTtiLateFcp,
95
94
  oopifRequests,
96
95
  oopifScripts,
97
- perfBudgets,
98
96
  perfDebug,
99
97
  perfDiagnosticsAnimations,
100
98
  perfDiagnosticsThirdParty,
@@ -117,7 +117,8 @@ class RenderBlockingResources extends Audit {
117
117
  guidanceLevel: 2,
118
118
  // TODO: look into adding an `optionalArtifacts` property that captures the non-required nature
119
119
  // of CSSUsage
120
- requiredArtifacts: ['URL', 'traces', 'devtoolsLogs', 'CSSUsage', 'GatherContext', 'Stacks'],
120
+ requiredArtifacts:
121
+ ['URL', 'traces', 'devtoolsLogs', 'Stylesheets', 'CSSUsage', 'GatherContext', 'Stacks'],
121
122
  };
122
123
  }
123
124
 
@@ -263,6 +264,7 @@ class RenderBlockingResources extends Audit {
263
264
  const wastedBytesByUrl = new Map();
264
265
  try {
265
266
  const unusedCssItems = await UnusedCSS.request({
267
+ Stylesheets: artifacts.Stylesheets,
266
268
  CSSUsage: artifacts.CSSUsage,
267
269
  devtoolsLog: artifacts.devtoolsLogs[Audit.DEFAULT_PASS],
268
270
  }, context);
@@ -37,7 +37,7 @@ class UnminifiedCSS extends ByteEfficiencyAudit {
37
37
  description: str_(UIStrings.description),
38
38
  scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
39
39
  guidanceLevel: 3,
40
- requiredArtifacts: ['CSSUsage', 'devtoolsLogs', 'traces', 'URL', 'GatherContext'],
40
+ requiredArtifacts: ['Stylesheets', 'devtoolsLogs', 'traces', 'URL', 'GatherContext'],
41
41
  };
42
42
  }
43
43
 
@@ -85,7 +85,7 @@ class UnminifiedCSS extends ByteEfficiencyAudit {
85
85
  */
86
86
  static audit_(artifacts, networkRecords) {
87
87
  const items = [];
88
- for (const stylesheet of artifacts.CSSUsage.stylesheets) {
88
+ for (const stylesheet of artifacts.Stylesheets) {
89
89
  const networkRecord = networkRecords
90
90
  .find(record => record.url === stylesheet.header.sourceURL);
91
91
  if (!stylesheet.content) continue;
@@ -34,7 +34,8 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
34
34
  description: str_(UIStrings.description),
35
35
  scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
36
36
  guidanceLevel: 1,
37
- requiredArtifacts: ['CSSUsage', 'URL', 'devtoolsLogs', 'traces', 'GatherContext'],
37
+ requiredArtifacts:
38
+ ['Stylesheets', 'CSSUsage', 'URL', 'devtoolsLogs', 'traces', 'GatherContext'],
38
39
  };
39
40
  }
40
41
 
@@ -46,6 +47,7 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
46
47
  */
47
48
  static async audit_(artifacts, _, context) {
48
49
  const unusedCssItems = await UnusedCSS.request({
50
+ Stylesheets: artifacts.Stylesheets,
49
51
  CSSUsage: artifacts.CSSUsage,
50
52
  devtoolsLog: artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS],
51
53
  }, context);
@@ -50,7 +50,7 @@ class FontDisplay extends Audit {
50
50
  description: str_(UIStrings.description),
51
51
  supportedModes: ['navigation'],
52
52
  guidanceLevel: 3,
53
- requiredArtifacts: ['devtoolsLogs', 'CSSUsage', 'URL'],
53
+ requiredArtifacts: ['devtoolsLogs', 'Stylesheets', 'URL'],
54
54
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
55
55
  };
56
56
  }
@@ -67,7 +67,7 @@ class FontDisplay extends Audit {
67
67
  const failingURLs = new Set();
68
68
 
69
69
  // Go through all the stylesheets to find all @font-face declarations
70
- for (const stylesheet of artifacts.CSSUsage.stylesheets) {
70
+ for (const stylesheet of artifacts.Stylesheets) {
71
71
  // Eliminate newlines so we can more easily scan through with a regex
72
72
  const newlinesStripped = stylesheet.content.replace(/(\r|\n)+/g, ' ');
73
73
  // Find the @font-faces
@@ -1,4 +1,6 @@
1
1
  export default ResourceSummary;
2
+ export type ResourceType = import('../computed/resource-summary.js').ResourceType;
3
+ /** @typedef {import('../computed/resource-summary.js').ResourceType} ResourceType */
2
4
  declare class ResourceSummary extends Audit {
3
5
  /**
4
6
  * @param {LH.Artifacts} artifacts
@@ -10,6 +10,8 @@ import * as i18n from '../lib/i18n/i18n.js';
10
10
 
11
11
  const str_ = i18n.createIcuMessageFn(import.meta.url);
12
12
 
13
+ /** @typedef {import('../computed/resource-summary.js').ResourceType} ResourceType */
14
+
13
15
  class ResourceSummary extends Audit {
14
16
  /**
15
17
  * @return {LH.Audit.Meta}
@@ -32,7 +34,7 @@ class ResourceSummary extends Audit {
32
34
  static async audit(artifacts, context) {
33
35
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
34
36
  const summary = await ComputedResourceSummary
35
- .request({devtoolsLog, URL: artifacts.URL, budgets: context.settings.budgets}, context);
37
+ .request({devtoolsLog, URL: artifacts.URL}, context);
36
38
 
37
39
  /** @type {LH.Audit.Details.Table['headings']} */
38
40
  const headings = [
@@ -41,8 +43,7 @@ class ResourceSummary extends Audit {
41
43
  {key: 'transferSize', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
42
44
  ];
43
45
 
44
-
45
- /** @type {Record<LH.Budget.ResourceType, LH.IcuMessage>} */
46
+ /** @type {Record<ResourceType, LH.IcuMessage>} */
46
47
  const strMappings = {
47
48
  'total': str_(i18n.UIStrings.totalResourceType),
48
49
  'document': str_(i18n.UIStrings.documentResourceType),
@@ -55,7 +56,7 @@ class ResourceSummary extends Audit {
55
56
  'third-party': str_(i18n.UIStrings.thirdPartyResourceType),
56
57
  };
57
58
 
58
- const types = /** @type {Array<LH.Budget.ResourceType>} */ (Object.keys(summary));
59
+ const types = /** @type {Array<ResourceType>} */ (Object.keys(summary));
59
60
  const rows = types.map(type => {
60
61
  return {
61
62
  // ResourceType is included as an "id" for ease of use.
@@ -4,42 +4,40 @@ export type ResourceEntry = {
4
4
  resourceSize: number;
5
5
  transferSize: number;
6
6
  };
7
+ export type ResourceType = 'stylesheet' | 'image' | 'media' | 'font' | 'script' | 'document' | 'other' | 'third-party' | 'total';
7
8
  declare const ResourceSummaryComputed: typeof ResourceSummary & {
8
9
  request: (dependencies: {
9
10
  URL: LH.Artifacts['URL'];
10
11
  devtoolsLog: import("../index.js").DevtoolsLog;
11
- budgets: LH.Util.ImmutableObject<LH.Budget[] | null>;
12
12
  }, context: import("../../types/utility-types.js").default.ImmutableObject<{
13
13
  computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
14
- }>) => Promise<Record<import("../../types/lhr/budget.js").default.ResourceType, ResourceEntry>>;
14
+ }>) => Promise<Record<ResourceType, ResourceEntry>>;
15
15
  };
16
16
  /** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
17
+ /** @typedef {'stylesheet'|'image'|'media'|'font'|'script'|'document'|'other'|'third-party'|'total'} ResourceType */
17
18
  declare class ResourceSummary {
18
19
  /**
19
20
  * @param {LH.Artifacts.NetworkRequest} record
20
- * @return {LH.Budget.ResourceType}
21
+ * @return {ResourceType}
21
22
  */
22
- static determineResourceType(record: LH.Artifacts.NetworkRequest): LH.Budget.ResourceType;
23
+ static determineResourceType(record: LH.Artifacts.NetworkRequest): ResourceType;
23
24
  /**
24
25
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
25
26
  * @param {LH.Artifacts.URL} URLArtifact
26
- * @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
27
27
  * @param {LH.Artifacts.EntityClassification} classifiedEntities
28
- * @return {Record<LH.Budget.ResourceType, ResourceEntry>}
28
+ * @return {Record<ResourceType, ResourceEntry>}
29
29
  */
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
+ static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, classifiedEntities: LH.Artifacts.EntityClassification): Record<ResourceType, ResourceEntry>;
31
31
  /**
32
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, budgets: LH.Util.ImmutableObject<LH.Budget[]|null>}} data
32
+ * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
33
33
  * @param {LH.Artifacts.ComputedContext} context
34
- * @return {Promise<Record<LH.Budget.ResourceType,ResourceEntry>>}
34
+ * @return {Promise<Record<ResourceType,ResourceEntry>>}
35
35
  */
36
36
  static compute_(data: {
37
37
  URL: LH.Artifacts['URL'];
38
38
  devtoolsLog: import("../index.js").DevtoolsLog;
39
- budgets: LH.Util.ImmutableObject<LH.Budget[] | null>;
40
- }, context: LH.Artifacts.ComputedContext): Promise<Record<LH.Budget.ResourceType, ResourceEntry>>;
39
+ }, context: LH.Artifacts.ComputedContext): Promise<Record<ResourceType, ResourceEntry>>;
41
40
  }
42
- import { Budget } from '../config/budget.js';
43
41
  import { NetworkRequest } from '../lib/network-request.js';
44
42
  import { EntityClassification } from './entity-classification.js';
45
43
  //# sourceMappingURL=resource-summary.d.ts.map
@@ -8,19 +8,19 @@ import {EntityClassification} from './entity-classification.js';
8
8
  import {makeComputedArtifact} from './computed-artifact.js';
9
9
  import {NetworkRecords} from './network-records.js';
10
10
  import {NetworkRequest} from '../lib/network-request.js';
11
- import {Budget} from '../config/budget.js';
12
11
  import UrlUtils from '../lib/url-utils.js';
13
12
 
14
13
  /** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
14
+ /** @typedef {'stylesheet'|'image'|'media'|'font'|'script'|'document'|'other'|'third-party'|'total'} ResourceType */
15
15
 
16
16
  class ResourceSummary {
17
17
  /**
18
18
  * @param {LH.Artifacts.NetworkRequest} record
19
- * @return {LH.Budget.ResourceType}
19
+ * @return {ResourceType}
20
20
  */
21
21
  static determineResourceType(record) {
22
22
  if (!record.resourceType) return 'other';
23
- /** @type {Partial<Record<LH.Crdp.Network.ResourceType, LH.Budget.ResourceType>>} */
23
+ /** @type {Partial<Record<LH.Crdp.Network.ResourceType, ResourceType>>} */
24
24
  const requestToResourceType = {
25
25
  'Stylesheet': 'stylesheet',
26
26
  'Image': 'image',
@@ -35,12 +35,11 @@ class ResourceSummary {
35
35
  /**
36
36
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
37
37
  * @param {LH.Artifacts.URL} URLArtifact
38
- * @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
39
38
  * @param {LH.Artifacts.EntityClassification} classifiedEntities
40
- * @return {Record<LH.Budget.ResourceType, ResourceEntry>}
39
+ * @return {Record<ResourceType, ResourceEntry>}
41
40
  */
42
- static summarize(networkRecords, URLArtifact, budgets, classifiedEntities) {
43
- /** @type {Record<LH.Budget.ResourceType, ResourceEntry>} */
41
+ static summarize(networkRecords, URLArtifact, classifiedEntities) {
42
+ /** @type {Record<ResourceType, ResourceEntry>} */
44
43
  const resourceSummary = {
45
44
  'stylesheet': {count: 0, resourceSize: 0, transferSize: 0},
46
45
  'image': {count: 0, resourceSize: 0, transferSize: 0},
@@ -52,15 +51,9 @@ class ResourceSummary {
52
51
  'total': {count: 0, resourceSize: 0, transferSize: 0},
53
52
  'third-party': {count: 0, resourceSize: 0, transferSize: 0},
54
53
  };
55
- const budget = Budget.getMatchingBudget(budgets, URLArtifact.mainDocumentUrl);
56
54
  /** @type {ReadonlyArray<string>} */
57
- let firstPartyHosts = [];
58
- if (budget?.options?.firstPartyHostnames) {
59
- firstPartyHosts = budget.options.firstPartyHostnames;
60
- } else {
61
- firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
62
- [`*.${UrlUtils.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
63
- }
55
+ const firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
56
+ [`*.${UrlUtils.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
64
57
 
65
58
  networkRecords.filter(record => {
66
59
  // Ignore favicon.co
@@ -101,18 +94,18 @@ class ResourceSummary {
101
94
  }
102
95
 
103
96
  /**
104
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, budgets: LH.Util.ImmutableObject<LH.Budget[]|null>}} data
97
+ * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
105
98
  * @param {LH.Artifacts.ComputedContext} context
106
- * @return {Promise<Record<LH.Budget.ResourceType,ResourceEntry>>}
99
+ * @return {Promise<Record<ResourceType,ResourceEntry>>}
107
100
  */
108
101
  static async compute_(data, context) {
109
102
  const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
110
103
  const classifiedEntities = await EntityClassification.request(
111
104
  {URL: data.URL, devtoolsLog: data.devtoolsLog}, context);
112
- return ResourceSummary.summarize(networkRecords, data.URL, data.budgets, classifiedEntities);
105
+ return ResourceSummary.summarize(networkRecords, data.URL, classifiedEntities);
113
106
  }
114
107
  }
115
108
 
116
109
  const ResourceSummaryComputed =
117
- makeComputedArtifact(ResourceSummary, ['URL', 'devtoolsLog', 'budgets']);
110
+ makeComputedArtifact(ResourceSummary, ['URL', 'devtoolsLog']);
118
111
  export {ResourceSummaryComputed as ResourceSummary};
@@ -5,6 +5,7 @@ export type StyleSheetInfo = LH.Artifacts.CSSStyleSheetInfo & {
5
5
  };
6
6
  declare const UnusedCSSComputed: typeof UnusedCSS & {
7
7
  request: (dependencies: {
8
+ Stylesheets: LH.Artifacts['Stylesheets'];
8
9
  CSSUsage: LH.Artifacts['CSSUsage'];
9
10
  devtoolsLog: import("../index.js").DevtoolsLog;
10
11
  }, context: import("../../types/utility-types.js").default.ImmutableObject<{
@@ -50,11 +51,12 @@ declare class UnusedCSS {
50
51
  */
51
52
  static mapSheetToResult(stylesheetInfo: StyleSheetInfo): LH.Audit.ByteEfficiencyItem;
52
53
  /**
53
- * @param {{CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
54
+ * @param {{Stylesheets: LH.Artifacts['Stylesheets'], CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
54
55
  * @param {LH.Artifacts.ComputedContext} context
55
56
  * @return {Promise<LH.Audit.ByteEfficiencyItem[]>}
56
57
  */
57
58
  static compute_(data: {
59
+ Stylesheets: LH.Artifacts['Stylesheets'];
58
60
  CSSUsage: LH.Artifacts['CSSUsage'];
59
61
  devtoolsLog: import("../index.js").DevtoolsLog;
60
62
  }, context: LH.Artifacts.ComputedContext): Promise<LH.Audit.ByteEfficiencyItem[]>;
@@ -134,15 +134,15 @@ class UnusedCSS {
134
134
  }
135
135
 
136
136
  /**
137
- * @param {{CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
137
+ * @param {{Stylesheets: LH.Artifacts['Stylesheets'], CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
138
138
  * @param {LH.Artifacts.ComputedContext} context
139
139
  * @return {Promise<LH.Audit.ByteEfficiencyItem[]>}
140
140
  */
141
141
  static async compute_(data, context) {
142
- const {CSSUsage, devtoolsLog} = data;
142
+ const {CSSUsage, Stylesheets, devtoolsLog} = data;
143
143
  const networkRecords = await NetworkRecords.request(devtoolsLog, context);
144
- const indexedSheets = UnusedCSS.indexStylesheetsById(CSSUsage.stylesheets, networkRecords);
145
- UnusedCSS.indexUsedRules(CSSUsage.rules, indexedSheets);
144
+ const indexedSheets = UnusedCSS.indexStylesheetsById(Stylesheets, networkRecords);
145
+ UnusedCSS.indexUsedRules(CSSUsage, indexedSheets);
146
146
 
147
147
  const items = Object.keys(indexedSheets)
148
148
  .map(sheetId => UnusedCSS.mapSheetToResult(indexedSheets[sheetId]));
@@ -150,5 +150,6 @@ class UnusedCSS {
150
150
  }
151
151
  }
152
152
 
153
- const UnusedCSSComputed = makeComputedArtifact(UnusedCSS, ['CSSUsage', 'devtoolsLog']);
153
+ const UnusedCSSComputed = makeComputedArtifact(UnusedCSS,
154
+ ['Stylesheets', 'CSSUsage', 'devtoolsLog']);
154
155
  export {UnusedCSSComputed as UnusedCSS};
@@ -11,7 +11,6 @@ import url from 'url';
11
11
  import isDeepEqual from 'lodash/isEqual.js';
12
12
 
13
13
  import * as constants from './constants.js';
14
- import {Budget} from './budget.js';
15
14
  import ConfigPlugin from './config-plugin.js';
16
15
  import {Runner} from '../runner.js';
17
16
  import * as i18n from '../lib/i18n/i18n.js';
@@ -347,9 +346,6 @@ function resolveSettings(settingsJson = {}, overrides = undefined) {
347
346
  true
348
347
  );
349
348
 
350
- if (settingsWithFlags.budgets) {
351
- settingsWithFlags.budgets = Budget.initializeBudget(settingsWithFlags.budgets);
352
- }
353
349
  // Locale is special and comes only from flags/settings/lookupLocale.
354
350
  settingsWithFlags.locale = locale;
355
351
 
@@ -118,7 +118,6 @@ const defaultSettings = {
118
118
 
119
119
  // the following settings have no defaults but we still want ensure that `key in settings`
120
120
  // in config will work in a typechecked way
121
- budgets: null,
122
121
  locale: 'en-US', // actual default determined by Config using lib/i18n
123
122
  blockedUrlPatterns: null,
124
123
  additionalTraceCategories: null,
@@ -13,10 +13,6 @@ import * as i18n from '../lib/i18n/i18n.js';
13
13
  const UIStrings = {
14
14
  /** Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters. */
15
15
  performanceCategoryTitle: 'Performance',
16
- /** Title of the Budgets section of the Performance Category. 'Budgets' refers to a budget (like a financial budget), but applied to the amount of resources on a page, rather than money. */
17
- budgetsGroupTitle: 'Budgets',
18
- /** Description of the Budgets section of the Performance category. Within this section the budget results are displayed. */
19
- budgetsGroupDescription: 'Performance budgets set standards for the performance of your site.',
20
16
  /** Title of the speed metrics section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. */
21
17
  metricGroupTitle: 'Metrics',
22
18
  /** Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage. */
@@ -136,6 +132,7 @@ const defaultConfig = {
136
132
  {id: 'Scripts', gatherer: 'scripts'},
137
133
  {id: 'SourceMaps', gatherer: 'source-maps'},
138
134
  {id: 'Stacks', gatherer: 'stacks'},
135
+ {id: 'Stylesheets', gatherer: 'stylesheets'},
139
136
  {id: 'TraceElements', gatherer: 'trace-elements'},
140
137
  {id: 'ViewportDimensions', gatherer: 'viewport-dimensions'},
141
138
 
@@ -183,8 +180,6 @@ const defaultConfig = {
183
180
  'network-server-latency',
184
181
  'main-thread-tasks',
185
182
  'metrics',
186
- 'performance-budget',
187
- 'timing-budget',
188
183
  'resource-summary',
189
184
  'third-party-summary',
190
185
  'third-party-facades',
@@ -312,10 +307,6 @@ const defaultConfig = {
312
307
  'metrics': {
313
308
  title: str_(UIStrings.metricGroupTitle),
314
309
  },
315
- 'budgets': {
316
- title: str_(UIStrings.budgetsGroupTitle),
317
- description: str_(UIStrings.budgetsGroupDescription),
318
- },
319
310
  'diagnostics': {
320
311
  title: str_(UIStrings.diagnosticsGroupTitle),
321
312
  description: str_(UIStrings.diagnosticsGroupDescription),
@@ -437,10 +428,6 @@ const defaultConfig = {
437
428
  {id: 'work-during-interaction', weight: 0, group: 'diagnostics'},
438
429
  {id: 'bf-cache', weight: 0, group: 'diagnostics'},
439
430
 
440
- // Budget audits.
441
- {id: 'performance-budget', weight: 0, group: 'budgets'},
442
- {id: 'timing-budget', weight: 0, group: 'budgets'},
443
-
444
431
  // Audits past this point contain useful data but are not displayed with other audits.
445
432
  {id: 'network-requests', weight: 0, group: 'hidden'},
446
433
  {id: 'network-rtt', weight: 0, group: 'hidden'},
@@ -1,26 +1,5 @@
1
1
  export default CSSUsage;
2
2
  declare class CSSUsage extends BaseGatherer {
3
- /** @type {LH.Gatherer.ProtocolSession|undefined} */
4
- _session: LH.Gatherer.ProtocolSession | undefined;
5
- /** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|Error>>} */
6
- _sheetPromises: Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo | Error>>;
7
- /**
8
- * Initialize as undefined so we can assert results are fetched.
9
- * @type {LH.Crdp.CSS.RuleUsage[]|undefined}
10
- */
11
- _ruleUsage: LH.Crdp.CSS.RuleUsage[] | undefined;
12
- /**
13
- * @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
14
- */
15
- _onStylesheetAdded(event: LH.Crdp.CSS.StyleSheetAddedEvent): void;
16
- /**
17
- * @param {LH.Gatherer.Context} context
18
- */
19
- startInstrumentation(context: LH.Gatherer.Context): Promise<void>;
20
- /**
21
- * @param {LH.Gatherer.Context} context
22
- */
23
- stopInstrumentation(context: LH.Gatherer.Context): Promise<void>;
24
3
  /**
25
4
  * @param {LH.Gatherer.Context} context
26
5
  * @return {Promise<LH.Artifacts['CSSUsage']>}
@@ -8,145 +8,35 @@
8
8
  * @fileoverview Tracks unused CSS rules.
9
9
  */
10
10
 
11
- import log from 'lighthouse-logger';
12
-
13
11
  import BaseGatherer from '../base-gatherer.js';
14
- import {Sentry} from '../../lib/sentry.js';
15
12
 
16
13
  class CSSUsage extends BaseGatherer {
17
- constructor() {
18
- super();
19
- /** @type {LH.Gatherer.ProtocolSession|undefined} */
20
- this._session = undefined;
21
- /** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|Error>>} */
22
- this._sheetPromises = new Map();
23
- /**
24
- * Initialize as undefined so we can assert results are fetched.
25
- * @type {LH.Crdp.CSS.RuleUsage[]|undefined}
26
- */
27
- this._ruleUsage = undefined;
28
- this._onStylesheetAdded = this._onStylesheetAdded.bind(this);
29
- }
30
-
31
14
  /** @type {LH.Gatherer.GathererMeta} */
32
15
  meta = {
33
- supportedModes: ['snapshot', 'timespan', 'navigation'],
16
+ supportedModes: ['snapshot', 'navigation'],
34
17
  };
35
18
 
36
- /**
37
- * @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
38
- */
39
- _onStylesheetAdded(event) {
40
- if (!this._session) throw new Error('Session not initialized');
41
- const styleSheetId = event.header.styleSheetId;
42
- const sheetPromise = this._session.sendCommand('CSS.getStyleSheetText', {styleSheetId})
43
- .then(content => ({
44
- header: event.header,
45
- content: content.text,
46
- }))
47
- .catch(/** @param {Error} err */ (err) => {
48
- log.warn(
49
- 'CSSUsage',
50
- `Error fetching content of stylesheet with URL "${event.header.sourceURL}"`
51
- );
52
- Sentry.captureException(err, {
53
- tags: {
54
- gatherer: 'CSSUsage',
55
- },
56
- extra: {
57
- url: event.header.sourceURL,
58
- },
59
- level: 'error',
60
- });
61
- return err;
62
- });
63
- this._sheetPromises.set(styleSheetId, sheetPromise);
64
- }
65
-
66
19
  /**
67
20
  * @param {LH.Gatherer.Context} context
21
+ * @return {Promise<LH.Artifacts['CSSUsage']>}
68
22
  */
69
- async startInstrumentation(context) {
23
+ async getArtifact(context) {
70
24
  const session = context.driver.defaultSession;
71
- this._session = session;
72
-
73
- // Calling `CSS.enable` will emit events for stylesheets currently on the page.
74
- // We want to ignore these events in navigation mode because they are not relevant to the
75
- // navigation that is about to happen. Adding the event listener *after* calling `CSS.enable`
76
- // ensures that the events for pre-existing stylesheets are ignored.
77
- const isNavigation = context.gatherMode === 'navigation';
78
- if (!isNavigation) {
79
- session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
80
- }
25
+ const executionContext = context.driver.executionContext;
81
26
 
82
27
  await session.sendCommand('DOM.enable');
83
28
  await session.sendCommand('CSS.enable');
84
29
  await session.sendCommand('CSS.startRuleUsageTracking');
85
30
 
86
- if (isNavigation) {
87
- session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
88
- }
89
- }
90
-
91
-
92
- /**
93
- * @param {LH.Gatherer.Context} context
94
- */
95
- async stopInstrumentation(context) {
96
- const session = context.driver.defaultSession;
97
- const coverageResponse = await session.sendCommand('CSS.stopRuleUsageTracking');
98
- this._ruleUsage = coverageResponse.ruleUsage;
99
- session.off('CSS.styleSheetAdded', this._onStylesheetAdded);
100
-
101
- // Ensure we finish fetching all stylesheet contents before disabling the CSS domain
102
- await Promise.all(this._sheetPromises.values());
31
+ // Force style to recompute.
32
+ // Doesn't appear to be necessary in newer versions of Chrome.
33
+ await executionContext.evaluateAsync('getComputedStyle(document.body)');
103
34
 
35
+ const {ruleUsage} = await session.sendCommand('CSS.stopRuleUsageTracking');
104
36
  await session.sendCommand('CSS.disable');
105
37
  await session.sendCommand('DOM.disable');
106
- }
107
-
108
- /**
109
- * @param {LH.Gatherer.Context} context
110
- * @return {Promise<LH.Artifacts['CSSUsage']>}
111
- */
112
- async getArtifact(context) {
113
- const executionContext = context.driver.executionContext;
114
-
115
- if (context.gatherMode === 'snapshot') {
116
- await this.startInstrumentation(context);
117
-
118
- // Force style to recompute.
119
- // Doesn't appear to be necessary in newer versions of Chrome.
120
- await executionContext.evaluateAsync('getComputedStyle(document.body)');
121
-
122
- await this.stopInstrumentation(context);
123
- }
124
-
125
- /** @type {Map<string, LH.Artifacts.CSSStyleSheetInfo>} */
126
- const dedupedStylesheets = new Map();
127
- const sheets = await Promise.all(this._sheetPromises.values());
128
-
129
- for (const sheet of sheets) {
130
- // Erroneous sheets will be reported via sentry and the log.
131
- // We can ignore them here without throwing a fatal error.
132
- if (sheet instanceof Error) {
133
- continue;
134
- }
135
-
136
- // Exclude empty stylesheets.
137
- if (sheet.header.length === 0) {
138
- continue;
139
- }
140
-
141
- dedupedStylesheets.set(sheet.content, sheet);
142
- }
143
-
144
- if (!this._ruleUsage) throw new Error('Issue collecting rule usages');
145
38
 
146
- return {
147
- rules: this._ruleUsage,
148
- stylesheets: Array.from(dedupedStylesheets.values()),
149
- };
39
+ return ruleUsage;
150
40
  }
151
41
  }
152
42