Add snippet to validate preload on async/defer scripts#54
Conversation
Adds new documentation page with JavaScript snippet to detect and validate the use of preload hints on async and defer scripts, helping identify potential performance optimization opportunities.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Review: Add snippet to validate preload on async/defer scriptsGreat addition! This addresses a real-world performance anti-pattern that's commonly misunderstood. The documentation is thorough and well-organized. Here's my detailed feedback: Strengths
Code IssuesVariable shadowing (bug risk): Inside the forEach callback, a variable named const inHead = matchingScript.closest('head') \!== null;
const location = inHead ? 'head' : 'body'; // shadows window.locationThis shadows the global const preloadUrl = new URL(preloadHref, location.origin).href; // uses window.location.originWhile it does not cause a runtime bug in the current code (the outer Fragile URL matching for dynamic scripts: const shortUrl = preloadHref.split('/').pop()?.split('?')[0] || preloadHref;
// ...
return entry.name === preloadUrl || entry.name.includes(shortUrl);The Module scripts handling: The snippet flags Documentation SuggestionsContradictory framing in "When Is Preload + Script Actually Appropriate?": The section introduces a valid edge case for Unsourced performance impact claim:
This is presented as a fact without a citation. The actual impact is highly site-specific. Consider softening to "can measurably delay LCP" or linking to a specific measurement/study. Missing: fetchpriority as a mitigation: The snippet recommends removing preload as the fix, but does not mention Minor Notes
SummaryThis is a high-quality, well-researched snippet that fills a real gap in the collection. The main actionable fixes before merging:
The documentation content is excellent and the snippet logic is sound. With the variable shadowing fix in particular, this is ready to merge. |
Renames the local variable 'location' to 'scriptLocation' to avoid shadowing the global window.location object. While this didn't cause a runtime bug in the current code (since preloadUrl is resolved before the inner scope), it creates a maintenance hazard for future edits. Addresses code review feedback from Claude Bot.
Replaces fragile string matching (includes) with pathname-based comparison when matching Performance API entries. This prevents false positives for common filenames like 'main.js' or 'app.js' by comparing full pathnames instead of just checking if the entry name contains the short filename. - First attempts exact URL match - Falls back to pathname comparison using endsWith - More precise than the previous includes() approach Addresses code review feedback from Claude Bot.
Adds detection for ES modules using rel="preload" instead of the correct rel="modulepreload" attribute. ES modules behave like defer scripts by default, so using preload escalates their priority unnecessarily. Changes: - New warning type for modules without async/defer - Detects rel="preload" on type="module" scripts - Recommends rel="modulepreload" as the correct alternative - Added documentation section explaining modulepreload usage - Includes examples and MDN reference link This prevents inappropriate priority escalation for module scripts and guides developers to the proper preloading mechanism. Addresses code review feedback from Claude Bot.
Replaces specific unsourced timing claim ("100-500ms") with more
accurate, qualitative description of LCP impact. The actual delay
varies significantly based on multiple factors that are site-specific.
Changes:
- Removed unsourced "100-500ms" claim
- Uses "measurably delay" instead of specific numbers
- Acknowledges variability based on resource size, connection speed,
and competing resources
- More honest and defensible performance guidance
Addresses code review feedback from Claude Bot.
Adds documentation for using fetchpriority="low" on script tags as an alternative fix when preload needs to be kept for early discovery but bandwidth priority should be reduced. Changes: - New section explaining fetchpriority="low" usage - Problem/solution examples with code snippets - Guidance on when to use this approach vs removing preload - Notes that removing preload is usually simpler and safer - MDN reference link for fetchpriority attribute This provides developers with more options to fix the anti-pattern while understanding the trade-offs of each approach. Addresses code review feedback from Claude Bot.
Enhances the snippet to detect when fetchpriority="low" is used on async/defer scripts with preload, treating this as a valid mitigation pattern instead of an anti-pattern. Changes: - Reads fetchpriority attribute from script tags - If fetchpriority="low" is present on async/defer script with preload, classifies as valid (mitigated pattern) instead of error - Updates error messages to suggest fetchpriority="low" as alternative fix - Adds fetchPriority field to error output for debugging - Categorizes mitigated cases in validPreloads with explanatory note This allows developers who legitimately need early discovery but low priority to be recognized as using the correct pattern, reducing false positives while maintaining strict detection of actual anti-patterns.
Updates all documentation tables and guidance sections to include the fetchpriority="low" mitigation pattern as a valid approach. Changes in Overview section: - Added row in priority table for preload + async + fetchpriority="low" - Shows this pattern maintains Lowest/Low priority (valid pattern) Changes in Understanding the Results section: - Added "Module preload" to Issue Types table - Added "Mitigated pattern" to Valid Preload Types table - Updated Anti-patterns Table to include fetchPriority column - Updated Recommendations to mention fetchpriority mitigation This ensures users understand: 1. The mitigated pattern is valid and won't trigger errors 2. How to interpret results when fetchpriority is used 3. What the fetchPriority column means in output tables 4. Multiple fix options (remove preload OR add fetchpriority="low") Makes the documentation consistent with the snippet's detection logic.
PR Review: Add snippet to validate preload on async/defer scriptsOverall this is a well-conceived and technically accurate addition to the collection. The documentation is thorough and the snippet addresses a real, commonly misunderstood performance anti-pattern. Here is detailed feedback. Strengths
Issues and Suggestions1. URL matching logic — potential false positivesIn the dynamic script detection block, the endsWith comparison can produce false positives for common filenames (e.g. main.js, index.js, chunk.js): If a preload points to /app/main.js and a completely unrelated /vendor/main.js was loaded, this would match. A safer approach: 2. Module detection — implicit async module caseThe module check fires only when isAsync and isDefer are both false. However, an async ES module (script type=module async) would be caught by the isAsync branch first, skipping the modulepreload recommendation. The behavior is acceptable, but the comment about ES modules without async/defer behaving like defer could mislead future maintainers — worth clarifying in a note. 3. fetchpriority check — missing on the link elementThe mitigation check only inspects fetchpriority on the script element. The attribute can also be set on the link rel=preload element itself. A developer writing link rel=preload with fetchpriority=low on the link tag would still trigger an error, even though this is a valid mitigation. Consider also checking fetchpriority on the preload link element and OR-ing it into the hasMitigation check. 4. Summary count label is misleadingThe summary line reads: Valid preloads (blocking scripts): N But validPreloads also contains dynamic scripts and mitigated preloads, not just blocking scripts. The label should be generalized (e.g. Valid or acceptable preloads) or the count filtered to only blocking scripts. 5. Minor: external image URLThe v8.dev diagram uses an external URL with no fallback. If that URL ever becomes unavailable the page will show a broken image. The project already uses Cloudinary for media — hosting it there would be more resilient. SummaryThis is a high-quality, technically sound contribution. The main actionable items before merging are:
Issues 2 and 5 are minor and can be addressed at the author's discretion. |
…efer-Scripts Add snippet to validate preload on async/defer scripts
Summary
Test plan