awesome-everything RU
↑ Back to the climb

Performance

V8 JIT pipeline, HTTP priorities, and bundle security

Crux V8''''s four compilation tiers, HTTP/3 Extensible Priorities (RFC 9218), 103 Early Hints, and Subresource Integrity form the senior layer of bundle delivery — the mechanisms that explain why a smaller bundle still varies by 2-3x depending on how it is served.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 18 min

Two apps have the same 100 KB homepage bundle. One has LCP 1.4 s; the other 2.3 s. The bundle sizes are identical. The difference is in how the bundle is delivered — resource priorities, Early Hints, and whether critical functions reach V8’s optimised tiers before the page is interactive.

V8’s tiered compilation pipeline

V8 compiles JavaScript through four progressive tiers, trading compile cost for execution speed.

Ignition — the bytecode interpreter. Every function starts here. Compile cost is minimal; execution is ~5-10x slower than optimised native code. Code that runs only once (module-level initialisation) typically stays in Ignition.

Sparkplug (Chrome 91, 2021) — a non-optimising baseline JIT. Compiles bytecode to machine code with no inlining or type speculation. Compile cost is similar to Ignition; execution is ~5x faster. Functions automatically promote to Sparkplug after running roughly 100 times.

Maglev (Chrome 117, 2023) — a mid-tier optimising JIT with some inlining and type speculation. Promotes after more iterations.

TurboFan — the top-tier optimising compiler. Full inlining, escape analysis, type speculation, loop unrolling. Compile cost is high (10-100 ms per hot function) but execution approaches native speed. Functions reach TurboFan only after proven hot.

Implications for bundle budgets: total parse cost is proportional to bundle bytes — every byte must be parsed once regardless of tier. Initial compile cost is proportional to code that actually runs at startup. Code that never runs is parsed but never compiled (V8’s lazy compilation). Bundle size matters most for parse and initial compile; execution speed of hot functions depends more on code shape (type stability, allocation patterns) than on bundle size.

Deoptimisation traps: V8 speculatively optimises functions based on observed types. If a function that was compiled assuming argument is always number receives a string, V8 deoptimises it — throws away the TurboFan-compiled version and falls back to Sparkplug or Ignition. A deopt loop is a function that optimises, deoptimises, and re-optimises repeatedly — it can burn CPU even with a small bundle. Diagnose with Chrome DevTools Performance tab; look for “Deoptimize” events.

HTTP/3 Extensible Priorities (RFC 9218)

HTTP/1.1 and HTTP/2 have no reliable client-to-server priority signalling. HTTP/3 (over QUIC) implements RFC 9218: browsers send a Priority header with each request. Servers and CDNs that implement it serve critical resources first even if they were requested last.

Priority: u=1          # High urgency (0=highest, 7=lowest)
Priority: u=3, i       # Medium urgency, incremental delivery

Browsers automatically assign priorities: CSS in <head> gets urgency 0; lazy-loaded images get urgency 5-6. A small critical bundle competing with a large deferred vendor chunk for bandwidth is served first when the CDN honours priorities.

Misconfiguration risk: misconfigured HTTP/3 priority can erase 20-30% of code-splitting benefits if the CDN sends the large deferred chunk first despite browser priority hints. Verify in Chrome’s Network panel under the “Priority” column.

103 Early Hints (RFC 8297)

A server that knows it will serve index.html also knows the critical resources that page will need — the critical JS chunk, the main font, the hero image. With 103 Early Hints, the server sends an informational 103 response with Link: ...; rel=preload headers before finishing HTML generation. The browser starts fetching critical resources while the server is still building the response.

HTTP/2 103 Early Hints
Link: </static/app.abc123.js>; rel=preload; as=script
Link: </fonts/inter.woff2>; rel=preload; as=font; crossorigin

Typical gain: 100-500 ms on critical resource delivery, depending on the server’s HTML generation time and network latency. Cloudflare, Fastly, and Vercel support 103. Most production teams do not use Early Hints yet; it is a senior-level optimisation that shows up in 95th-percentile LCP improvements.

TechniqueMechanismTypical gain
HTTP/3 RFC 9218 prioritiesCritical chunk served before deferred chunksPrevents 20-30% split benefit loss
103 Early HintsPreload headers before HTML is ready100-500 ms LCP improvement
modulepreloadDownload + parse-compile ESM module earlyRemoves parse cost from critical path

Subresource Integrity and CSP

Subresource Integrity (SRI): the integrity attribute on <script> and <link> tags includes a hash of the expected file content. If a CDN or third-party host is compromised and serves a modified script, the browser computes the hash and rejects the file.

<script src="https://cdn.example.com/lib.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

Without SRI, a CDN compromise ships malicious JS to all users silently. With SRI, the browser refuses the script. Production-grade: SRI on all third-party script tags; build tooling generates SRI hashes for first-party assets automatically.

CSP + bundle delivery: script-src 'self' https://cdn.example.com restricts which origins can serve scripts. Common misconfiguration: 'unsafe-inline' allows inline scripts, defeating the protection against XSS-injected scripts. Use nonces or hashes for intentional inline scripts instead.

Production observability: bundle size as a RUM metric

Beyond LCP/INP/CLS, senior teams track gzip’d bundle size per route as a custom RUM metric. When LCP degrades, the first correlation to check is whether the bundle size changed in the same deploy. Some platforms (Vercel Analytics, Sentry Performance) expose this automatically; others require a custom beacon.

Production failure patterns: Pinterest 2017 (single large bundle → 12 s main-thread block, rewrite to chunks → bounce -40%); Tinder 2019 (admin panel on consumer routes → 200 KB removed → conversion +5%); Stripe 2020 (Stripe.js 80 KB on every checkout → small loader + lazy → TTI -35%). The pattern is always structural: split, lazy, replace — not compress-more.

Why this works

Why does a deopt loop matter for bundle budgets? A deoptimisation happens when V8 detects that its type assumptions were wrong and falls back to slower tiers. If the deopt is in a frequently-called function (say, a render loop), the CPU overhead is multiplicative — the function re-JITs repeatedly. A 50 KB bundle with a deopt loop in a hot function can feel slower than a 200 KB bundle without one. Bundle analysis and —trace-deopt are different diagnostic axes; senior performance work uses both.

Quiz

A team profiles V8 and finds a render function deoptimises 50 times per second. The bundle is 90 KB. What is the fix, and does reducing bundle size help?

Quiz

A team enables code splitting but their CDN is misconfigured with equal HTTP/3 priorities for all chunks. What is the likely performance impact?

Quiz

A script tag has no integrity attribute and loads from a third-party CDN. The CDN is compromised and serves a modified script. What happens without SRI, and what happens with it?

Recall before you leave
  1. 01
    Describe V8's four compilation tiers and what each buys.
  2. 02
    What does RFC 9218 define, and why does it matter for code-split bundles?
  3. 03
    A PR introduces a function that handles both strings and numbers. After a deploy, RUM shows INP regression on a specific route. What is the likely diagnosis and fix?
Recap

Bundle size sets the parse cost floor, but the ceiling is determined by how the bundle is delivered and compiled. V8’s four JIT tiers compile hot functions progressively from Ignition through TurboFan — bundle bytes affect parse, but type-unstable hot functions cause deopt loops that dominate execution time independently of size. HTTP/3 RFC 9218 priorities ensure code-split chunks arrive in the right order; a misconfigured CDN erases up to 30% of split benefits. 103 Early Hints gives the browser a 100-500 ms head start on critical resources before HTML even arrives. Subresource Integrity and CSP secure the delivery against CDN compromise. Together these form the senior performance layer: the difference between a theoretically correct bundle budget and one that actually delivers the performance the measurements promise.

Connected lessons
appears again in260
Continue the climb ↑Bundle budgets: multiple-choice review
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.