Hash in filename = cache key. Content changes → filename changes → fresh HTML points at new file. Aggressive caching + instant bust, zero stale-code risk.
Revalidation:ETag + If-None-Match → 304 = saves the download, still pays the RTT.
stale-while-revalidate = serve stale instantly + refresh in background → instant & eventually-fresh. Engine behind React Query/SWR.
App-level data cache (server state)
Server state ≠ UI state: shared, goes stale, many consumers → React Query / SWR.
Default wins: dedupe in-flight requests, SWR background refetch, invalidate on mutation, cached by query key ['hotel', id].
Browser HTTP cache is coarse (whole response by URL) — can't model shared mutating state.
Perf budgets & guardrails (the systemic move)
Budget
Example
Tool
Quantity
bundle ≤170KB gz, ≤10 req
size-limit
Milestone
LCP ≤2.5s, TBT ≤200ms
Lighthouse CI
Rule
LH Perf ≥90
Lighthouse CI
Two-sided guardrail:Pre-merge (lab): size-limit + Lighthouse CI fail the PR over budget. Post-deploy (field): RUM web-vitalsp75 LCP/INP/CLS dashboard + release alerts (lab can't catch real device/network/3rd-party variance).
Memory leaks (stay fast within a session)
SPA doesn't reload between routes → per-navigation leak compounds over a long session → slow then crash.
Causes: un-removed listeners · live setInterval/timers · detached DOM still referenced · subscriptions/observers/WebSockets not torn down · unbounded global array/Map/cache.
React: almost always a missing useEffect cleanup — return a fn that removes listener/clears timer/unsubscribes.
Frame “Fast once is easy; fast across 20 teams and a long session is the job — cache repeated work, budget regressions in CI, watch real users.”
Cache “Content-hash assets, cache immutably for a year; HTML on no-cache. The hash is the cache key, so aggressive caching AND instant busting.”
Data “Server state isn't UI state — React Query with stale-while-revalidate, dedupe, background refetch; force an authoritative read at checkout.”
Budget “Regressions un-mergeable: size-limit + Lighthouse CI fail the PR; RUM p75 web-vitals catches what the lab can't, with release alerts.”
Leak “SPAs don't reload, so a per-nav leak compounds — most are a missing teardown, so every subscribing effect unsubscribes; I confirm with comparison snapshots + the detached filter.”