feat(validate): add 7 performance/web vitals validation rules#725
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds seven performance-focused validation rules to the Validate plugin, updates documentation with their behavior and configuration examples, and adds unit tests covering warning and non-warning cases for each new rule. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add render-blocking-script, too-many-fetchpriority-high, defer-on-module-script, duplicate-resource-hint, charset-not-early, preload-not-modulepreload, and preconnect-missing-crossorigin rules to the ValidatePlugin. These catch common performance anti-patterns that impact Core Web Vitals (LCP, INP, CLS) including render-blocking scripts in head, diluted fetch priority signals, redundant defer on modules, duplicate resource hints, late charset declarations, incorrect preload vs modulepreload usage, and missing crossorigin on preconnect.
3ed3893 to
99e6afc
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/unhead/test/unit/plugins/validate.test.ts (1)
951-963: Test comment is technically inaccurate.The comment states preconnects with and without
crossoriginare "logically duplicates," but they establish different connection pools (non-CORS vs CORS). Both may be intentionally needed.Consider updating the comment to acknowledge this is a design trade-off:
- // Two preconnects to the same origin: one with crossorigin, one without. - // They hash differently so unhead keeps both, but they are logically duplicates. + // Two preconnects to the same origin: one with crossorigin, one without. + // While these technically serve different connection pools, having both + // is uncommon. The rule flags this as a potential oversight.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/unhead/test/unit/plugins/validate.test.ts` around lines 951 - 963, Update the in-test comment in the test case that pushes two preconnect links (the "warns on duplicate preconnect for same origin with different props" it-block) to note that preconnects with and without crossorigin create different connection pools (non-CORS vs CORS) and therefore may be intentionally distinct; clarify this is a deliberate design trade-off related to the 'duplicate-resource-hint' validation rule and reference the relevant items (the head.push entries, createValidationHead, and renderSSRHead) so future readers understand why the test exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/unhead/src/plugins/validate.ts`:
- Around line 578-588: The duplicate-resource-hint detection currently uses only
rel:href as the dedupe key and thus flags legitimate preconnect pairs that
differ by crossorigin; update the logic in the loop (see resourceHintsSeen,
tags, report and tag.props.rel/tag.props.href) to treat preconnect specially by
incorporating tag.props.crossorigin into the key when tag.props.rel ===
'preconnect' (or alternatively skip preconnect entirely from this check); ensure
the chosen approach compares and stores keys accordingly so that non-CORS and
CORS preconnect links are not reported as duplicates while keeping the existing
behavior for preload/prefetch.
---
Nitpick comments:
In `@packages/unhead/test/unit/plugins/validate.test.ts`:
- Around line 951-963: Update the in-test comment in the test case that pushes
two preconnect links (the "warns on duplicate preconnect for same origin with
different props" it-block) to note that preconnects with and without crossorigin
create different connection pools (non-CORS vs CORS) and therefore may be
intentionally distinct; clarify this is a deliberate design trade-off related to
the 'duplicate-resource-hint' validation rule and reference the relevant items
(the head.push entries, createValidationHead, and renderSSRHead) so future
readers understand why the test exists.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 39549deb-bed6-421e-b2e1-8b40eacb58f4
📒 Files selected for processing (3)
docs/head/1.guides/plugins/validate.mdpackages/unhead/src/plugins/validate.tspackages/unhead/test/unit/plugins/validate.test.ts
Bundle Size Analysis
|
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/unhead/src/plugins/validate.ts (1)
616-626:⚠️ Potential issue | 🟡 MinorPreconnect deduplication key should account for
crossoriginattribute.The deduplication key
${rel}:${href}will flag legitimate preconnect pairs that differ bycrossoriginas duplicates. Having both variants is intentional when an origin serves both CORS and non-CORS resources:<link rel="preconnect" href="https://cdn.example.com"> <!-- For images --> <link rel="preconnect" href="https://cdn.example.com" crossorigin> <!-- For fonts -->These establish separate connection pools in the browser.
,
Proposed fix: include crossorigin in key for preconnects
for (const tag of tags) { if (tag.tag === 'link' && tag.props.href && (tag.props.rel === 'preload' || tag.props.rel === 'prefetch' || tag.props.rel === 'preconnect')) { - const key = `${tag.props.rel}:${tag.props.href}` + const crossoriginSuffix = tag.props.rel === 'preconnect' && 'crossorigin' in tag.props ? ':cors' : '' + const key = `${tag.props.rel}:${tag.props.href}${crossoriginSuffix}` if (resourceHintsSeen.has(key))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/unhead/src/plugins/validate.ts` around lines 616 - 626, The dedupe key for resource hints in validate.ts currently uses `${rel}:${href}` and incorrectly treats preconnects with different crossorigin attributes as duplicates; update the logic in the loop that builds resourceHintsSeen (referencing resourceHintsSeen, tag, tag.props.rel, tag.props.href, tag.props.crossorigin) so that when tag.props.rel === 'preconnect' the key includes the crossorigin value (e.g. `${rel}:${href}:crossorigin=${tag.props.crossorigin}`) while keeping existing keys for preload/prefetch unchanged, then use that key for the resourceHintsSeen.has/set checks and duplicate reporting via report('duplicate-resource-hint', ...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/unhead/src/plugins/validate.ts`:
- Around line 657-672: The rule currently collects corsOrigins from any tag with
crossorigin and then warns on non-CORS preconnects, causing false positives when
a CORS preconnect already exists; fix by tracking origins of preconnect tags
that already include crossorigin (e.g., build a preconnectCorsOrigins Set from
tags where tag.tag==='link' && tag.props.rel==='preconnect' && 'crossorigin' in
tag.props using extractOrigin) and in the second loop skip reporting if the
origin is present in that preconnectCorsOrigins set (in addition to the existing
corsOrigins check), so a deliberate pair of preconnects (with and without
crossorigin) does not trigger preconnect-missing-crossorigin.
---
Duplicate comments:
In `@packages/unhead/src/plugins/validate.ts`:
- Around line 616-626: The dedupe key for resource hints in validate.ts
currently uses `${rel}:${href}` and incorrectly treats preconnects with
different crossorigin attributes as duplicates; update the logic in the loop
that builds resourceHintsSeen (referencing resourceHintsSeen, tag,
tag.props.rel, tag.props.href, tag.props.crossorigin) so that when tag.props.rel
=== 'preconnect' the key includes the crossorigin value (e.g.
`${rel}:${href}:crossorigin=${tag.props.crossorigin}`) while keeping existing
keys for preload/prefetch unchanged, then use that key for the
resourceHintsSeen.has/set checks and duplicate reporting via
report('duplicate-resource-hint', ...).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 13232884-4f35-4521-b744-f9d96e2f343c
📒 Files selected for processing (3)
docs/head/1.guides/plugins/validate.mdpackages/unhead/src/plugins/validate.tspackages/unhead/test/unit/plugins/validate.test.ts
✅ Files skipped from review due to trivial changes (1)
- packages/unhead/test/unit/plugins/validate.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/head/1.guides/plugins/validate.md
Preconnects with and without crossorigin establish separate connection pools and are intentionally paired. Include crossorigin in the dedupe key for duplicate-resource-hint, and skip preconnect-missing-crossorigin when a CORS preconnect already exists for the same origin.
🔗 Linked issue
N/A
❓ Type of change
📚 Description
Adds 7 new validation rules to the ValidatePlugin focused on performance and Core Web Vitals anti-patterns:
render-blocking-script<script src>in head withoutasync/defer/type="module"too-many-fetchpriority-highfetchpriority="high"dilutes the signaldefer-on-module-scriptdeferontype="module"scriptsduplicate-resource-hintrel:hrefpair appearing multiple times in preload/prefetch/preconnectcharset-not-early<meta charset>not within first N (configurable, default 3) head tagspreload-not-modulepreloadrel="preload" as="script"for a module script should usemodulepreloadpreconnect-missing-crossorigincrossoriginto an origin that serves CORS resourcestoo-many-fetchpriority-highandcharset-not-earlysupport configurable thresholds via the existing ESLint-style tuple syntax. All rules are documented and have full test coverage (20 new test cases).Summary by CodeRabbit
New Features
Documentation
Tests