0
# Configuration and Extension
1
2
Lighthouse provides a comprehensive configuration system and extensibility framework for customizing audits, creating custom gatherers, and adapting the tool to specific testing requirements. This system enables deep customization while maintaining compatibility with the core Lighthouse architecture.
3
4
## Capabilities
5
6
### Configuration Interface
7
8
The main configuration interface that controls all aspects of Lighthouse behavior.
9
10
```javascript { .api }
11
interface LH.Config {
12
// Core configuration
13
extends?: 'lighthouse:default' | 'lighthouse:desktop' | string;
14
settings?: LH.Config.Settings;
15
16
// Audit configuration
17
audits?: LH.Config.AuditDefn[];
18
categories?: Record<string, LH.Config.Category>;
19
groups?: Record<string, LH.Config.Group>;
20
21
// Extension points
22
plugins?: string[];
23
passes?: LH.Config.Pass[];
24
gatherers?: LH.Config.GathererDefn[];
25
}
26
```
27
28
### Configuration Settings
29
30
Runtime settings that control Lighthouse execution behavior.
31
32
```javascript { .api }
33
interface LH.Config.Settings {
34
// Output configuration
35
output?: LH.OutputMode | LH.OutputMode[];
36
outputPath?: string;
37
locale?: string;
38
39
// Runtime configuration
40
maxWaitForFcp?: number;
41
maxWaitForLoad?: number;
42
pauseAfterFcpMs?: number;
43
pauseAfterLoadMs?: number;
44
networkQuietThresholdMs?: number;
45
cpuQuietThresholdMs?: number;
46
47
// Throttling configuration
48
throttlingMethod?: 'devtools' | 'simulate' | 'provided';
49
throttling?: LH.ThrottlingSettings;
50
51
// Device emulation
52
screenEmulation?: LH.Config.ScreenEmulationSettings;
53
emulatedUserAgent?: string;
54
55
// Audit filtering
56
onlyAudits?: string[];
57
skipAudits?: string[];
58
onlyCategories?: string[];
59
60
// Advanced options
61
disableStorageReset?: boolean;
62
disableDeviceEmulation?: boolean;
63
clearStorageTypes?: string[];
64
budgets?: LH.Budget[];
65
}
66
```
67
68
**Usage Examples:**
69
70
```javascript
71
import lighthouse, { defaultConfig, desktopConfig } from 'lighthouse';
72
73
// Basic custom configuration
74
const customConfig = {
75
extends: 'lighthouse:default',
76
settings: {
77
onlyCategories: ['performance', 'accessibility'],
78
throttlingMethod: 'simulate',
79
screenEmulation: {
80
mobile: false,
81
width: 1920,
82
height: 1080,
83
deviceScaleFactor: 1,
84
},
85
},
86
};
87
88
const result = await lighthouse('https://example.com', {}, customConfig);
89
90
// Desktop configuration
91
const result = await lighthouse('https://example.com', {}, desktopConfig);
92
93
// Performance-only configuration
94
const perfConfig = {
95
extends: 'lighthouse:default',
96
settings: {
97
onlyCategories: ['performance'],
98
throttling: {
99
rttMs: 40,
100
throughputKbps: 10240,
101
cpuSlowdownMultiplier: 1,
102
},
103
},
104
};
105
```
106
107
### Audit System
108
109
Framework for creating and configuring custom audits.
110
111
```javascript { .api }
112
/**
113
* Base class for creating custom audits
114
*/
115
class Audit {
116
/**
117
* Audit metadata
118
*/
119
static get meta(): LH.Audit.Meta;
120
121
/**
122
* Main audit logic
123
* @param artifacts - Collected artifacts from gatherers
124
* @param context - Audit execution context
125
* @returns Audit result with score and details
126
*/
127
static audit(
128
artifacts: LH.Artifacts,
129
context: LH.Audit.Context
130
): LH.Audit.Product | Promise<LH.Audit.Product>;
131
132
/**
133
* Generate audit result structure
134
* @param score - Audit score (0-1 or null)
135
* @param options - Additional result options
136
* @returns Formatted audit result
137
*/
138
static generateAuditResult(
139
score: number | null,
140
options?: {
141
displayValue?: string;
142
explanation?: string;
143
errorMessage?: string;
144
warnings?: string[];
145
details?: LH.Audit.Details;
146
}
147
): LH.Audit.Product;
148
}
149
```
150
151
**Custom Audit Example:**
152
153
```javascript
154
import { Audit } from 'lighthouse';
155
156
class CustomPerformanceAudit extends Audit {
157
static get meta() {
158
return {
159
id: 'custom-performance-audit',
160
title: 'Custom Performance Check',
161
description: 'Checks for custom performance criteria',
162
requiredArtifacts: ['traces', 'devtoolsLogs'],
163
};
164
}
165
166
static audit(artifacts, context) {
167
const traces = artifacts.traces[Audit.DEFAULT_PASS];
168
const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
169
170
// Custom audit logic
171
const customMetric = calculateCustomMetric(traces, devtoolsLogs);
172
const score = customMetric < 2000 ? 1 : customMetric < 4000 ? 0.5 : 0;
173
174
return Audit.generateAuditResult(score, {
175
displayValue: `${customMetric}ms`,
176
details: {
177
type: 'table',
178
headings: [{key: 'metric', text: 'Custom Metric'}],
179
items: [{metric: `${customMetric}ms`}],
180
},
181
});
182
}
183
}
184
185
// Configuration with custom audit
186
const config = {
187
extends: 'lighthouse:default',
188
audits: [CustomPerformanceAudit],
189
categories: {
190
performance: {
191
title: 'Performance',
192
auditRefs: [
193
{id: 'first-contentful-paint', weight: 10},
194
{id: 'custom-performance-audit', weight: 5},
195
],
196
},
197
},
198
};
199
```
200
201
### Gatherer System
202
203
Framework for creating custom data gatherers.
204
205
```javascript { .api }
206
/**
207
* Base class for creating custom gatherers
208
*/
209
class Gatherer {
210
/**
211
* Gatherer metadata
212
*/
213
meta: LH.Gatherer.GathererMeta;
214
215
/**
216
* Start instrumentation for data collection
217
* @param passContext - Gatherer execution context
218
*/
219
startInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
220
221
/**
222
* Start sensitive instrumentation (user interactions, etc.)
223
* @param passContext - Gatherer execution context
224
*/
225
startSensitiveInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
226
227
/**
228
* Stop sensitive instrumentation
229
* @param passContext - Gatherer execution context
230
*/
231
stopSensitiveInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
232
233
/**
234
* Stop instrumentation and finalize data collection
235
* @param passContext - Gatherer execution context
236
*/
237
stopInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
238
239
/**
240
* Get the collected artifact
241
* @param passContext - Gatherer execution context
242
* @returns Collected artifact data
243
*/
244
getArtifact(passContext: LH.Gatherer.Context): LH.Gatherer.PhaseResult;
245
}
246
```
247
248
**Custom Gatherer Example:**
249
250
```javascript
251
import { Gatherer } from 'lighthouse';
252
253
class CustomMetricsGatherer extends Gatherer {
254
constructor() {
255
super();
256
this.meta = {
257
supportedModes: ['navigation', 'timespan', 'snapshot'],
258
};
259
}
260
261
async startInstrumentation(context) {
262
// Initialize data collection
263
this.customData = {};
264
}
265
266
async getArtifact(context) {
267
const {driver} = context;
268
269
// Collect custom metrics using Chrome DevTools Protocol
270
const customMetrics = await driver.executionContext.evaluate(() => {
271
return {
272
customLoadTime: performance.now(),
273
resourceCount: document.querySelectorAll('img, script, link').length,
274
domComplexity: document.querySelectorAll('*').length,
275
};
276
}, {useIsolation: true});
277
278
return customMetrics;
279
}
280
}
281
282
// Configuration with custom gatherer
283
const config = {
284
extends: 'lighthouse:default',
285
passes: [{
286
passName: 'defaultPass',
287
gatherers: ['custom-metrics'],
288
}],
289
gatherers: [{
290
path: CustomMetricsGatherer,
291
options: {},
292
}],
293
};
294
```
295
296
### Plugin System
297
298
Lighthouse supports plugins for packaging custom audits and gatherers.
299
300
```javascript { .api }
301
// Plugin structure
302
interface LH.Plugin {
303
audits: LH.Config.AuditDefn[];
304
groups?: Record<string, LH.Config.Group>;
305
category: LH.Config.Category;
306
}
307
```
308
309
**Plugin Example:**
310
311
```javascript
312
// lighthouse-plugin-custom.js
313
module.exports = {
314
audits: [
315
{path: 'lighthouse-plugin-custom/audits/custom-audit.js'},
316
],
317
groups: {
318
'custom-group': {
319
title: 'Custom Checks',
320
description: 'Custom performance and functionality checks',
321
},
322
},
323
category: {
324
title: 'Custom Category',
325
description: 'Custom audits for specialized requirements',
326
auditRefs: [
327
{id: 'custom-audit', weight: 1, group: 'custom-group'},
328
],
329
},
330
};
331
332
// Configuration using plugin
333
const config = {
334
extends: 'lighthouse:default',
335
plugins: ['lighthouse-plugin-custom'],
336
};
337
```
338
339
### Budget Configuration
340
341
Performance budgets for monitoring resource usage and performance metrics.
342
343
```javascript { .api }
344
interface LH.Budget {
345
path?: string; // URL path pattern
346
resourceSizes?: LH.Budget.ResourceBudget[];
347
resourceCounts?: LH.Budget.ResourceBudget[];
348
timings?: LH.Budget.TimingBudget[];
349
}
350
351
interface LH.Budget.ResourceBudget {
352
resourceType: LH.Budget.ResourceType;
353
budget: number; // Size in bytes or count
354
}
355
356
interface LH.Budget.TimingBudget {
357
metric: LH.Budget.TimingMetric;
358
budget: number; // Time in milliseconds
359
}
360
```
361
362
**Budget Example:**
363
364
```javascript
365
const budgetConfig = {
366
extends: 'lighthouse:default',
367
settings: {
368
budgets: [{
369
path: '/*', // Apply to all pages
370
resourceSizes: [
371
{resourceType: 'script', budget: 500000}, // 500KB JS
372
{resourceType: 'image', budget: 1000000}, // 1MB images
373
{resourceType: 'stylesheet', budget: 100000}, // 100KB CSS
374
],
375
resourceCounts: [
376
{resourceType: 'script', budget: 10}, // Max 10 scripts
377
{resourceType: 'image', budget: 50}, // Max 50 images
378
],
379
timings: [
380
{metric: 'first-contentful-paint', budget: 2000}, // 2s FCP
381
{metric: 'largest-contentful-paint', budget: 4000}, // 4s LCP
382
],
383
}],
384
},
385
};
386
```
387
388
## Advanced Configuration Patterns
389
390
### Environment-Specific Configurations
391
392
```javascript
393
// Development configuration
394
const devConfig = {
395
extends: 'lighthouse:default',
396
settings: {
397
throttlingMethod: 'provided', // No throttling for local dev
398
screenEmulation: {disabled: true}, // Use actual viewport
399
onlyCategories: ['performance'], // Focus on performance
400
},
401
};
402
403
// CI configuration
404
const ciConfig = {
405
extends: 'lighthouse:default',
406
settings: {
407
throttlingMethod: 'simulate', // Consistent throttling
408
maxWaitForLoad: 60000, // Longer timeout for CI
409
output: ['json', 'html'], // Multiple outputs
410
},
411
};
412
413
// Production monitoring configuration
414
const prodConfig = {
415
extends: 'lighthouse:default',
416
settings: {
417
throttlingMethod: 'simulate',
418
throttling: { // Production-like conditions
419
rttMs: 150,
420
throughputKbps: 1638,
421
cpuSlowdownMultiplier: 4,
422
},
423
budgets: [/* performance budgets */],
424
},
425
};
426
```
427
428
### Configuration Validation
429
430
```javascript
431
function validateConfig(config) {
432
const errors = [];
433
434
// Validate required fields
435
if (config.audits && !Array.isArray(config.audits)) {
436
errors.push('config.audits must be an array');
437
}
438
439
// Validate category references
440
if (config.categories) {
441
Object.values(config.categories).forEach(category => {
442
category.auditRefs?.forEach(auditRef => {
443
const auditExists = config.audits?.some(audit =>
444
audit.path?.includes(auditRef.id) || audit === auditRef.id
445
);
446
if (!auditExists) {
447
errors.push(`Audit ${auditRef.id} referenced but not defined`);
448
}
449
});
450
});
451
}
452
453
return errors;
454
}
455
456
// Usage
457
const configErrors = validateConfig(customConfig);
458
if (configErrors.length > 0) {
459
throw new Error(`Configuration errors: ${configErrors.join(', ')}`);
460
}
461
```
462
463
### Dynamic Configuration Generation
464
465
```javascript
466
function createDynamicConfig(options = {}) {
467
const baseConfig = {
468
extends: 'lighthouse:default',
469
settings: {
470
throttlingMethod: options.throttling || 'simulate',
471
},
472
};
473
474
// Add mobile-specific settings
475
if (options.mobile) {
476
baseConfig.settings.screenEmulation = {
477
mobile: true,
478
width: 375,
479
height: 667,
480
deviceScaleFactor: 2,
481
};
482
}
483
484
// Add category filtering
485
if (options.categories) {
486
baseConfig.settings.onlyCategories = options.categories;
487
}
488
489
// Add custom audits
490
if (options.customAudits) {
491
baseConfig.audits = options.customAudits;
492
}
493
494
return baseConfig;
495
}
496
497
// Usage
498
const mobileConfig = createDynamicConfig({
499
mobile: true,
500
categories: ['performance', 'accessibility'],
501
throttling: 'simulate',
502
});
503
```
504
505
## Error Handling and Debugging
506
507
### Configuration Debugging
508
509
```javascript
510
// Debug configuration loading
511
import lighthouse, { defaultConfig } from 'lighthouse';
512
513
console.log('Default config structure:', JSON.stringify(defaultConfig, null, 2));
514
515
try {
516
const result = await lighthouse('https://example.com', {}, customConfig);
517
console.log('Configuration applied successfully');
518
} catch (error) {
519
if (error.code === 'INVALID_CONFIG') {
520
console.error('Configuration error:', error.message);
521
console.error('Config details:', error.details);
522
} else {
523
console.error('Lighthouse error:', error.message);
524
}
525
}
526
```
527
528
### Audit and Gatherer Debugging
529
530
```javascript
531
// Enable debug logging for custom components
532
class DebugAudit extends Audit {
533
static audit(artifacts, context) {
534
console.log('Debug audit running with artifacts:', Object.keys(artifacts));
535
console.log('Audit context:', context);
536
537
try {
538
// Audit logic
539
const result = performAuditLogic(artifacts);
540
console.log('Audit result:', result);
541
return result;
542
} catch (error) {
543
console.error('Audit error:', error);
544
return Audit.generateAuditResult(null, {
545
errorMessage: error.message,
546
});
547
}
548
}
549
}
550
```