Module 07 advanced 35 min

Advanced Topics

Speculation Rules, bfcache, streaming SSR, memory leaks, and build-time performance engineering.

These topics separate senior engineers from “I ran Lighthouse once” practitioners.

Speculation Rules API

Declaratively prerender or prefetch likely next navigations:

<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/product/*" },
    "eagerness": "moderate"
  }],
  "prefetch": [{
    "where": { "href_matches": "/docs/*" },
    "eagerness": "conservative"
  }]
}
</script>
ModeEffect
prefetchFetch resources for next page
prerenderFull render in hidden tab — instant navigation

Caution: prerender costs bandwidth/CPU — use eagerness and match rules tightly.

Back/forward cache (bfcache)

Instant back navigation when page is frozen in memory.

Blocks eligibility:

  • unload / beforeunload listeners
  • Open IndexedDB transactions without closure
  • Cache-Control: no-store on main document
  • Certain APIs keeping live connections

Test: DevTools → Application → Back/forward cache → “Test bfcache”.

Priority hints beyond LCP

<script src="/critical.js" fetchpriority="high"></script>
<script src="/analytics.js" fetchpriority="low" defer></script>

fetchpriority on <link rel=preload> coordinates with image/script contention.

Streaming SSR

Send HTML shell immediately, stream slow sections:

// Conceptual — framework-specific APIs vary
res.write('<html><head>…</head><body>');
res.write(fastHeader);
await streamSlowSidebar(res);
res.write('</body></html>');

Improves FCP and perceived load; LCP may still wait on slow fragment — prioritize LCP chunk in first stream.

Islands & partial hydration mental model

ApproachJS shipped
SPA full hydrationEntire app tree
SSR + hydrate allHTML + full client bundle
Islands (Astro, etc.)Per-component

This academy site uses Astro: lessons are static HTML; labs ship scoped <script> modules only on pages that need interactivity.

Memory & leaks

Symptoms: tab slows over time, mobile kills tab, DevTools heap grows unbounded.

Find:

  1. Memory → Heap snapshot → compare snapshots
  2. Detached DOM trees (listeners holding nodes)
  3. Global caches without eviction
  4. Forgotten setInterval / observers
const observer = new MutationObserver(callback);
// Later:
observer.disconnect();

Build-time performance

TechniqueBenefit
Code splittingSmaller initial JS
Tree shakingDead code elimination
Minification + compression (brotli)Transfer size
modulepreload for entry graphFaster parse/execute
CDN immutable cachingRepeat visit speed
Image pipeline (build plugin)AVIF/WebP at build

HTTP/3 & connection coalescing

QUIC reduces head-of-line blocking. Still minimize origins — each origin has connection cost even with HTTP/3.

Expert habits

  1. Field first on user-facing routes
  2. Attribute before optimizing (which script, which element)
  3. One metric per PR when possible — isolate regressions
  4. Document budgets in repo (perf-budgets.json)
  5. Teach the team — perf is a system property, not a hero task

You’ve completed the curriculum. Use Labs for hands-on practice, Cheatsheet for quick reference, and Resources for deep external reading.

Live on this page

TTFB
FCP
LCP
INP
CLS