lighthouse 11.7.0-dev.20240416 → 11.7.0-dev.20240418
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/bin.js +0 -7
- package/cli/cli-flags.d.ts +1 -5
- package/cli/cli-flags.js +1 -5
- package/cli/test/smokehouse/core-tests.js +0 -2
- package/core/audits/accessibility/aria-conditional-attr.d.ts +10 -0
- package/core/audits/accessibility/aria-conditional-attr.js +43 -0
- package/core/audits/accessibility/aria-deprecated-role.d.ts +10 -0
- package/core/audits/accessibility/aria-deprecated-role.js +43 -0
- package/core/audits/accessibility/aria-prohibited-attr.d.ts +10 -0
- package/core/audits/accessibility/aria-prohibited-attr.js +44 -0
- package/core/audits/byte-efficiency/render-blocking-resources.js +3 -1
- package/core/audits/byte-efficiency/unminified-css.js +2 -2
- package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
- package/core/audits/font-display.js +2 -2
- package/core/audits/resource-summary.d.ts +2 -0
- package/core/audits/resource-summary.js +5 -4
- package/core/computed/resource-summary.d.ts +10 -12
- package/core/computed/resource-summary.js +12 -19
- package/core/computed/unused-css.d.ts +3 -1
- package/core/computed/unused-css.js +6 -5
- package/core/config/config-helpers.js +0 -4
- package/core/config/constants.js +0 -1
- package/core/config/default-config.js +7 -14
- package/core/gather/gatherers/accessibility.js +3 -3
- package/core/gather/gatherers/css-usage.d.ts +0 -21
- package/core/gather/gatherers/css-usage.js +9 -119
- package/core/gather/gatherers/stylesheets.d.ts +26 -0
- package/core/gather/gatherers/stylesheets.js +138 -0
- package/core/lib/i18n/i18n.d.ts +0 -1
- package/core/lib/i18n/i18n.js +0 -2
- package/core/runner.js +0 -1
- package/dist/report/bundle.esm.js +2 -19
- package/dist/report/flow.js +5 -22
- package/dist/report/standalone.js +3 -20
- package/package.json +3 -3
- package/readme.md +2 -2
- package/report/assets/styles.css +0 -17
- package/report/renderer/components.js +1 -1
- package/report/renderer/dom.d.ts +1 -1
- package/report/renderer/dom.js +1 -1
- package/report/renderer/performance-category-renderer.js +0 -21
- package/shared/localization/locales/ar-XB.json +61 -91
- package/shared/localization/locales/ar.json +61 -91
- package/shared/localization/locales/bg.json +61 -91
- package/shared/localization/locales/ca.json +61 -91
- package/shared/localization/locales/cs.json +61 -91
- package/shared/localization/locales/da.json +61 -91
- package/shared/localization/locales/de.json +61 -91
- package/shared/localization/locales/el.json +61 -91
- package/shared/localization/locales/en-GB.json +61 -91
- package/shared/localization/locales/en-US.json +27 -30
- package/shared/localization/locales/en-XA.json +61 -91
- package/shared/localization/locales/en-XL.json +27 -30
- package/shared/localization/locales/es-419.json +61 -91
- package/shared/localization/locales/es.json +61 -91
- package/shared/localization/locales/fi.json +61 -91
- package/shared/localization/locales/fil.json +60 -90
- package/shared/localization/locales/fr.json +61 -91
- package/shared/localization/locales/he.json +61 -91
- package/shared/localization/locales/hi.json +61 -91
- package/shared/localization/locales/hr.json +62 -92
- package/shared/localization/locales/hu.json +61 -91
- package/shared/localization/locales/id.json +61 -91
- package/shared/localization/locales/it.json +61 -91
- package/shared/localization/locales/ja.json +61 -91
- package/shared/localization/locales/ko.json +61 -91
- package/shared/localization/locales/lt.json +61 -91
- package/shared/localization/locales/lv.json +61 -91
- package/shared/localization/locales/nl.json +61 -91
- package/shared/localization/locales/no.json +61 -91
- package/shared/localization/locales/pl.json +60 -90
- package/shared/localization/locales/pt-PT.json +61 -91
- package/shared/localization/locales/pt.json +63 -93
- package/shared/localization/locales/ro.json +61 -91
- package/shared/localization/locales/ru.json +61 -91
- package/shared/localization/locales/sk.json +61 -91
- package/shared/localization/locales/sl.json +61 -91
- package/shared/localization/locales/sr-Latn.json +61 -91
- package/shared/localization/locales/sr.json +61 -91
- package/shared/localization/locales/sv.json +61 -91
- package/shared/localization/locales/ta.json +60 -90
- package/shared/localization/locales/te.json +61 -91
- package/shared/localization/locales/th.json +61 -91
- package/shared/localization/locales/tr.json +61 -91
- package/shared/localization/locales/uk.json +61 -91
- package/shared/localization/locales/vi.json +60 -90
- package/shared/localization/locales/zh-HK.json +61 -91
- package/shared/localization/locales/zh-TW.json +60 -90
- package/shared/localization/locales/zh.json +61 -91
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +3 -1
- package/types/externs.d.ts +0 -2
- package/types/lh.d.ts +0 -2
- package/types/lhr/settings.d.ts +0 -4
- package/core/audits/performance-budget.d.ts +0 -39
- package/core/audits/performance-budget.js +0 -154
- package/core/audits/timing-budget.d.ts +0 -43
- package/core/audits/timing-budget.js +0 -175
- package/core/config/budget.d.ts +0 -74
- package/core/config/budget.js +0 -340
- package/types/lhr/budget.d.ts +0 -60
|
@@ -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',
|
|
@@ -202,12 +197,15 @@ const defaultConfig = {
|
|
|
202
197
|
'accessibility/aria-allowed-attr',
|
|
203
198
|
'accessibility/aria-allowed-role',
|
|
204
199
|
'accessibility/aria-command-name',
|
|
200
|
+
'accessibility/aria-conditional-attr',
|
|
201
|
+
'accessibility/aria-deprecated-role',
|
|
205
202
|
'accessibility/aria-dialog-name',
|
|
206
203
|
'accessibility/aria-hidden-body',
|
|
207
204
|
'accessibility/aria-hidden-focus',
|
|
208
205
|
'accessibility/aria-input-field-name',
|
|
209
206
|
'accessibility/aria-meter-name',
|
|
210
207
|
'accessibility/aria-progressbar-name',
|
|
208
|
+
'accessibility/aria-prohibited-attr',
|
|
211
209
|
'accessibility/aria-required-attr',
|
|
212
210
|
'accessibility/aria-required-children',
|
|
213
211
|
'accessibility/aria-required-parent',
|
|
@@ -312,10 +310,6 @@ const defaultConfig = {
|
|
|
312
310
|
'metrics': {
|
|
313
311
|
title: str_(UIStrings.metricGroupTitle),
|
|
314
312
|
},
|
|
315
|
-
'budgets': {
|
|
316
|
-
title: str_(UIStrings.budgetsGroupTitle),
|
|
317
|
-
description: str_(UIStrings.budgetsGroupDescription),
|
|
318
|
-
},
|
|
319
313
|
'diagnostics': {
|
|
320
314
|
title: str_(UIStrings.diagnosticsGroupTitle),
|
|
321
315
|
description: str_(UIStrings.diagnosticsGroupDescription),
|
|
@@ -437,10 +431,6 @@ const defaultConfig = {
|
|
|
437
431
|
{id: 'work-during-interaction', weight: 0, group: 'diagnostics'},
|
|
438
432
|
{id: 'bf-cache', weight: 0, group: 'diagnostics'},
|
|
439
433
|
|
|
440
|
-
// Budget audits.
|
|
441
|
-
{id: 'performance-budget', weight: 0, group: 'budgets'},
|
|
442
|
-
{id: 'timing-budget', weight: 0, group: 'budgets'},
|
|
443
|
-
|
|
444
434
|
// Audits past this point contain useful data but are not displayed with other audits.
|
|
445
435
|
{id: 'network-requests', weight: 0, group: 'hidden'},
|
|
446
436
|
{id: 'network-rtt', weight: 0, group: 'hidden'},
|
|
@@ -468,12 +458,15 @@ const defaultConfig = {
|
|
|
468
458
|
{id: 'aria-allowed-attr', weight: 10, group: 'a11y-aria'},
|
|
469
459
|
{id: 'aria-allowed-role', weight: 1, group: 'a11y-aria'},
|
|
470
460
|
{id: 'aria-command-name', weight: 7, group: 'a11y-aria'},
|
|
461
|
+
{id: 'aria-conditional-attr', weight: 7, group: 'a11y-aria'},
|
|
462
|
+
{id: 'aria-deprecated-role', weight: 1, group: 'a11y-aria'},
|
|
471
463
|
{id: 'aria-dialog-name', weight: 7, group: 'a11y-aria'},
|
|
472
464
|
{id: 'aria-hidden-body', weight: 10, group: 'a11y-aria'},
|
|
473
465
|
{id: 'aria-hidden-focus', weight: 7, group: 'a11y-aria'},
|
|
474
466
|
{id: 'aria-input-field-name', weight: 7, group: 'a11y-aria'},
|
|
475
467
|
{id: 'aria-meter-name', weight: 7, group: 'a11y-aria'},
|
|
476
468
|
{id: 'aria-progressbar-name', weight: 7, group: 'a11y-aria'},
|
|
469
|
+
{id: 'aria-prohibited-attr', weight: 7, group: 'a11y-aria'},
|
|
477
470
|
{id: 'aria-required-attr', weight: 10, group: 'a11y-aria'},
|
|
478
471
|
{id: 'aria-required-children', weight: 10, group: 'a11y-aria'},
|
|
479
472
|
{id: 'aria-required-parent', weight: 10, group: 'a11y-aria'},
|
|
@@ -43,10 +43,10 @@ async function runA11yChecks() {
|
|
|
43
43
|
'area-alt': {enabled: false},
|
|
44
44
|
'aria-allowed-role': {enabled: true},
|
|
45
45
|
'aria-braille-equivalent': {enabled: false},
|
|
46
|
-
'aria-conditional-attr': {enabled:
|
|
47
|
-
'aria-deprecated-role': {enabled:
|
|
46
|
+
'aria-conditional-attr': {enabled: true},
|
|
47
|
+
'aria-deprecated-role': {enabled: true},
|
|
48
48
|
'aria-dialog-name': {enabled: true},
|
|
49
|
-
'aria-prohibited-attr': {enabled:
|
|
49
|
+
'aria-prohibited-attr': {enabled: true},
|
|
50
50
|
'aria-roledescription': {enabled: false},
|
|
51
51
|
'aria-treeitem-name': {enabled: true},
|
|
52
52
|
'aria-text': {enabled: true},
|
|
@@ -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', '
|
|
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
|
|
23
|
+
async getArtifact(context) {
|
|
70
24
|
const session = context.driver.defaultSession;
|
|
71
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default Stylesheets;
|
|
2
|
+
declare class Stylesheets extends BaseGatherer {
|
|
3
|
+
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
4
|
+
_session: LH.Gatherer.ProtocolSession | undefined;
|
|
5
|
+
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|null>>} */
|
|
6
|
+
_sheetPromises: Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo | null>>;
|
|
7
|
+
/**
|
|
8
|
+
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
9
|
+
*/
|
|
10
|
+
_onStylesheetAdded(event: LH.Crdp.CSS.StyleSheetAddedEvent): void;
|
|
11
|
+
/**
|
|
12
|
+
* @param {LH.Gatherer.Context} context
|
|
13
|
+
*/
|
|
14
|
+
startInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* @param {LH.Gatherer.Context} context
|
|
17
|
+
*/
|
|
18
|
+
stopInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* @param {LH.Gatherer.Context} context
|
|
21
|
+
* @return {Promise<LH.Artifacts['Stylesheets']>}
|
|
22
|
+
*/
|
|
23
|
+
getArtifact(context: LH.Gatherer.Context): Promise<LH.Artifacts['Stylesheets']>;
|
|
24
|
+
}
|
|
25
|
+
import BaseGatherer from '../base-gatherer.js';
|
|
26
|
+
//# sourceMappingURL=stylesheets.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Collects all stylesheets and their contents.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import log from 'lighthouse-logger';
|
|
12
|
+
|
|
13
|
+
import BaseGatherer from '../base-gatherer.js';
|
|
14
|
+
import {Sentry} from '../../lib/sentry.js';
|
|
15
|
+
|
|
16
|
+
class Stylesheets extends BaseGatherer {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
20
|
+
this._session = undefined;
|
|
21
|
+
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|null>>} */
|
|
22
|
+
this._sheetPromises = new Map();
|
|
23
|
+
this._onStylesheetAdded = this._onStylesheetAdded.bind(this);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @type {LH.Gatherer.GathererMeta} */
|
|
27
|
+
meta = {
|
|
28
|
+
supportedModes: ['snapshot', 'timespan', 'navigation'],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
33
|
+
*/
|
|
34
|
+
_onStylesheetAdded(event) {
|
|
35
|
+
if (!this._session) throw new Error('Session not initialized');
|
|
36
|
+
const styleSheetId = event.header.styleSheetId;
|
|
37
|
+
const sheetPromise = this._session.sendCommand('CSS.getStyleSheetText', {styleSheetId})
|
|
38
|
+
.then(content => ({
|
|
39
|
+
header: event.header,
|
|
40
|
+
content: content.text,
|
|
41
|
+
}))
|
|
42
|
+
.catch(err => {
|
|
43
|
+
log.warn(
|
|
44
|
+
'Stylesheets',
|
|
45
|
+
`Error fetching content of stylesheet with URL "${event.header.sourceURL}"`
|
|
46
|
+
);
|
|
47
|
+
Sentry.captureException(err, {
|
|
48
|
+
tags: {
|
|
49
|
+
gatherer: 'Stylesheets',
|
|
50
|
+
},
|
|
51
|
+
extra: {
|
|
52
|
+
url: event.header.sourceURL,
|
|
53
|
+
},
|
|
54
|
+
level: 'error',
|
|
55
|
+
});
|
|
56
|
+
return null;
|
|
57
|
+
});
|
|
58
|
+
this._sheetPromises.set(styleSheetId, sheetPromise);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {LH.Gatherer.Context} context
|
|
63
|
+
*/
|
|
64
|
+
async startInstrumentation(context) {
|
|
65
|
+
const session = context.driver.defaultSession;
|
|
66
|
+
this._session = session;
|
|
67
|
+
|
|
68
|
+
// Calling `CSS.enable` will emit events for stylesheets currently on the page.
|
|
69
|
+
// We want to ignore these events in navigation mode because they are not relevant to the
|
|
70
|
+
// navigation that is about to happen. Adding the event listener *after* calling `CSS.enable`
|
|
71
|
+
// ensures that the events for pre-existing stylesheets are ignored.
|
|
72
|
+
const isNavigation = context.gatherMode === 'navigation';
|
|
73
|
+
if (!isNavigation) {
|
|
74
|
+
session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await session.sendCommand('DOM.enable');
|
|
78
|
+
await session.sendCommand('CSS.enable');
|
|
79
|
+
|
|
80
|
+
if (isNavigation) {
|
|
81
|
+
session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {LH.Gatherer.Context} context
|
|
88
|
+
*/
|
|
89
|
+
async stopInstrumentation(context) {
|
|
90
|
+
const session = context.driver.defaultSession;
|
|
91
|
+
session.off('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
92
|
+
|
|
93
|
+
// Ensure we finish fetching all stylesheet contents before disabling the CSS domain
|
|
94
|
+
await Promise.all(this._sheetPromises.values());
|
|
95
|
+
|
|
96
|
+
await session.sendCommand('CSS.disable');
|
|
97
|
+
await session.sendCommand('DOM.disable');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {LH.Gatherer.Context} context
|
|
102
|
+
* @return {Promise<LH.Artifacts['Stylesheets']>}
|
|
103
|
+
*/
|
|
104
|
+
async getArtifact(context) {
|
|
105
|
+
const executionContext = context.driver.executionContext;
|
|
106
|
+
|
|
107
|
+
if (context.gatherMode === 'snapshot') {
|
|
108
|
+
await this.startInstrumentation(context);
|
|
109
|
+
|
|
110
|
+
// Force style to recompute.
|
|
111
|
+
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
112
|
+
await executionContext.evaluateAsync('getComputedStyle(document.body)');
|
|
113
|
+
|
|
114
|
+
await this.stopInstrumentation(context);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** @type {Map<string, LH.Artifacts.CSSStyleSheetInfo>} */
|
|
118
|
+
const dedupedStylesheets = new Map();
|
|
119
|
+
const sheets = await Promise.all(this._sheetPromises.values());
|
|
120
|
+
|
|
121
|
+
for (const sheet of sheets) {
|
|
122
|
+
// Erroneous sheets will be reported via sentry and the log.
|
|
123
|
+
// We can ignore them here without throwing a fatal error.
|
|
124
|
+
if (!sheet) continue;
|
|
125
|
+
|
|
126
|
+
// Exclude empty stylesheets.
|
|
127
|
+
if (sheet.header.length === 0) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
dedupedStylesheets.set(sheet.content, sheet);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return Array.from(dedupedStylesheets.values());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default Stylesheets;
|
package/core/lib/i18n/i18n.d.ts
CHANGED
package/core/lib/i18n/i18n.js
CHANGED
|
@@ -57,8 +57,6 @@ const UIStrings = {
|
|
|
57
57
|
columnName: 'Name',
|
|
58
58
|
/** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */
|
|
59
59
|
columnSource: 'Source',
|
|
60
|
-
/** Label for a column in a data table; entries will be how much a predetermined budget has been exeeded by. Depending on the context, this number could represent an excess in quantity or size of network requests, or, an excess in the duration of time that it takes for the page to load.*/
|
|
61
|
-
columnOverBudget: 'Over Budget',
|
|
62
60
|
/** Label for a column in a data table; entries will be a representation of a DOM element. */
|
|
63
61
|
columnElement: 'Element',
|
|
64
62
|
/** Label for a column in a data table; entries will be the number of milliseconds since the page started loading. */
|
package/core/runner.js
CHANGED
|
@@ -298,7 +298,6 @@ class Runner {
|
|
|
298
298
|
auditMode: undefined,
|
|
299
299
|
output: undefined,
|
|
300
300
|
channel: undefined,
|
|
301
|
-
budgets: undefined,
|
|
302
301
|
};
|
|
303
302
|
const normalizedGatherSettings = Object.assign({}, artifacts.settings, overrides);
|
|
304
303
|
const normalizedAuditSettings = Object.assign({}, settings, overrides);
|