perf-render-blocking-analysis
Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V. ✓ Copied. Switch to Claude and paste — ⌘/Ctrl+V.
Render-Blocking Resource Analysis
Identify and eliminate every resource in the critical path that delays FCP and LCP.
This skill goes deeper than the Lighthouse render-blocking-resources audit — it traces
the exact blocking chain, quantifies each resource's contribution, and prescribes targeted fixes.
Usage
/perf-render-blocking-analysis <URL or project-root-path> [--platform sitecore|optimizely|umbraco|headless]
Examples:
/perf-render-blocking-analysis https://localhost:3000— live URL analysis/perf-render-blocking-analysis ./src --platform sitecore— static source analysis/perf-render-blocking-analysis https://staging.client.com --platform umbraco
Phase 1 — Detect Analysis Mode
URL mode: Run Lighthouse to extract the render-blocking-resources audit and
network-requests waterfall. Parse the blocking chain from the JSON output.
Source mode: Grep the project for <head> HTML templates and locate CSS/JS/font
resource declarations. Identify blocking patterns statically.
Phase 2 — JavaScript Blocking Audit
2.1 Identify blocking scripts
Scan <head> for any <script> without async or defer:
<!-- BLOCKING — delays HTML parsing until script downloads + executes -->
<script src="/vendor/jquery.min.js"></script>
<!-- NON-BLOCKING — async: downloads in parallel, executes immediately on load -->
<script src="/analytics.js" async></script>
<!-- NON-BLOCKING — defer: downloads in parallel, executes after HTML parsed -->
<script src="/app.js" defer></script>
Rules:
async: use for scripts that are independent (analytics, ads, social widgets)defer: use for scripts that depend on DOM being ready (most app scripts)- Neither: only acceptable for inline critical scripts with no external dependencies
type="module"scripts are implicitlydefer— do not adddeferagain
2.2 Next.js / React specific
Check all <Script> component usages. Every third-party <Script> must declare a strategy:
| Strategy | When to use |
|---|---|
beforeInteractive |
Scripts that must run before page is interactive (rarely needed) |
afterInteractive (default) |
Scripts that can run after hydration |
lazyOnload |
Analytics, chat, social widgets — run when browser is idle |
worker |
Experimental — moves script to web worker via Partytown |
Flag any <Script> without a strategy prop and any script loaded via bare <script> tag.
2.3 Script size and parse time
For scripts identified as render-blocking, estimate parse/compile time:
- Mobile (slow CPU): ~1 ms per 1 KB of minified JS
- Rule of thumb: any blocking script > 50 KB is HIGH priority
- Webpack/Vite bundle analysis: check for un-split vendor chunks > 100 KB
Phase 3 — CSS Blocking Audit
3.1 Identify blocking stylesheets
Every <link rel="stylesheet"> in <head> is render-blocking by default. Triage:
Should be blocking (critical CSS): Styles needed for above-the-fold content. Should be non-blocking: Styles for below-fold sections, print, or deferred UI.
Non-blocking loading pattern:
<!-- Trick: media="print" loads without blocking; onload switches to all -->
<link rel="stylesheet" href="/below-fold.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/below-fold.css"></noscript>
Or use the modern approach with <link rel="preload">:
<link rel="preload" href="/below-fold.css" as="style" onload="this.rel='stylesheet'">
3.2 Critical CSS inlining
For pages with measurable FCP delay from external CSS, inline the critical-path styles
in a <style> block and defer the full stylesheet:
<head>
<!-- Inlined critical styles (above-fold only) — eliminates render-blocking entirely -->
<style>
/* nav, hero, above-fold typography — typically 5-15 KB */
body { margin: 0; font-family: 'Inter', sans-serif; }
.nav { display: flex; ... }
.hero { min-height: 400px; ... }
</style>
<!-- Full stylesheet deferred — loads without blocking -->
<link rel="preload" href="/styles.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>
Tools for generating critical CSS: critical, critters (used by Angular CLI and Vite).
3.3 CSS size and specificity
- Flag any single CSS file > 100 KB (uncompressed). Estimate blocked render time.
- Check for CSS
@importinside stylesheets — each@importcreates a serial request waterfall. - Flag any CSS file that includes a
@import url('...')— hoist to HTML<link>tags.
Phase 4 — Font Loading Audit
4.1 Font blocking patterns
Fonts are render-blocking when loaded via <link rel="stylesheet"> from Google Fonts
or similar CDNs without display=swap. The browser holds paint until the font resolves.
Blocking patterns to flag:
<!-- BLOCKING: Google Fonts without display=swap param -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600" rel="stylesheet">
<!-- BLOCKING: @font-face without font-display -->
<style>
@font-face { font-family: 'Inter'; src: url('/fonts/inter.woff2'); }
</style>
Fixed patterns:
<!-- Non-blocking: preconnect + swap -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
/* font-display: swap prevents FOIT; shows fallback while loading */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}
4.2 Font preloading
If the LCP element is text and a custom font is loading, preload the font file:
<!-- Preload the specific weight/format used in the LCP text element -->
<link rel="preload" href="/fonts/inter-600.woff2" as="font" type="font/woff2" crossorigin>
Rules:
- Only preload fonts actually used above the fold — preloading everything wastes bandwidth
- Always include
crossoriginattribute (required for CORS-served fonts) - Prefer
woff2— best compression, universally supported
4.3 Self-hosting vs. Google Fonts
Self-hosting (fonts served from your own domain/CDN) eliminates the DNS lookup + TLS
handshake overhead of fonts.googleapis.com and fonts.gstatic.com. For LCP-critical
fonts on high-traffic sites, self-hosting typically saves 100–300 ms.
Phase 5 — Third-Party Resource Audit
Extract from Lighthouse third-party-summary audit. For each third-party origin:
| Origin | Category | Blocking time | Action |
|---|---|---|---|
fonts.googleapis.com |
Fonts | > 0 ms | Preconnect / self-host |
www.googletagmanager.com |
Analytics | Variable | Load async; use GTM's delayed loading |
connect.facebook.net |
Social | > 0 ms | Defer with lazyOnload |
widget.intercom.io |
Chat | > 0 ms | strategy="lazyOnload" |
cdn.cookielaw.org |
Consent | Critical | Must load early but verify async is set |
Total third-party blocking time > 500 ms = HIGH finding. Flag each contributing origin.
Phase 6 — Report
Output structured findings:
## Render-Blocking Analysis Report
**URL / Path:** [target]
**Platform:** [detected/specified]
### Blocking Resource Inventory
| Resource | Type | Blocking time | Size | Priority |
|---|---|---|---|---|
| /vendor/jquery.min.js | JS (no defer) | ~320 ms | 87 KB | HIGH |
| https://fonts.googleapis.com/... | Font CSS | ~210 ms | 4 KB | HIGH |
| /styles/all.css | CSS | ~180 ms | 220 KB | MEDIUM |
**Total estimated FCP savings if all resolved:** ~XXX ms
### Findings
[one block per finding using standard finding schema]
Quality Checklist
- Every blocking script identified with exact filename and estimated blocking time
- Font loading strategy checked —
font-display: swappresent on all@font-face - Third-party script origins enumerated with blocking time
- CSS
@importchains identified and count noted - Every finding has a specific before/after code fix
- Total estimated FCP savings calculated
Reference files
reference.md— resource loading attributes reference, browser parsing waterfall model
Technical details
- Plugin
- performance-auditor
- Author
- Dakota Smith
- Skill name
perf-render-blocking-analysis- Maturity
- experimental
- Security review
- No security review
- Owners
-
- engineering
- Argument hint
<URL or project-root-path> [--platform sitecore|optimizely|umbraco|headless]- Allowed tools
-
ReadWriteGlobGrepBash(npx lighthouse *)Bash(node *)Bash(cat *)Bash(ls *)WebFetch(domain:localhost)WebFetch(domain:web.dev)
- Source
plugins/performance-auditor/skills/perf-render-blocking-analysis/SKILL.md
Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.