webperf-snippets 1.3.0 → 1.5.0
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 +67 -6
- package/package.json +3 -2
- package/snippets/CoreWebVitals/CLS.js +3 -2
- package/snippets/CoreWebVitals/LCP-Image-Entropy.js +8 -9
- package/snippets/CoreWebVitals/LCP-Subparts.js +32 -35
- package/snippets/CoreWebVitals/LCP-Video-Candidate.js +14 -13
- package/snippets/Interaction/DOM-Size-and-Depth.js +4 -0
- package/snippets/Interaction/Forced-Synchronous-Layout.js +2 -0
- package/snippets/Interaction/Input-Latency-Breakdown.js +2 -0
- package/snippets/Interaction/Interactions.js +2 -0
- package/snippets/Interaction/Scroll-Performance.js +2 -0
- package/snippets/Loading/Back-Forward-Cache.js +7 -0
- package/snippets/Loading/CSS-Media-Queries-Analysis.js +4 -2
- package/snippets/Loading/Cache-Strategy-Analysis.js +12 -0
- package/snippets/Loading/Client-Side-Redirect-Detection.js +5 -3
- package/snippets/Loading/Compression-Audit.js +3 -0
- package/snippets/Loading/Content-Visibility.js +2 -2
- package/snippets/Loading/Critical-CSS-Detection.js +6 -0
- package/snippets/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.js +2 -2
- package/snippets/Loading/Find-Images-With-Lazy-and-Fetchpriority.js +1 -1
- package/snippets/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.js +1 -1
- package/snippets/Loading/Find-render-blocking-resources.js +1 -1
- package/snippets/Loading/First-And-Third-Party-Script-Info.js +5 -2
- package/snippets/Loading/First-And-Third-Party-Script-Timings.js +4 -4
- package/snippets/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.js +3 -3
- package/snippets/Loading/Inline-CSS-Info-and-Size.js +5 -1
- package/snippets/Loading/Inline-Script-Info-and-Size.js +5 -1
- package/snippets/Loading/JS-Execution-Time-Breakdown.js +4 -4
- package/snippets/Loading/Prefetch-Resource-Validation.js +12 -3
- package/snippets/Loading/Priority-Hints-Audit.js +10 -0
- package/snippets/Loading/Resource-Hints-Validation.js +3 -3
- package/snippets/Loading/Resource-Hints.js +7 -1
- package/snippets/Loading/SSR-Hydration-Data-Analysis.js +5 -2
- package/snippets/Loading/Script-Loading.js +6 -2
- package/snippets/Loading/Server-Timing-Early-Hints.js +3 -0
- package/snippets/Loading/Service-Worker-Analysis.js +12 -2
- package/snippets/Loading/Speculation-Rules-Inspector.js +7 -4
- package/snippets/Loading/TTFB-Resources.js +1 -1
- package/snippets/Loading/TTFB-Sub-Parts.js +1 -0
- package/snippets/Loading/Third-Party-Impact-by-Domain.js +6 -0
- package/snippets/Loading/Validate-Preload-Async-Defer-Scripts.js +5 -0
- package/snippets/Loading/Webfont-Usage-Analyzer.js +13 -14
- package/snippets/Media/Image-Element-Audit.js +16 -13
- package/snippets/Media/Oversized-Images.js +4 -0
- package/snippets/Media/SVG-Embedded-Bitmap-Analysis.js +2 -1
- package/snippets/Media/Video-Element-Audit.js +13 -2
- package/snippets/SCHEMA.md +425 -3
- package/src/baseline.js +225 -0
- package/src/bin.js +68 -7
- package/src/blocking.js +3 -1
- package/src/conditions.js +7 -0
- package/src/mcp/documents.js +41 -21
- package/src/reporters/baseline-view.js +83 -0
- package/src/reporters/human.js +43 -5
- package/src/reporters/markdown.js +46 -6
- package/src/reporters/matrix-view.js +8 -2
package/snippets/SCHEMA.md
CHANGED
|
@@ -53,8 +53,10 @@ Every script must return an object matching this shape:
|
|
|
53
53
|
|
|
54
54
|
// Issues detected (for audit scripts)
|
|
55
55
|
issues?: Array<{
|
|
56
|
+
code: string; // What the issue is, kebab-case, stable across runs and versions (see Issue codes)
|
|
56
57
|
severity: "error" | "warning" | "info";
|
|
57
58
|
message: string;
|
|
59
|
+
target?: string; // The URL, selector or name the issue is about, when there is one issue per thing
|
|
58
60
|
}>;
|
|
59
61
|
|
|
60
62
|
// Tracking scripts (status: "tracking")
|
|
@@ -505,8 +507,8 @@ When the rating is not good, `issues` holds one entry that names the TTFB and th
|
|
|
505
507
|
}
|
|
506
508
|
],
|
|
507
509
|
"issues": [
|
|
508
|
-
{ "severity": "error", "message": "2 blocking
|
|
509
|
-
{ "severity": "error", "message": "1 third-party blocking script" }
|
|
510
|
+
{ "code": "blocking-in-head", "severity": "error", "message": "2 blocking script(s) in <head>" },
|
|
511
|
+
{ "code": "third-party-blocking", "severity": "error", "message": "1 third-party blocking script(s)" }
|
|
510
512
|
]
|
|
511
513
|
}
|
|
512
514
|
```
|
|
@@ -1189,6 +1191,424 @@ Same shape as Image-Element-Audit but for video elements.
|
|
|
1189
1191
|
|
|
1190
1192
|
---
|
|
1191
1193
|
|
|
1194
|
+
## Issue codes
|
|
1195
|
+
|
|
1196
|
+
Every issue has a `code` that says what it is, so a comparison pairs the issues of two runs without reading their text: the message carries figures, and its wording can change from a version to the next. The code is kebab-case and unique within its snippet, so `script` and `code` together name an issue across the collection. A code never changes once published, and is never reused for another situation. The same situation keeps its code when its severity depends on a threshold.
|
|
1197
|
+
|
|
1198
|
+
An issue about one thing among several, one issue per thing, also names it in `target`: the URL of a resource, a CSS selector, or a name such as an event type or a CSS property. Two issues with the same code and different targets are two issues.
|
|
1199
|
+
|
|
1200
|
+
### LCP-Image-Entropy
|
|
1201
|
+
|
|
1202
|
+
| Code | Severity | When |
|
|
1203
|
+
|------|----------|------|
|
|
1204
|
+
| `low-entropy-images` | warning | Images under 0.05 bits per pixel, which Chrome does not take as the LCP |
|
|
1205
|
+
| `lcp-low-entropy` | error | The LCP image itself has low entropy |
|
|
1206
|
+
| `lcp-size-unknown` | info | The LCP `<img>` has no file size to read (a `data:` URL, or cross-origin without `Timing-Allow-Origin`) |
|
|
1207
|
+
| `lcp-not-img` | info | The LCP is the image of another element, such as a CSS background or a video poster |
|
|
1208
|
+
| `lcp-is-text` | info | The LCP element is text |
|
|
1209
|
+
|
|
1210
|
+
### LCP-Video-Candidate
|
|
1211
|
+
|
|
1212
|
+
| Code | Severity | When |
|
|
1213
|
+
|------|----------|------|
|
|
1214
|
+
| `lcp-not-video` | info | The LCP element is not a `<video>` |
|
|
1215
|
+
| `lcp-element-removed` | info | The LCP element is no longer in the DOM |
|
|
1216
|
+
| `late-candidate` | warning | The LCP candidate rendered more than 10 s after the load |
|
|
1217
|
+
| `first-frame-lcp` | info | The LCP is the first frame of the video, without a poster |
|
|
1218
|
+
| `first-frame-not-autoplay-muted` | warning | A first-frame LCP on a video without `autoplay` and `muted` |
|
|
1219
|
+
| `poster-not-preloaded` | warning | The poster has no `<link rel="preload" as="image">` |
|
|
1220
|
+
| `poster-preload-no-fetchpriority` | info | The preload of the poster has no `fetchpriority="high"` |
|
|
1221
|
+
| `poster-legacy-format` | info | The poster is not AVIF or WebP |
|
|
1222
|
+
| `render-time-hidden` | info | `renderTime` is 0: the video is cross-origin without `Timing-Allow-Origin` |
|
|
1223
|
+
| `preload-none-delays-poster` | warning | `preload="none"` on a video without `autoplay` |
|
|
1224
|
+
|
|
1225
|
+
### Script-Loading
|
|
1226
|
+
|
|
1227
|
+
| Code | Severity | When |
|
|
1228
|
+
|------|----------|------|
|
|
1229
|
+
| `blocking-in-head` | error | Classic scripts without `async`, `defer` or `type="module"` in `<head>` |
|
|
1230
|
+
| `third-party-blocking` | error | Blocking scripts from a third party |
|
|
1231
|
+
| `large-blocking` | warning | Blocking scripts larger than 50 KB |
|
|
1232
|
+
| `could-defer` | info | Blocking scripts other than the last three of `<body>`, which could try `defer` |
|
|
1233
|
+
| `unknown-size` | info | Scripts whose size is hidden by a missing `Timing-Allow-Origin`, so the total is a lower bound |
|
|
1234
|
+
|
|
1235
|
+
### CSS-Media-Queries-Analysis
|
|
1236
|
+
|
|
1237
|
+
| Code | Severity | When |
|
|
1238
|
+
|------|----------|------|
|
|
1239
|
+
| `no-wide-rules` | info | No `@media` rules for viewports wider than the breakpoint (768 px by default) |
|
|
1240
|
+
| `wide-rules` | info or warning | `@media` rules for wider viewports that narrower screens download without using, a warning above 50 KB |
|
|
1241
|
+
| `repeated-queries` | info | Few distinct queries repeated across many `@media` blocks |
|
|
1242
|
+
| `unreadable-stylesheets` | info | Cross-origin stylesheets whose rules cannot be read |
|
|
1243
|
+
|
|
1244
|
+
### Content-Visibility
|
|
1245
|
+
|
|
1246
|
+
| Code | Severity | When |
|
|
1247
|
+
|------|----------|------|
|
|
1248
|
+
| `missing-intrinsic-size` | warning | An element with `content-visibility: auto` and no `contain-intrinsic-size`; `target` is its selector |
|
|
1249
|
+
| `not-used` | info | No `content-visibility` on the page |
|
|
1250
|
+
|
|
1251
|
+
### Critical-CSS-Detection
|
|
1252
|
+
|
|
1253
|
+
| Code | Severity | When |
|
|
1254
|
+
|------|----------|------|
|
|
1255
|
+
| `no-inline-critical-css` | error | Render-blocking stylesheets and no inline critical CSS |
|
|
1256
|
+
| `render-blocking-over-budget` | error | Render-blocking CSS above the 14 KB critical budget |
|
|
1257
|
+
| `large-not-preloaded` | warning | Render-blocking stylesheets above 10 KB without preload |
|
|
1258
|
+
| `inline-over-budget` | error | Inline CSS above the 14 KB critical budget |
|
|
1259
|
+
| `styles-in-body` | warning | Inline style blocks in `<body>` |
|
|
1260
|
+
|
|
1261
|
+
### Find-Above-The-Fold-Lazy-Loaded-Images
|
|
1262
|
+
|
|
1263
|
+
| Code | Severity | When |
|
|
1264
|
+
|------|----------|------|
|
|
1265
|
+
| `lcp-lazy` | error | The LCP candidate image has `loading="lazy"` |
|
|
1266
|
+
| `lazy-above-fold` | warning | Other images above the fold with `loading="lazy"` |
|
|
1267
|
+
|
|
1268
|
+
### Find-Images-With-Lazy-and-Fetchpriority
|
|
1269
|
+
|
|
1270
|
+
| Code | Severity | When |
|
|
1271
|
+
|------|----------|------|
|
|
1272
|
+
| `lazy-and-high-priority` | error | Elements with both `loading="lazy"` and `fetchpriority="high"` |
|
|
1273
|
+
|
|
1274
|
+
### Find-non-Lazy-Loaded-Images-outside-of-the-viewport
|
|
1275
|
+
|
|
1276
|
+
| Code | Severity | When |
|
|
1277
|
+
|------|----------|------|
|
|
1278
|
+
| `eager-off-viewport` | warning | Images outside the viewport without `loading="lazy"` |
|
|
1279
|
+
|
|
1280
|
+
### Find-render-blocking-resources
|
|
1281
|
+
|
|
1282
|
+
| Code | Severity | When |
|
|
1283
|
+
|------|----------|------|
|
|
1284
|
+
| `render-blocking` | error | Resources that block rendering |
|
|
1285
|
+
|
|
1286
|
+
### Fonts-Preloaded-Loaded-and-used-above-the-fold
|
|
1287
|
+
|
|
1288
|
+
Each issue names its font in `target`.
|
|
1289
|
+
|
|
1290
|
+
| Code | Severity | When |
|
|
1291
|
+
|------|----------|------|
|
|
1292
|
+
| `preloaded-unused` | warning | A preloaded font that the content above the fold does not use |
|
|
1293
|
+
| `used-not-preloaded` | warning | A font used above the fold without preload |
|
|
1294
|
+
| `preload-no-crossorigin` | error | A font preload without `crossorigin`, which fetches the font twice |
|
|
1295
|
+
|
|
1296
|
+
### Inline-CSS-Info-and-Size
|
|
1297
|
+
|
|
1298
|
+
| Code | Severity | When |
|
|
1299
|
+
|------|----------|------|
|
|
1300
|
+
| `over-budget` | warning | Inline CSS above the 14 KB critical budget |
|
|
1301
|
+
| `duplicate-blocks` | warning | Style blocks with identical content |
|
|
1302
|
+
| `large-blocks` | warning | Style blocks above 5 KB |
|
|
1303
|
+
| `styles-in-body` | warning | Style blocks in `<body>` |
|
|
1304
|
+
|
|
1305
|
+
### Webfont-Usage-Analyzer
|
|
1306
|
+
|
|
1307
|
+
`load-failed`, `loaded-unused` and `redeclared` name the font file by its URL in `target`, or the face when it has none.
|
|
1308
|
+
|
|
1309
|
+
| Code | Severity | When |
|
|
1310
|
+
|------|----------|------|
|
|
1311
|
+
| `load-failed` | error | A font that failed to load |
|
|
1312
|
+
| `loaded-unused` | warning | A loaded font that no rendered element uses |
|
|
1313
|
+
| `redeclared` | warning | A loaded font declared again later with the same descriptors, so the page uses the other file |
|
|
1314
|
+
| `blocking-font-display` | warning | Faces with `font-display` `auto` or `block`, which can keep text invisible |
|
|
1315
|
+
| `heavy-fonts` | warning | Web fonts above 300 KB in total |
|
|
1316
|
+
| `never-loaded` | info | Faces declared and never loaded |
|
|
1317
|
+
| `shadowed` | info | Faces declared more than once, whose earlier declarations never loaded |
|
|
1318
|
+
| `unused-subsets` | info | `unicode-range` subsets the page did not need |
|
|
1319
|
+
| `size-unknown` | info | Cross-origin font files without `Timing-Allow-Origin`, so the byte totals are a lower bound |
|
|
1320
|
+
| `unreadable-stylesheets` | info | Cross-origin stylesheets whose font files cannot be matched to faces |
|
|
1321
|
+
| `elements-capped` | info | Only the first 20,000 elements were scanned for text |
|
|
1322
|
+
|
|
1323
|
+
### First-And-Third-Party-Script-Info
|
|
1324
|
+
|
|
1325
|
+
| Code | Severity | When |
|
|
1326
|
+
|------|----------|------|
|
|
1327
|
+
| `unknown-size` | info | Scripts whose size is hidden by a missing `Timing-Allow-Origin`, so the totals are a lower bound |
|
|
1328
|
+
| `render-blocking-unsupported` | info | The browser has no `renderBlockingStatus` (only Chromium has it) |
|
|
1329
|
+
| `third-party-blocking` | error | Third-party scripts that block rendering |
|
|
1330
|
+
| `many-third-party-hosts` | warning | Scripts from more than 3 third-party hosts |
|
|
1331
|
+
| `large-third-party` | warning | Third-party scripts above 100 KB in total |
|
|
1332
|
+
|
|
1333
|
+
### First-And-Third-Party-Script-Timings
|
|
1334
|
+
|
|
1335
|
+
| Code | Severity | When |
|
|
1336
|
+
|------|----------|------|
|
|
1337
|
+
| `slow-scripts` | warning | Scripts that take more than 500 ms to load |
|
|
1338
|
+
| `slow-dns` | warning | A DNS lookup above 100 ms |
|
|
1339
|
+
| `slow-connection` | warning | A TCP connection above 100 ms |
|
|
1340
|
+
| `slow-server` | warning | A server response above 200 ms |
|
|
1341
|
+
|
|
1342
|
+
### Inline-Script-Info-and-Size
|
|
1343
|
+
|
|
1344
|
+
| Code | Severity | When |
|
|
1345
|
+
|------|----------|------|
|
|
1346
|
+
| `parser-blocking-in-head` | error | Inline scripts in `<head>` that block the parser |
|
|
1347
|
+
| `large-inline` | warning | Inline scripts above 2 KB |
|
|
1348
|
+
| `duplicate-scripts` | warning | Inline scripts with identical content |
|
|
1349
|
+
| `analytics-in-head` | warning | Analytics scripts that block in `<head>` |
|
|
1350
|
+
|
|
1351
|
+
### JS-Execution-Time-Breakdown
|
|
1352
|
+
|
|
1353
|
+
| Code | Severity | When |
|
|
1354
|
+
|------|----------|------|
|
|
1355
|
+
| `render-blocking` | error | Scripts that block HTML parsing |
|
|
1356
|
+
| `high-parse-cost` | warning | An estimated parse cost above 500 ms on mobile |
|
|
1357
|
+
| `split-candidates` | warning | Scripts above 50 KB decoded, candidates for code splitting |
|
|
1358
|
+
| `low-compression` | warning | A compression ratio below 2x on more than 10 KB of scripts |
|
|
1359
|
+
|
|
1360
|
+
### SSR-Hydration-Data-Analysis
|
|
1361
|
+
|
|
1362
|
+
| Code | Severity | When |
|
|
1363
|
+
|------|----------|------|
|
|
1364
|
+
| `large-hydration-data` | warning | The hydration data of a framework above its threshold; `target` is the framework |
|
|
1365
|
+
| `large-arrays` | warning | `pageProps` arrays with more than 50 entries |
|
|
1366
|
+
| `deep-nesting` | warning | `pageProps` nested more than 5 levels |
|
|
1367
|
+
| `sensitive-keys` | warning | `pageProps` keys that look sensitive |
|
|
1368
|
+
|
|
1369
|
+
### Third-Party-Impact-by-Domain
|
|
1370
|
+
|
|
1371
|
+
| Code | Severity | When |
|
|
1372
|
+
|------|----------|------|
|
|
1373
|
+
| `render-blocking-domains` | warning | Third-party domains that serve render-blocking resources |
|
|
1374
|
+
| `heavy-domain` | warning | A domain whose scripts take more than 250 ms in long animation frames; `target` is the domain |
|
|
1375
|
+
| `render-blocking-unsupported` | info | The browser has no `renderBlockingStatus` (only Chromium has it) |
|
|
1376
|
+
| `loaf-unattributed` | info | Long animation frames with no third-party script attributed |
|
|
1377
|
+
| `unknown-size` | info | Third-party requests without `Timing-Allow-Origin`, so the transfer size is a lower bound |
|
|
1378
|
+
|
|
1379
|
+
### Validate-Preload-Async-Defer-Scripts
|
|
1380
|
+
|
|
1381
|
+
Each issue names the preloaded script in `target`.
|
|
1382
|
+
|
|
1383
|
+
| Code | Severity | When |
|
|
1384
|
+
|------|----------|------|
|
|
1385
|
+
| `orphan-preload` | warning | A preloaded script that the page neither has nor loaded |
|
|
1386
|
+
| `async-defer-preload` | error | A script with `async` or `defer` that is also preloaded, which raises its priority |
|
|
1387
|
+
| `module-preload` | warning | An ES module preloaded with `rel="preload"` instead of `rel="modulepreload"` |
|
|
1388
|
+
|
|
1389
|
+
### Back-Forward-Cache
|
|
1390
|
+
|
|
1391
|
+
| Code | Severity | When |
|
|
1392
|
+
|------|----------|------|
|
|
1393
|
+
| `not-restored` | error | A reason the browser gave for not restoring the page from bfcache, after a back or forward navigation; `target` is the reason and its frame |
|
|
1394
|
+
| `unload-handler` | error | A `window.onunload` handler |
|
|
1395
|
+
| `cache-control-no-store` | warning | `Cache-Control: no-store` on the page response |
|
|
1396
|
+
| `iframes` | info | Iframes on the page, whose blockers block the whole page |
|
|
1397
|
+
| `service-worker` | info | A Service Worker controls the page, which bfcache allows |
|
|
1398
|
+
|
|
1399
|
+
### Cache-Strategy-Analysis
|
|
1400
|
+
|
|
1401
|
+
Each issue names its resource in `target`, except `header-coverage`. `id` repeats the code, as before the codes.
|
|
1402
|
+
|
|
1403
|
+
| Code | Severity | When |
|
|
1404
|
+
|------|----------|------|
|
|
1405
|
+
| `static-no-store` | error | A static asset with `no-store` |
|
|
1406
|
+
| `versioned-short-cache` | warning | A URL with a hash and a short `max-age` |
|
|
1407
|
+
| `versioned-not-immutable` | info | A URL with a hash and no `immutable` |
|
|
1408
|
+
| `large-no-cache` | error | A large resource with no effective cache |
|
|
1409
|
+
| `expires-without-cc` | warning | An `Expires` header without `Cache-Control` |
|
|
1410
|
+
| `maxage-zero-static` | warning | A static asset with `max-age=0` |
|
|
1411
|
+
| `short-cache-static` | warning | A static asset with a `max-age` under an hour |
|
|
1412
|
+
| `uncompressed` | warning | A text resource sent uncompressed |
|
|
1413
|
+
| `duplicate-uncached` | warning | A resource loaded several times from the network |
|
|
1414
|
+
| `header-coverage` | info | The share of resources whose cache headers could be read |
|
|
1415
|
+
|
|
1416
|
+
### Client-Side-Redirect-Detection
|
|
1417
|
+
|
|
1418
|
+
| Code | Severity | When |
|
|
1419
|
+
|------|----------|------|
|
|
1420
|
+
| `server-redirects` | warning | Server-side redirects before the document |
|
|
1421
|
+
| `document-navigation` | error | Same-origin document navigations, likely a client-side redirect |
|
|
1422
|
+
| `same-origin-navigation` | warning | A same-origin referrer with another path |
|
|
1423
|
+
| `fast-minimal-navigation` | warning | A small same-origin page that loads fast, possibly a redirect page |
|
|
1424
|
+
|
|
1425
|
+
### Compression-Audit
|
|
1426
|
+
|
|
1427
|
+
| Code | Severity | When |
|
|
1428
|
+
|------|----------|------|
|
|
1429
|
+
| `uncompressed` | warning | Text resources served without compression |
|
|
1430
|
+
| `unknown-size` | info | Cross-origin text resources without `Timing-Allow-Origin`, whose compression is unknown |
|
|
1431
|
+
| `content-encoding-unavailable` | info | No `contentEncoding` in Resource Timing, so compression is inferred from the sizes |
|
|
1432
|
+
|
|
1433
|
+
### Prefetch-Resource-Validation
|
|
1434
|
+
|
|
1435
|
+
Each issue about one prefetch names its URL in `target`.
|
|
1436
|
+
|
|
1437
|
+
| Code | Severity | When |
|
|
1438
|
+
|------|----------|------|
|
|
1439
|
+
| `no-prefetch` | info | No `rel="prefetch"` hints on the page |
|
|
1440
|
+
| `missing-as` | warning | A prefetch without `as` |
|
|
1441
|
+
| `invalid-as` | warning | A prefetch with an `as` value that does not exist |
|
|
1442
|
+
| `duplicate-prefetch` | warning | A URL prefetched more than once |
|
|
1443
|
+
| `used-on-current-page` | error | A prefetched resource that the current page uses, which needs `preload` |
|
|
1444
|
+
| `large-file` | warning | A prefetched file above 500 KB |
|
|
1445
|
+
| `inappropriate-type` | warning | A prefetched type that may not suit prefetch |
|
|
1446
|
+
| `too-many-prefetches` | warning | More than 10 prefetch hints |
|
|
1447
|
+
| `large-total-size` | warning or error | Prefetches above 2 MB in total, an error above 5 MB |
|
|
1448
|
+
|
|
1449
|
+
### Priority-Hints-Audit
|
|
1450
|
+
|
|
1451
|
+
Each issue names its resource in `target`.
|
|
1452
|
+
|
|
1453
|
+
| Code | Severity | When |
|
|
1454
|
+
|------|----------|------|
|
|
1455
|
+
| `preload-low-priority` | error | A preload with `fetchpriority="low"` |
|
|
1456
|
+
| `low-priority-loaded-early` | warning | A `fetchpriority="low"` resource that still loaded early |
|
|
1457
|
+
| `high-priority-loaded-late` | warning | A `fetchpriority="high"` resource that still loaded late |
|
|
1458
|
+
| `lcp-no-fetchpriority` | warning | The LCP candidate image without `fetchpriority="high"` |
|
|
1459
|
+
|
|
1460
|
+
### Resource-Hints
|
|
1461
|
+
|
|
1462
|
+
Each issue about one hint names its URL in `target`.
|
|
1463
|
+
|
|
1464
|
+
| Code | Severity | When |
|
|
1465
|
+
|------|----------|------|
|
|
1466
|
+
| `preload-missing-as` | error | A preload without `as` |
|
|
1467
|
+
| `font-preload-no-crossorigin` | error | A font preload without `crossorigin`, which fetches the font twice |
|
|
1468
|
+
| `preconnect-no-crossorigin` | warning | A preconnect without `crossorigin` to an origin that serves CORS resources |
|
|
1469
|
+
| `unused-preload` | warning | A preload that the page did not use during the load |
|
|
1470
|
+
| `unused-preconnect` | warning | A preconnect to an origin the page loaded nothing from |
|
|
1471
|
+
| `too-many-preloads` | warning | More than 6 preloads |
|
|
1472
|
+
|
|
1473
|
+
### Resource-Hints-Validation
|
|
1474
|
+
|
|
1475
|
+
| Code | Severity | When |
|
|
1476
|
+
|------|----------|------|
|
|
1477
|
+
| `unused-hints` | warning | Hints the page did not use |
|
|
1478
|
+
| `missing-connection-hints` | info | Domains that could use a connection hint |
|
|
1479
|
+
| `redundant-hints` | warning | Domains with both `preconnect` and `dns-prefetch` |
|
|
1480
|
+
|
|
1481
|
+
### Server-Timing-Early-Hints
|
|
1482
|
+
|
|
1483
|
+
| Code | Severity | When |
|
|
1484
|
+
|------|----------|------|
|
|
1485
|
+
| `no-server-timing` | info | The document response has no `Server-Timing` header |
|
|
1486
|
+
| `timing-hidden` | info | Cross-origin resources without `Timing-Allow-Origin`, whose Server-Timing cannot be read |
|
|
1487
|
+
| `no-early-hints` | info | No 103 Early Hints response for the document |
|
|
1488
|
+
|
|
1489
|
+
### Service-Worker-Analysis
|
|
1490
|
+
|
|
1491
|
+
| Code | Severity | When |
|
|
1492
|
+
|------|----------|------|
|
|
1493
|
+
| `unsupported` | error | The browser has no Service Workers |
|
|
1494
|
+
| `no-service-worker` | info | No Service Worker registered |
|
|
1495
|
+
| `not-controlled` | warning | The page is not controlled by its Service Worker, after a hard reload or on a first visit |
|
|
1496
|
+
| `update-pending` | warning | A waiting update; `target` is the scope |
|
|
1497
|
+
| `navigation-preload-disabled` | info | Navigation Preload is off; `target` is the scope |
|
|
1498
|
+
| `slow-startup` | warning or error | A Service Worker startup above 50 ms, an error above 100 ms |
|
|
1499
|
+
| `low-cache-hit-rate` | warning or error | A cache hit rate under 80%, an error under 50% |
|
|
1500
|
+
| `unknown-source` | info | Intercepted cross-origin resources without `Timing-Allow-Origin`, left out of the hit rate |
|
|
1501
|
+
|
|
1502
|
+
### Speculation-Rules-Inspector
|
|
1503
|
+
|
|
1504
|
+
| Code | Severity | When |
|
|
1505
|
+
|------|----------|------|
|
|
1506
|
+
| `invalid-json` | error | A speculation rules script that is not valid JSON |
|
|
1507
|
+
| `eager-list-capped` | warning | An eager prerender list with more than 10 URLs, above what Chrome prerenders |
|
|
1508
|
+
| `eager-document-rule` | warning | A document prerender rule with eager eagerness |
|
|
1509
|
+
| `no-rules` | info | No speculation rules in the DOM |
|
|
1510
|
+
| `no-prefetch-or-prerender` | info | Speculation rules scripts without prefetch or prerender rules |
|
|
1511
|
+
| `unsupported` | info | The browser does not support speculation rules |
|
|
1512
|
+
| `prerendered` | info | The page was prerendered, so its timings start at `activationStart` |
|
|
1513
|
+
|
|
1514
|
+
### TTFB-Resources
|
|
1515
|
+
|
|
1516
|
+
| Code | Severity | When |
|
|
1517
|
+
|------|----------|------|
|
|
1518
|
+
| `no-resources` | info | No resources with TTFB data |
|
|
1519
|
+
|
|
1520
|
+
### TTFB-Sub-Parts
|
|
1521
|
+
|
|
1522
|
+
| Code | Severity | When |
|
|
1523
|
+
|------|----------|------|
|
|
1524
|
+
| `slow-ttfb` | warning or error | A TTFB that is not good, an error when poor, naming its slowest phase |
|
|
1525
|
+
|
|
1526
|
+
### DOM-Size-and-Depth
|
|
1527
|
+
|
|
1528
|
+
| Code | Severity | When |
|
|
1529
|
+
|------|----------|------|
|
|
1530
|
+
| `too-many-nodes` | warning or error | More than 800 nodes, an error above 1,400 |
|
|
1531
|
+
| `too-deep` | warning | A DOM deeper than 32 levels |
|
|
1532
|
+
| `too-many-children` | warning | An element with more than 60 children |
|
|
1533
|
+
|
|
1534
|
+
### Forced-Synchronous-Layout
|
|
1535
|
+
|
|
1536
|
+
| Code | Severity | When |
|
|
1537
|
+
|------|----------|------|
|
|
1538
|
+
| `forced-layout` | warning or error | A layout property read after a write forced a layout, an error above 5 times; `target` is the property |
|
|
1539
|
+
|
|
1540
|
+
### Input-Latency-Breakdown
|
|
1541
|
+
|
|
1542
|
+
| Code | Severity | When |
|
|
1543
|
+
|------|----------|------|
|
|
1544
|
+
| `slow-event-type` | warning or error | An event type whose P75 is not good, an error when poor; `target` is the event type |
|
|
1545
|
+
|
|
1546
|
+
### Interactions
|
|
1547
|
+
|
|
1548
|
+
| Code | Severity | When |
|
|
1549
|
+
|------|----------|------|
|
|
1550
|
+
| `slow-interaction` | warning or error | An interaction above 200 ms, an error above 500 ms; `target` is its type |
|
|
1551
|
+
|
|
1552
|
+
### Scroll-Performance
|
|
1553
|
+
|
|
1554
|
+
| Code | Severity | When |
|
|
1555
|
+
|------|----------|------|
|
|
1556
|
+
| `non-passive-listeners` | warning | Scroll or touch listeners without `{ passive: true }` |
|
|
1557
|
+
| `will-change` | info | Elements with `will-change` set |
|
|
1558
|
+
|
|
1559
|
+
### Image-Element-Audit
|
|
1560
|
+
|
|
1561
|
+
Each issue names its image in `target`, except `lcp-not-img`.
|
|
1562
|
+
|
|
1563
|
+
| Code | Severity | When |
|
|
1564
|
+
|------|----------|------|
|
|
1565
|
+
| `lcp-not-img` | info | The LCP element is not an `<img>` |
|
|
1566
|
+
| `lcp-no-fetchpriority` | error | The LCP image has no `fetchpriority="high"` |
|
|
1567
|
+
| `lcp-lazy` | error | The LCP image has `loading="lazy"` |
|
|
1568
|
+
| `lcp-not-decoding-sync` | warning | The LCP image has no `decoding="sync"` |
|
|
1569
|
+
| `lcp-not-preloaded` | warning | The LCP image has no `<link rel="preload" as="image">` |
|
|
1570
|
+
| `lcp-preload-no-fetchpriority` | info | The preload of the LCP image has no `fetchpriority="high"` |
|
|
1571
|
+
| `lazy-in-viewport` | warning | An image in the viewport with `loading="lazy"` |
|
|
1572
|
+
| `eager-off-viewport` | warning | An image outside the viewport without `loading="lazy"` |
|
|
1573
|
+
| `high-priority-off-viewport` | error | An image outside the viewport with `fetchpriority="high"` |
|
|
1574
|
+
| `lazy-and-high-priority` | error | An image with both `loading="lazy"` and `fetchpriority="high"` |
|
|
1575
|
+
| `missing-dimensions` | warning | An image without `width` and `height` |
|
|
1576
|
+
| `no-modern-format` | info | An image that is not WebP, AVIF, JPEG XL or SVG, outside a `<picture>` |
|
|
1577
|
+
|
|
1578
|
+
### Oversized-Images
|
|
1579
|
+
|
|
1580
|
+
Each issue names its image in `target`.
|
|
1581
|
+
|
|
1582
|
+
| Code | Severity | When |
|
|
1583
|
+
|------|----------|------|
|
|
1584
|
+
| `oversized` | info or warning | A file larger than its slot needs, a warning when it is far larger |
|
|
1585
|
+
| `undersized` | info or warning | A file smaller than its slot needs, so it looks blurry, a warning when it is far smaller |
|
|
1586
|
+
|
|
1587
|
+
### SVG-Embedded-Bitmap-Analysis
|
|
1588
|
+
|
|
1589
|
+
| Code | Severity | When |
|
|
1590
|
+
|------|----------|------|
|
|
1591
|
+
| `embedded-bitmaps` | warning | SVG files that contain bitmaps |
|
|
1592
|
+
| `sprite-opportunity` | info | Standalone inline SVGs that could share one `<symbol>` sprite |
|
|
1593
|
+
|
|
1594
|
+
### Video-Element-Audit
|
|
1595
|
+
|
|
1596
|
+
Each issue names its video in `target`, except `no-videos`.
|
|
1597
|
+
|
|
1598
|
+
| Code | Severity | When |
|
|
1599
|
+
|------|----------|------|
|
|
1600
|
+
| `no-videos` | info | No `<video>` elements on the page |
|
|
1601
|
+
| `preload-auto` | error | `preload="auto"` on a video without `autoplay` |
|
|
1602
|
+
| `off-viewport-preload` | warning | A video outside the viewport without `preload="none"` |
|
|
1603
|
+
| `autoplay-not-muted` | error | `autoplay` without `muted` |
|
|
1604
|
+
| `autoplay-no-playsinline` | warning | `autoplay` without `playsinline` |
|
|
1605
|
+
| `missing-poster` | warning | A video without a poster |
|
|
1606
|
+
| `missing-dimensions` | warning | A video without `width` and `height` |
|
|
1607
|
+
| `no-modern-codec` | info | No WebM source (VP9 or AV1) |
|
|
1608
|
+
| `no-controls` | info | A video without `controls` and without `autoplay` |
|
|
1609
|
+
|
|
1610
|
+
---
|
|
1611
|
+
|
|
1192
1612
|
## Guidelines for Agents
|
|
1193
1613
|
|
|
1194
1614
|
### Reading results
|
|
@@ -1223,6 +1643,7 @@ data = evaluate_script("getINP()")
|
|
|
1223
1643
|
- `rating === "poor"` → high priority fix, check `issues` for specific problems
|
|
1224
1644
|
- `count > 0` and `issues.length > 0` → audit found actionable problems
|
|
1225
1645
|
- `count === 0` → nothing to audit (no render-blocking resources, no images, etc.)
|
|
1646
|
+
- To tell whether an issue is new, fixed or the same as in an earlier run, compare `script`, `code` and `target`, not `message`
|
|
1226
1647
|
|
|
1227
1648
|
---
|
|
1228
1649
|
|
|
@@ -1240,5 +1661,6 @@ data = evaluate_script("getINP()")
|
|
|
1240
1661
|
10. **Valid statuses only** — `ok`, `tracking`, `error` or `unsupported`, with an `error` message when the status is `error` or `unsupported`.
|
|
1241
1662
|
11. **Hidden cross-origin data is reported, not guessed** — a resource whose timing or size is hidden (no `Timing-Allow-Origin`) reports zeros for every size and timing. Count it (`sizeKnown: false`, `corsRestrictedCount`) instead of treating the zero as a measurement.
|
|
1242
1663
|
12. **Partial analysis is flagged** — when hidden cross-origin data leaves part of the set unanalyzed, set the top-level `corsLimitedAnalysis: true` and report how many resources were skipped in `details` (`sizeUnknownCount`, `corsRestrictedCount`). Set it to `false` when every resource was analyzed.
|
|
1664
|
+
13. **Issues carry a stable code**: every issue has a kebab-case `code`, written as a literal in the source (`code: "blocking-in-head"`) and listed under Issue codes, and a `target` string when it is about one resource.
|
|
1243
1665
|
|
|
1244
|
-
The rules are checked by `cli/tests/e2e/snippet-contract.test.js`, which runs every script, its `getDataFn` and every other getter it exposes on `window` (such as `getINPDetails()` and `checkBfcache()`), on an empty page, a seeded page and a heavy page.
|
|
1666
|
+
The rules are checked by `cli/tests/e2e/snippet-contract.test.js`, which runs every script, its `getDataFn` and every other getter it exposes on `window` (such as `getINPDetails()` and `checkBfcache()`), on an empty page, a seeded page and a heavy page. `cli/tests/unit/issue-codes.test.js` checks that the codes in the source of each snippet match its table under Issue codes.
|