lighthouse-audit-utils 1.0.1 → 1.2.3
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/README.md +258 -192
- package/dist/chunk-4DICEJP6.js +510 -0
- package/dist/chunk-4DICEJP6.js.map +1 -0
- package/dist/index.js +1 -194
- package/dist/index.js.map +1 -1
- package/dist/log-recommendations.d.ts +1 -1
- package/dist/playwright.d.ts +60 -0
- package/dist/playwright.js +78 -0
- package/dist/playwright.js.map +1 -0
- package/package.json +25 -2
package/README.md
CHANGED
|
@@ -1,192 +1,258 @@
|
|
|
1
|
-
# lighthouse-audit-utils
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
await
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
await handleAuditResult({ result
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
| `
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- https://example.com/assets/
|
|
133
|
-
- https://example.com/assets/
|
|
134
|
-
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
1
|
+
# lighthouse-audit-utils
|
|
2
|
+
|
|
3
|
+
Programmatic [Lighthouse](https://github.com/GoogleChrome/lighthouse) audit utilities for CI and performance testing: score-threshold checking, HTML/JSON report writing, and a recommendations logger (ie, what is seen in a lighthouse report UI), all from a finished Lighthouse run in one call. Each step can be configured or disabled.
|
|
4
|
+
|
|
5
|
+
Running the audits from Playwright? [`lighthouse-audit-utils/playwright`](#playwright)
|
|
6
|
+
ships the CDP wiring as a fixture, so a test can audit whatever page it's on —
|
|
7
|
+
handy for Lighthouse CI-style performance budgets inside a Playwright suite.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --save-dev lighthouse-audit-utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`lighthouse` is a peer dependency; `@playwright/test` is an optional one, needed
|
|
14
|
+
only if using the [Playwright entrypoint](#playwright).
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
`runAudit` audits a URL and handles the result:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { runAudit } from 'lighthouse-audit-utils'
|
|
22
|
+
|
|
23
|
+
await runAudit({
|
|
24
|
+
lighthouseArgs: {
|
|
25
|
+
url: 'https://example.com',
|
|
26
|
+
flags: { port, output: ['html', 'json'] },
|
|
27
|
+
},
|
|
28
|
+
reports: { directory: 'lighthouse', name: 'desktop' },
|
|
29
|
+
thresholds: { performance: 90 },
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`lighthouseArgs` is handed to `lighthouse()`, in the order it takes them:
|
|
34
|
+
|
|
35
|
+
| Option | Default | Description |
|
|
36
|
+
| -------- | ---------- | ----------------------------------------------------- |
|
|
37
|
+
| `url` | _required_ | The URL to audit |
|
|
38
|
+
| `flags` | _none_ | Settings for the run, e.g. the `port` Lighthouse uses |
|
|
39
|
+
| `config` | _none_ | Overrides the default config, e.g. `desktopConfig` |
|
|
40
|
+
|
|
41
|
+
Everything else it takes is passed straight to `handleAuditResult` below, which returns `{ result, failures }`.
|
|
42
|
+
|
|
43
|
+
## `handleAuditResult`
|
|
44
|
+
|
|
45
|
+
Handles a run you've already made yourself — this is what `runAudit` calls with the result from the actual `lighthouse()` audit:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import lighthouse from 'lighthouse'
|
|
49
|
+
import { handleAuditResult } from 'lighthouse-audit-utils'
|
|
50
|
+
|
|
51
|
+
const result = await lighthouse(url, { port, output: ['html', 'json'] })
|
|
52
|
+
if (!result) throw new Error('Lighthouse returned no result')
|
|
53
|
+
|
|
54
|
+
await handleAuditResult({
|
|
55
|
+
result,
|
|
56
|
+
reports: { directory: 'lighthouse', name: 'desktop' },
|
|
57
|
+
thresholds: { performance: 90 },
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The three steps run in that order — reports, recommendations, thresholds — so a
|
|
62
|
+
failing run still prints its recommendations before throwing.
|
|
63
|
+
|
|
64
|
+
| Option | Default | Description |
|
|
65
|
+
| ----------------- | ---------- | ------------------------------------------------------------ |
|
|
66
|
+
| `result` | _required_ | The full `RunnerResult` from a Lighthouse run |
|
|
67
|
+
| `reports` | _none_ | Where to write the reports; omit to skip writing them |
|
|
68
|
+
| `recommendations` | _none_ | Recommendation logging options, or `false` to skip |
|
|
69
|
+
| `thresholds` | `100` | Minimum scores (0-100) — one number for all, or per category |
|
|
70
|
+
| `ignoreError` | `false` | Return the threshold failures rather than throwing on them |
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// just the log
|
|
74
|
+
await handleAuditResult({ result, ignoreError: true })
|
|
75
|
+
|
|
76
|
+
// just the thresholds
|
|
77
|
+
await handleAuditResult({ result, recommendations: false })
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `reports`
|
|
81
|
+
|
|
82
|
+
| Option | Default | Description |
|
|
83
|
+
| ----------- | ---------- | -------------------------------------------------------------- |
|
|
84
|
+
| `directory` | _required_ | Directory to write into; created if it doesn't exist |
|
|
85
|
+
| `name` | _required_ | Base filename, e.g. `desktop` → `desktop.html`, `desktop.json` |
|
|
86
|
+
|
|
87
|
+
Each report is written to `<directory>/<name>.<format>`, using the formats the
|
|
88
|
+
run's `output` flag asked for.
|
|
89
|
+
|
|
90
|
+
### `thresholds`
|
|
91
|
+
|
|
92
|
+
One number applies to every category; an object sets them individually. Any
|
|
93
|
+
category you leave out has to score 100, so the strict case is the default:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
await handleAuditResult({ result }) // every category must score 100
|
|
97
|
+
await handleAuditResult({ result, thresholds: 90 })
|
|
98
|
+
await handleAuditResult({ result, thresholds: { performance: 90 } })
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Only the categories present that are scored in the lighthouse report are checked.
|
|
102
|
+
|
|
103
|
+
### `ignoreError`
|
|
104
|
+
|
|
105
|
+
Returns the threshold failures instead of throwing an error, so you can decide what to do with
|
|
106
|
+
them. `undefined` when everything passed.
|
|
107
|
+
|
|
108
|
+
### `recommendations`
|
|
109
|
+
|
|
110
|
+
| Option | Default | Description |
|
|
111
|
+
| ---------------- | -------------- | -------------------------------------------------------------- |
|
|
112
|
+
| `label` | `reports.name` | Distinguishes runs of the same URL, e.g. `desktop`/`mobile` |
|
|
113
|
+
| `maxItems` | `5` | Rows shown per audit before collapsing to "…and N more" |
|
|
114
|
+
| `maxValueLength` | `120` | Max length of a single value before it's truncated with an "…" |
|
|
115
|
+
|
|
116
|
+
Pass `recommendations: false` to skip the log entirely.
|
|
117
|
+
|
|
118
|
+
#### Output
|
|
119
|
+
|
|
120
|
+
The log is the same recommendations the report UI shows — failing audits, their
|
|
121
|
+
estimated savings, and the individual offending URLs/nodes — so a failing CI run
|
|
122
|
+
is actionable without downloading and opening the HTML report. Audits are
|
|
123
|
+
grouped by category and sorted by estimated savings, so the biggest wins come
|
|
124
|
+
first:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
───── Lighthouse recommendations: desktop — https://example.com/ ─────
|
|
128
|
+
|
|
129
|
+
Performance: 87
|
|
130
|
+
• Reduce unused JavaScript (Est savings of 1,010 KiB)
|
|
131
|
+
unused-javascript · score 50
|
|
132
|
+
- https://example.com/assets/vendor.css · Transfer Size: 24.1 KiB
|
|
133
|
+
- https://example.com/assets/fonts.css · Transfer Size: 7.3 KiB
|
|
134
|
+
- https://example.com/assets/dep-vendor-1.js · Transfer Size: 372 KiB · Est Savings: 343 KiB
|
|
135
|
+
- https://example.com/assets/dep-vendor-2.js · Transfer Size: 176 KiB · Est Savings: 149 KiB
|
|
136
|
+
- …and 2 more
|
|
137
|
+
• Properly size images (Potential savings of 96 KiB)
|
|
138
|
+
uses-responsive-images · score 62
|
|
139
|
+
- https://example.com/hero.png · Size: 142 KiB
|
|
140
|
+
- …and 3 more
|
|
141
|
+
• Render-blocking requests — est. savings: FCP 310 ms, LCP 310 ms
|
|
142
|
+
render-blocking-insight · score 50
|
|
143
|
+
- https://example.com/assets/index.css · Transfer Size: 12.4 KiB · Duration: 52 ms
|
|
144
|
+
|
|
145
|
+
Accessibility: 100 — nothing to flag
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Individual utilities
|
|
149
|
+
|
|
150
|
+
The three steps are also exported on their own, each taking the report first and
|
|
151
|
+
its options second:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
writeReports(result, { directory, name })
|
|
155
|
+
logRecommendations(lhr, { label, maxItems, maxValueLength })
|
|
156
|
+
checkAgainstThresholds(lhr, { thresholds, ignoreError })
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Playwright
|
|
160
|
+
|
|
161
|
+
`lighthouse-audit-utils/playwright` ships the wiring as a fixture.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// fixtures.ts
|
|
165
|
+
import { desktopConfig } from 'lighthouse'
|
|
166
|
+
import { withLighthouse } from 'lighthouse-audit-utils/playwright'
|
|
167
|
+
|
|
168
|
+
export const lighthouseTest = withLighthouse({
|
|
169
|
+
basePort: 9222,
|
|
170
|
+
lighthouseArgs: {
|
|
171
|
+
flags: { disableStorageReset: true, output: ['html', 'json'] },
|
|
172
|
+
config: {
|
|
173
|
+
extends: 'lighthouse:default',
|
|
174
|
+
settings: { skipAudits: ['color-contrast'] },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
thresholds: { performance: 70 },
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// a.spec.ts
|
|
181
|
+
lighthouseTest('home page', async ({ page, runAudit }) => {
|
|
182
|
+
await page.goto('/')
|
|
183
|
+
await runAudit({
|
|
184
|
+
name: 'desktop',
|
|
185
|
+
lighthouseArgs: { config: desktopConfig },
|
|
186
|
+
})
|
|
187
|
+
await runAudit({ name: 'mobile', thresholds: { performance: 60 } }) // merges over the fixture's value
|
|
188
|
+
})
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- Each call to `runAudit` audits whatever page the test is currently on and writes its reports to the test's output directory.
|
|
192
|
+
- Run `runAudit` more than once for more than one form factor
|
|
193
|
+
— wrap the calls in `test.step` if you want them grouped in the report.
|
|
194
|
+
- `withLighthouse(options, test)` takes the test to extend second, so you can layer
|
|
195
|
+
it onto your own fixtures; omit it to start from Playwright's `test`.
|
|
196
|
+
|
|
197
|
+
| Option | Required | Description |
|
|
198
|
+
| ---------------- | -------- | ---------------------------------------------------------------------------------------- |
|
|
199
|
+
| `basePort` | yes | First worker's CDP port; each further worker gets the next one up |
|
|
200
|
+
| `lighthouseArgs` | no | `flags` and `config` for `lighthouse()`; `url` and `flags.port` are set for you |
|
|
201
|
+
| `reports` | no | `(context) => { directory, name }`, or `false` to skip writing them |
|
|
202
|
+
| `launchOptions` | no | Merged into the persistent context launch, which already sets the CDP port and `baseURL` |
|
|
203
|
+
|
|
204
|
+
Plus everything [`runAudit`](#usage) from `lighthouse-audit-utils` takes —
|
|
205
|
+
`thresholds`, `ignoreError`, `recommendations`.
|
|
206
|
+
|
|
207
|
+
The `runAudit` fixture takes `name` — which names that run's reports, so two
|
|
208
|
+
audits in one test don't overwrite each other — and `lighthouseArgs`,
|
|
209
|
+
`thresholds`, `ignoreError` and `recommendations`, to overwrite the overall fixture's:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const { result, failures } = await runAudit({
|
|
213
|
+
name: 'logged-in',
|
|
214
|
+
thresholds: { performance: 50 },
|
|
215
|
+
lighthouseArgs: { config: { settings: { onlyCategories: ['performance'] } } },
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`thresholds` merge when both are objects; anything else replaces, since a flat
|
|
220
|
+
number can't be partially overridden.
|
|
221
|
+
|
|
222
|
+
`context` is overridden to launch a persistent Chrome profile on the CDP port,
|
|
223
|
+
since Lighthouse navigates over that port itself rather than driving the
|
|
224
|
+
Playwright `page` — this way both see the same browser session.
|
|
225
|
+
|
|
226
|
+
### Doing it by hand
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { desktopConfig } from 'lighthouse'
|
|
230
|
+
import { runAudit } from 'lighthouse-audit-utils'
|
|
231
|
+
|
|
232
|
+
await runAudit({
|
|
233
|
+
lighthouseArgs: {
|
|
234
|
+
url: page.url(),
|
|
235
|
+
flags: { port, output: ['html', 'json'] },
|
|
236
|
+
config: desktopConfig,
|
|
237
|
+
},
|
|
238
|
+
reports: { directory: testInfo.outputPath('lighthouse'), name: 'desktop' },
|
|
239
|
+
thresholds: { performance: 90 },
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
pnpm install
|
|
247
|
+
pnpm build # tsup → dist/ (types via tsc)
|
|
248
|
+
pnpm start # tsup watch
|
|
249
|
+
pnpm check # biome + tsc
|
|
250
|
+
pnpm format # biome check --fix
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
CI type-checks and builds against both supported peer majors, Lighthouse 12 and
|
|
254
|
+
13, on Node 22/24/26.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT
|