The CDN was on. It wasn’t caching.
The distribution sat in “no cache” mode and a Vary: Cookie header stopped the edge from storing anything, so every visitor waited for a full WordPress render, about 650 ms before the first byte. On top of that, every page carried a 707 KB JavaScript monolith, a 445 KB SVG sprite inlined into the HTML and five font weights with 644 glyphs each.
- JavaScript bundle
- 707 KB
- Inline SVG sprite
- 445 KB
- Fonts, 5 weights
- 245 KB
- HTML
- 239 KB
Three levels of cache, one script.
Browser, server and CDN edge, taught in that order: the origin first learned what must never be cached (admin bar, redirects, logged-in pages), and only then was the edge allowed to cache everything. Then the theme. The bars show roughly how much of the page weight was left after each step.
The page arrives before the server wakes up.
A cached page is served from the nearest edge in tens of milliseconds and the server renders it once every few minutes instead of on every request. On the phone: first paint from 3.2 to 1.5 seconds, main-thread blocking from 486 to 51 ms, JavaScript execution from 2.0 to 0.4 s. Honest leftovers: the hero still shifts on some runs and the mobile LCP wants an AVIF hero with a preload. Both are on the list.