Skip to content

Commit 7012a1f

Browse files
committed
feat: add Cache Strategy Analysis snippet
Audits HTTP caching strategies, CDN hit rates, and cache anti-patterns across all page resources. Includes cache efficiency score, bandwidth savings, protocol distribution, duplicate resource detection, and actionable recommendations optimized for AI agent consumption.
1 parent 2be82b6 commit 7012a1f

3 files changed

Lines changed: 960 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import snippet from '../../snippets/Loading/Cache-Strategy-Analysis.js?raw'
2+
import { Snippet } from '../../components/Snippet'
3+
4+
# Cache Strategy Analysis
5+
6+
Audits HTTP caching strategies across all page resources, identifying resources without cache, short-lived cache configurations, cache anti-patterns, and CDN cache hit rates. Provides a cache efficiency score and actionable recommendations.
7+
8+
**What this snippet analyzes:**
9+
10+
- Cache strategy classification for every resource (immutable, long, medium, short, no-cache, no-store, etc.)
11+
- Resources missing cache headers entirely
12+
- Static assets with insufficient cache duration
13+
- Cache anti-patterns (versioned files without `immutable`, large uncached resources, outdated `Expires` usage)
14+
- CDN cache hit/miss detection (Cloudflare, Vercel, CloudFront, and generic proxies)
15+
- Cache efficiency score and estimated bandwidth savings
16+
- Protocol distribution (HTTP/1.1 vs H2/H3)
17+
- Uncompressed text resources and duplicate resource loads
18+
19+
**How the browser decides to serve a resource:**
20+
21+
```mermaid
22+
flowchart TD
23+
A[Resource Request] --> B{In browser cache?}
24+
B -- No --> C[Fetch from network]
25+
B -- Yes --> D{Cache-Control directive?}
26+
D -- no-store --> C
27+
D -- no-cache / max-age=0 --> E[Revalidate with server]
28+
D -- max-age not expired --> F[Serve from cache ✅]
29+
D -- max-age expired --> E
30+
E -- 304 Not Modified --> F
31+
E -- 200 OK --> G[New response + update cache]
32+
C --> G
33+
```
34+
35+
**Why caching matters for performance:**
36+
37+
| Metric | Impact |
38+
|--------|--------|
39+
| LCP | Cached resources load instantly — no network round-trip |
40+
| TTFB | CDN cache hits dramatically reduce server response time |
41+
| Bandwidth | Cached resources don't consume data (mobile users benefit) |
42+
| Repeat visits | Good caching makes subsequent page loads near-instant |
43+
44+
### Snippet
45+
46+
<Snippet code={snippet} />
47+
48+
## Understanding the Results
49+
50+
### Cache Strategy Distribution
51+
52+
Every resource is classified into one of these strategies:
53+
54+
| Strategy | Cache-Control directive | Typical use case |
55+
|---------|------------------------|-----------------|
56+
| `immutable` | `max-age=31536000, immutable` | Versioned/hashed static assets |
57+
| `long` | `max-age > 86400` (> 1 day) | Static assets with long lifetime |
58+
| `medium` | `max-age 3600–86400` (1h–1d) | Semi-static content |
59+
| `short` | `max-age < 3600` (< 1h) | Frequently updated content |
60+
| `swr` | `stale-while-revalidate` | Content served stale while background refresh |
61+
| `must-revalidate` | `must-revalidate` + ETag/Last-Modified | Documents that must be fresh |
62+
| `no-cache` | `no-cache` or `max-age=0` | Forces revalidation every request |
63+
| `no-store` | `no-store` | Never cached (sensitive data) |
64+
| `expires-only` | Only `Expires` header, no `Cache-Control` | Legacy servers (outdated) |
65+
| `none` | No caching headers at all | Missing cache configuration |
66+
| `unknown (CORS)` | Cross-origin, headers not readable | Add `Timing-Allow-Origin` for visibility |
67+
| `cached (inferred)` | `transferSize=0` but no readable headers | Browser cached, strategy unknown |
68+
69+
The **Cache Efficiency Score** shows what percentage of resources have an effective cache strategy (`immutable`, `long`, `medium`, `swr`, or `must-revalidate`).
70+
71+
### Resources Without Cache
72+
73+
Resources with strategy `none`, `no-store`, or `no-cache`. For static assets (JS, CSS, fonts, images), this is a performance problem — every page load re-fetches them from the network.
74+
75+
**Fix:** Add `Cache-Control: max-age=31536000, immutable` for versioned assets, or at minimum `max-age=86400` for stable static files.
76+
77+
### Short Cache Resources
78+
79+
Resources with `max-age < 3600` (less than 1 hour). Pay attention to:
80+
81+
- **Has Hash = ✅**: If the URL contains a content hash, the file changes when its content changes. A short cache is wasted opportunity — use `immutable`.
82+
- **Has Hash = ❌**: The URL is stable, so a short cache forces frequent re-fetches. Increase the TTL if the content changes infrequently.
83+
84+
### Cache Anti-patterns
85+
86+
| Pattern | Severity | Meaning |
87+
|---------|----------|---------|
88+
| `static-no-store` | 🔴 Error | A JS, CSS, font, or image file has `no-store` — these should always be cacheable |
89+
| `large-no-cache` | 🔴 Error | A resource > 100 KB has no cache — significant bandwidth waste per visit |
90+
| `versioned-short-cache` | 🟡 Warning | A hashed URL has `max-age < 86400` — safe to use much longer TTL |
91+
| `expires-without-cc` | 🟡 Warning | Uses only `Expires` header — outdated, less reliable than `Cache-Control` |
92+
| `maxage-zero-static` | 🟡 Warning | Static asset with `max-age=0` — browser revalidates on every request |
93+
| `short-cache-static` | 🟡 Warning | Static asset with `max-age < 3600` — increase TTL for better performance |
94+
| `versioned-not-immutable` | 🔵 Info | Hashed URL without `immutable` — adding it avoids conditional GET requests |
95+
96+
### CDN Cache Status
97+
98+
Reads CDN-specific response headers to determine cache hit/miss per resource:
99+
100+
| Header | CDN detected |
101+
|--------|-------------|
102+
| `CF-Cache-Status` | Cloudflare |
103+
| `X-Vercel-Cache` | Vercel Edge Network |
104+
| `X-Cache` | CloudFront or generic CDN |
105+
| `Age` | Generic proxy/CDN (presence = served from cache) |
106+
| `Via` | Any HTTP proxy |
107+
| `Server-Timing` | CDN that exposes cache info in Server-Timing |
108+
109+
A **CDN hit rate below 70%** usually indicates the CDN cache is cold, the TTL is too short, or cache-busting headers (`Cache-Control: no-store`, `Vary: *`) are preventing caching at the edge.
110+
111+
## Header Analysis Scope and CORS Limitations
112+
113+
Header inspection (`Cache-Control`, `Expires`, CDN headers) requires issuing `HEAD` requests via `fetch()`. Two categories of resources are excluded from this analysis and fall back to **Tier 1 heuristics** (Performance API data only):
114+
115+
### Cross-origin resources
116+
117+
Resources served from a different origin (different scheme, host, or port) than the current page are blocked by CORS unless the server sends `Access-Control-Allow-Origin`. This includes subdomains — `api.example.com` is cross-origin from `www.example.com`.
118+
119+
Those resources appear as **"CORS-restricted"** in the output.
120+
121+
### Non-static resource types
122+
123+
`fetch`, `xhr`, `iframe`, `beacon`, and similar dynamic resource types are excluded intentionally:
124+
125+
- Their servers commonly reject `HEAD` requests with `4xx`/`5xx` errors
126+
- Dynamic endpoints (API calls, tracking pixels) have different caching semantics than static assets
127+
- They produce console noise if fetched (e.g., CSRF token endpoints, analytics beacons)
128+
129+
These resources are still visible in the summary via Tier 1 data:
130+
131+
- `transferSize === 0` and `encodedBodySize > 0` → served from browser cache
132+
- `transferSize > 0` → fetched from the network
133+
134+
To get header visibility on your own cross-origin or CDN resources, configure the server to send:
135+
136+
```http
137+
Access-Control-Allow-Origin: *
138+
Timing-Allow-Origin: *
139+
```
140+
141+
## Further Reading
142+
143+
- [HTTP caching](https://web.dev/articles/http-cache) | web.dev
144+
- [Prevent unnecessary network requests with the HTTP Cache](https://developer.chrome.com/docs/lighthouse/performance/uses-long-cache-ttl) | Chrome Developers
145+
- [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) | MDN
146+
- [Stale-while-revalidate](https://web.dev/articles/stale-while-revalidate) | web.dev
147+
- [Content delivery networks (CDNs)](https://web.dev/articles/content-delivery-networks) | web.dev
148+
- [Service Worker Analysis](/Loading/Service-Worker-Analysis) | Complements cache analysis for SW-managed caches
149+
- [TTFB](/Loading/TTFB) | CDN cache hits directly reduce TTFB

pages/Loading/_meta.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,8 @@
7979
},
8080
"Service-Worker-Analysis": {
8181
"title": "Service Worker Analysis"
82+
},
83+
"Cache-Strategy-Analysis": {
84+
"title": "Cache Strategy Analysis"
8285
}
8386
}

0 commit comments

Comments
 (0)