[{"data":1,"prerenderedAt":1282},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost":1273},{"id":4,"title":5,"body":6,"description":1254,"extension":1255,"meta":1256,"navigation":1267,"path":1268,"seo":1269,"stem":1271,"__hash__":1272},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002Findex.md","Measuring JavaScript Parse and Compile Cost",{"type":7,"value":8,"toc":1239},"minimark",[9,14,29,32,192,197,226,230,236,242,248,254,335,339,344,347,843,846,850,853,857,868,1021,1028,1032,1035,1119,1123,1126,1130,1133,1137,1163,1167,1179,1188,1197,1201,1224,1229,1232,1235],[10,11,13],"h1",{"id":12},"how-to-measure-javascript-parse-and-compile-cost-on-real-devices","How to Measure JavaScript Parse and Compile Cost on Real Devices",[15,16,17,18,23,24,28],"p",{},"This guide gives ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002F","JavaScript Performance Budgets"," their conversion factor, within ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". Budgets expressed in kilobytes are only convincing when someone can say what a kilobyte costs in milliseconds on the devices your users hold. That number is not universal: it depends on the engine, the device's CPU, whether code is cached, and what the code does when it is evaluated.",[15,30,31],{},"Modern engines are fast at parsing — V8 parses lazily, compiles in the background where it can, and caches compiled code for repeat visits — so the cost per kilobyte has fallen over the years. But on a mid-tier phone, cold-loading a few hundred kilobytes of JavaScript still costs on the order of 100–300ms of main-thread time before any application logic runs, and that time sits directly in Total Blocking Time and in the input delay of the first interactions.",[15,33,34],{},[35,36,42,43,42,50,42,54,42,57,42,66,42,72,42,83,42,88,42,97,42,104,42,109,42,113,42,119,42,123,42,127,42,131,42,136,42,142,42,145,42,149,42,153,42,157,42,161,42,165,42,169,42,173,42,177,42,183,42,188,42],"svg",{"viewBox":37,"width":38,"role":39,"ariaLabel":40,"style":41},"0 0 760 206","100%","img","Main-thread timeline of compiling, evaluating and executing a large bundle on a mid-tier phone, compared with the 50 millisecond long-task line.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[44,45],"rect",{"className":46,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],"svg-canvas","0","#ffffff",[51,52,53],"title",{},"Loading one 420KB (uncompressed) bundle on a mid-tier phone, cold cache",[55,56,40],"desc",{},[44,58],{"x":59,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"1","758","204","10","none","currentColor","stroke-opacity:0.18",[67,68,53],"text",{"x":69,"y":70,"fill":64,"style":71},"28.0","34.0","font-size:16px;font-weight:700",[73,74],"line",{"x1":75,"y1":76,"x2":75,"y2":77,"stroke":78,"strokeWidth":79,"strokeDashArray":80,"style":82},"186.7","72.0","118.0","#b8860b","1.5",[81,81],"4","stroke-opacity:0.9",[67,84,87],{"x":69,"y":85,"fill":64,"style":86},"96.0","font-size:12.5px;font-weight:700","Main thread",[44,89],{"x":90,"y":91,"width":92,"height":93,"rx":94,"fill":95,"stroke":95,"style":96},"120.0","78.0","126.6","26.0","3","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[67,98,103],{"x":99,"y":100,"fill":64,"style":101,"textAnchor":102},"183.3","95.5","font-size:11.5px","middle","compile (eager)",[44,105],{"x":106,"y":91,"width":107,"height":93,"rx":94,"fill":64,"stroke":64,"style":108},"248.1","106.4","fill-opacity:0.06;stroke-opacity:0.4",[67,110,112],{"x":111,"y":100,"fill":64,"style":101,"textAnchor":102},"301.3","evaluate modules",[44,114],{"x":115,"y":91,"width":116,"height":93,"rx":94,"fill":117,"stroke":78,"style":118},"356.0","153.6","#ffc300","fill-opacity:0.24;stroke-opacity:0.9",[67,120,122],{"x":121,"y":100,"fill":64,"style":101,"textAnchor":102},"432.7","lazy compile on call",[44,124],{"x":125,"y":91,"width":126,"height":93,"rx":94,"fill":95,"stroke":95,"style":96},"511.0","173.8",[67,128,130],{"x":129,"y":100,"fill":64,"style":101,"textAnchor":102},"597.9","app startup",[73,132],{"x1":133,"y1":77,"x2":134,"y2":77,"stroke":64,"style":135},"119.3","726.0","stroke-opacity:0.4",[67,137,141],{"x":138,"y":139,"fill":140,"style":101,"textAnchor":102},"131.2","135.0","#51617a","0ms",[67,143,144],{"x":75,"y":139,"fill":140,"style":101,"textAnchor":102},"50ms",[67,146,148],{"x":147,"y":139,"fill":140,"style":101,"textAnchor":102},"254.1","100ms",[67,150,152],{"x":151,"y":139,"fill":140,"style":101,"textAnchor":102},"321.5","150ms",[67,154,156],{"x":155,"y":139,"fill":140,"style":101,"textAnchor":102},"388.9","200ms",[67,158,160],{"x":159,"y":139,"fill":140,"style":101,"textAnchor":102},"456.3","250ms",[67,162,164],{"x":163,"y":139,"fill":140,"style":101,"textAnchor":102},"523.8","300ms",[67,166,168],{"x":167,"y":139,"fill":140,"style":101,"textAnchor":102},"591.2","350ms",[67,170,172],{"x":171,"y":139,"fill":140,"style":101,"textAnchor":102},"658.6","400ms",[67,174,176],{"x":175,"y":139,"fill":140,"style":101,"textAnchor":102},"713.3","450ms",[67,178,182],{"x":75,"y":179,"fill":180,"style":181,"textAnchor":102},"68.0","#8a6608","font-size:12px;font-weight:700","50ms long-task line",[67,184,187],{"x":69,"y":185,"fill":140,"style":186},"166.0","font-size:12.5px","Lazy compilation moves some cost to first call, which is why startup functions appear slower in profiles than their",[67,189,191],{"x":69,"y":190,"fill":140,"style":186},"184.0","logic suggests.",[193,194,196],"h2",{"id":195},"rapid-diagnosis","Rapid Diagnosis",[198,199,200,208,214,220],"ul",{},[201,202,203,207],"li",{},[204,205,206],"strong",{},"Record a throttled, cold-cache trace."," DevTools Performance panel, 4x CPU, \"Disable cache\" checked. In Bottom-Up, group by Activity and look at \"Compile Script\", \"Compile Code\", \"Evaluate Script\" and \"Parse HTML\" totals.",[201,209,210,213],{},[204,211,212],{},"Compare cold and warm loads."," Reload without disabling the cache; V8's code cache should cut compile time substantially on the second load. If it does not, scripts may be changing between loads (inline scripts with dynamic content, unique query strings).",[201,215,216,219],{},[204,217,218],{},"Look at which scripts dominate."," Group Bottom-Up by URL; vendor chunks and polyfills are frequent leaders.",[201,221,222,225],{},[204,223,224],{},"Profile on a real device"," at least once. Remote debugging an Android phone over USB gives true numbers that throttling only approximates.",[193,227,229],{"id":228},"root-cause-analysis","Root Cause Analysis",[15,231,232,235],{},[204,233,234],{},"1. Size on the critical path."," Compile time scales roughly with the amount of code compiled at startup, which depends on uncompressed size and how much of it runs immediately.",[15,237,238,241],{},[204,239,240],{},"2. Eager top-level code."," Modules that do work when evaluated — building lookup tables, registering components, configuring SDKs — force compilation and execution at load, regardless of whether the result is used soon.",[15,243,244,247],{},[204,245,246],{},"3. Cache misses."," V8's code cache keys on the script URL and content. Changing hashes on every deploy (for unchanged code) or injecting per-request content into scripts defeats it, forcing full compilation on repeat visits.",[15,249,250,253],{},[204,251,252],{},"4. Low-end CPUs."," The same code compiles three to five times slower on a budget phone than a laptop. Desktop measurements consistently understate the problem.",[15,255,256],{},[35,257,42,260,42,263,42,266,42,268,42,271,42,273,42,278,42,285,42,291,42,296,42,300,42,305,42,309,42,313,42,317,42,321,42,325,42,329,42,333,42],{"viewBox":258,"width":38,"role":39,"ariaLabel":259,"style":41},"0 0 760 216","Bar chart of compile and evaluate time for one bundle across four device classes.",[44,261],{"className":262,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,264,265],{},"Compile + evaluate time for the same bundle by device (cold)",[55,267,259],{},[44,269],{"x":59,"y":59,"width":60,"height":270,"rx":62,"fill":63,"stroke":64,"style":65},"214",[67,272,265],{"x":69,"y":70,"fill":64,"style":71},[73,274],{"x1":275,"y1":76,"x2":275,"y2":276,"stroke":78,"strokeWidth":79,"strokeDashArray":277,"style":82},"217.6","194.0",[81,81],[67,279,284],{"x":280,"y":281,"fill":64,"style":282,"textAnchor":283},"127.9","92.0","font-size:13px","end","Desktop laptop",[44,286],{"x":287,"y":91,"width":288,"height":289,"rx":94,"fill":95,"stroke":95,"style":290},"139.9","74.5","19","fill-opacity:0.55;stroke-opacity:0.9",[67,292,295],{"x":293,"y":281,"fill":64,"style":294},"220.5","font-size:12px;font-weight:600","48ms",[67,297,299],{"x":280,"y":298,"fill":64,"style":282,"textAnchor":283},"123.0","Flagship phone",[44,301],{"x":287,"y":302,"width":303,"height":289,"rx":94,"fill":117,"stroke":78,"style":304},"109.0","111.8","fill-opacity:0.7;stroke-opacity:0.9",[67,306,308],{"x":307,"y":298,"fill":64,"style":294},"257.8","72ms",[67,310,312],{"x":280,"y":311,"fill":64,"style":282,"textAnchor":283},"154.0","Mid-tier Android",[44,314],{"x":287,"y":315,"width":316,"height":289,"rx":94,"fill":117,"stroke":78,"style":304},"140.0","271.8",[67,318,320],{"x":319,"y":311,"fill":64,"style":294},"417.7","175ms",[67,322,324],{"x":280,"y":323,"fill":64,"style":282,"textAnchor":283},"185.0","Low-end Android",[44,326],{"x":287,"y":327,"width":328,"height":289,"rx":94,"fill":117,"stroke":78,"style":304},"171.0","528.1",[67,330,332],{"x":331,"y":323,"fill":64,"style":294},"674.0","340ms",[67,334,144],{"x":275,"y":179,"fill":180,"style":181,"textAnchor":102},[193,336,338],{"id":337},"step-by-step-measurement","Step-by-Step Measurement",[340,341,343],"h3",{"id":342},"_1-measure-in-the-lab-with-tracing","1. Measure in the lab with tracing",[15,345,346],{},"Use Puppeteer to capture a trace with the relevant categories and sum compile and evaluate durations per script.",[348,349,354],"pre",{"className":350,"code":351,"language":352,"meta":353,"style":353},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F scripts\u002Fjs-cost.mjs — cold-load compile\u002Fevaluate cost per script URL.\nimport puppeteer from 'puppeteer';\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\nconst cdp = await page.createCDPSession();\nawait cdp.send('Emulation.setCPUThrottlingRate', { rate: 4 });\nawait page.setCacheEnabled(false);\nawait page.tracing.start({ categories: ['devtools.timeline', 'v8', 'disabled-by-default-v8.compile'] });\nawait page.goto(process.argv[2], { waitUntil: 'networkidle0' });\nconst trace = JSON.parse(await page.tracing.stop());\nconst byUrl = {};\nfor (const e of trace.traceEvents) {\n  if (!['v8.compile', 'EvaluateScript', 'v8.compileModule', 'v8.evaluateModule'].includes(e.name) || !e.dur) continue;\n  const url = e.args?.data?.url || e.args?.fileName || '(unknown)';\n  byUrl[url] = (byUrl[url] ?? 0) + e.dur \u002F 1000;\n}\nconsole.table(Object.entries(byUrl).sort((a, b) => b[1] - a[1]).slice(0, 10));\nawait browser.close();\n\u002F\u002F trace event names differ slightly between Chrome versions — check them in a\n\u002F\u002F recorded trace if totals come out empty.\n\u002F\u002F trade-off: CPU throttling scales main-thread work but not background\n\u002F\u002F compilation threads equally, so throttled lab numbers are approximations.\n","javascript","",[355,356,357,365,386,412,432,452,478,496,527,551,582,595,615,670,696,731,737,807,819,825,831,837],"code",{"__ignoreMap":353},[358,359,361],"span",{"class":73,"line":360},1,[358,362,364],{"class":363},"sjfSM","\u002F\u002F scripts\u002Fjs-cost.mjs — cold-load compile\u002Fevaluate cost per script URL.\n",[358,366,368,372,376,379,383],{"class":73,"line":367},2,[358,369,371],{"class":370},"sPARh","import",[358,373,375],{"class":374},"saISM"," puppeteer ",[358,377,378],{"class":370},"from",[358,380,382],{"class":381},"sZ8jY"," 'puppeteer'",[358,384,385],{"class":374},";\n",[358,387,389,392,396,399,402,405,409],{"class":73,"line":388},3,[358,390,391],{"class":370},"const",[358,393,395],{"class":394},"sPXB4"," browser",[358,397,398],{"class":370}," =",[358,400,401],{"class":370}," await",[358,403,404],{"class":374}," puppeteer.",[358,406,408],{"class":407},"smZ65","launch",[358,410,411],{"class":374},"();\n",[358,413,415,417,420,422,424,427,430],{"class":73,"line":414},4,[358,416,391],{"class":370},[358,418,419],{"class":394}," page",[358,421,398],{"class":370},[358,423,401],{"class":370},[358,425,426],{"class":374}," browser.",[358,428,429],{"class":407},"newPage",[358,431,411],{"class":374},[358,433,435,437,440,442,444,447,450],{"class":73,"line":434},5,[358,436,391],{"class":370},[358,438,439],{"class":394}," cdp",[358,441,398],{"class":370},[358,443,401],{"class":370},[358,445,446],{"class":374}," page.",[358,448,449],{"class":407},"createCDPSession",[358,451,411],{"class":374},[358,453,455,458,461,464,467,470,473,475],{"class":73,"line":454},6,[358,456,457],{"class":370},"await",[358,459,460],{"class":374}," cdp.",[358,462,463],{"class":407},"send",[358,465,466],{"class":374},"(",[358,468,469],{"class":381},"'Emulation.setCPUThrottlingRate'",[358,471,472],{"class":374},", { rate: ",[358,474,81],{"class":394},[358,476,477],{"class":374}," });\n",[358,479,481,483,485,488,490,493],{"class":73,"line":480},7,[358,482,457],{"class":370},[358,484,446],{"class":374},[358,486,487],{"class":407},"setCacheEnabled",[358,489,466],{"class":374},[358,491,492],{"class":394},"false",[358,494,495],{"class":374},");\n",[358,497,499,501,504,507,510,513,516,519,521,524],{"class":73,"line":498},8,[358,500,457],{"class":370},[358,502,503],{"class":374}," page.tracing.",[358,505,506],{"class":407},"start",[358,508,509],{"class":374},"({ categories: [",[358,511,512],{"class":381},"'devtools.timeline'",[358,514,515],{"class":374},", ",[358,517,518],{"class":381},"'v8'",[358,520,515],{"class":374},[358,522,523],{"class":381},"'disabled-by-default-v8.compile'",[358,525,526],{"class":374},"] });\n",[358,528,530,532,534,537,540,543,546,549],{"class":73,"line":529},9,[358,531,457],{"class":370},[358,533,446],{"class":374},[358,535,536],{"class":407},"goto",[358,538,539],{"class":374},"(process.argv[",[358,541,542],{"class":394},"2",[358,544,545],{"class":374},"], { waitUntil: ",[358,547,548],{"class":381},"'networkidle0'",[358,550,477],{"class":374},[358,552,554,556,559,561,564,567,570,572,574,576,579],{"class":73,"line":553},10,[358,555,391],{"class":370},[358,557,558],{"class":394}," trace",[358,560,398],{"class":370},[358,562,563],{"class":394}," JSON",[358,565,566],{"class":374},".",[358,568,569],{"class":407},"parse",[358,571,466],{"class":374},[358,573,457],{"class":370},[358,575,503],{"class":374},[358,577,578],{"class":407},"stop",[358,580,581],{"class":374},"());\n",[358,583,585,587,590,592],{"class":73,"line":584},11,[358,586,391],{"class":370},[358,588,589],{"class":394}," byUrl",[358,591,398],{"class":370},[358,593,594],{"class":374}," {};\n",[358,596,598,601,604,606,609,612],{"class":73,"line":597},12,[358,599,600],{"class":370},"for",[358,602,603],{"class":374}," (",[358,605,391],{"class":370},[358,607,608],{"class":394}," e",[358,610,611],{"class":370}," of",[358,613,614],{"class":374}," trace.traceEvents) {\n",[358,616,618,621,623,626,629,632,634,637,639,642,644,647,650,653,656,659,662,665,668],{"class":73,"line":617},13,[358,619,620],{"class":370},"  if",[358,622,603],{"class":374},[358,624,625],{"class":370},"!",[358,627,628],{"class":374},"[",[358,630,631],{"class":381},"'v8.compile'",[358,633,515],{"class":374},[358,635,636],{"class":381},"'EvaluateScript'",[358,638,515],{"class":374},[358,640,641],{"class":381},"'v8.compileModule'",[358,643,515],{"class":374},[358,645,646],{"class":381},"'v8.evaluateModule'",[358,648,649],{"class":374},"].",[358,651,652],{"class":407},"includes",[358,654,655],{"class":374},"(e.name) ",[358,657,658],{"class":370},"||",[358,660,661],{"class":370}," !",[358,663,664],{"class":374},"e.dur) ",[358,666,667],{"class":370},"continue",[358,669,385],{"class":374},[358,671,673,676,679,681,684,686,689,691,694],{"class":73,"line":672},14,[358,674,675],{"class":370},"  const",[358,677,678],{"class":394}," url",[358,680,398],{"class":370},[358,682,683],{"class":374}," e.args?.data?.url ",[358,685,658],{"class":370},[358,687,688],{"class":374}," e.args?.fileName ",[358,690,658],{"class":370},[358,692,693],{"class":381}," '(unknown)'",[358,695,385],{"class":374},[358,697,699,702,705,708,711,714,717,720,723,726,729],{"class":73,"line":698},15,[358,700,701],{"class":374},"  byUrl[url] ",[358,703,704],{"class":370},"=",[358,706,707],{"class":374}," (byUrl[url] ",[358,709,710],{"class":370},"??",[358,712,713],{"class":394}," 0",[358,715,716],{"class":374},") ",[358,718,719],{"class":370},"+",[358,721,722],{"class":374}," e.dur ",[358,724,725],{"class":370},"\u002F",[358,727,728],{"class":394}," 1000",[358,730,385],{"class":374},[358,732,734],{"class":73,"line":733},16,[358,735,736],{"class":374},"}\n",[358,738,740,743,746,749,752,755,758,761,764,766,769,771,774,777,779,782,785,788,790,793,796,798,800,802,804],{"class":73,"line":739},17,[358,741,742],{"class":374},"console.",[358,744,745],{"class":407},"table",[358,747,748],{"class":374},"(Object.",[358,750,751],{"class":407},"entries",[358,753,754],{"class":374},"(byUrl).",[358,756,757],{"class":407},"sort",[358,759,760],{"class":374},"((",[358,762,19],{"class":763},"sQw3B",[358,765,515],{"class":374},[358,767,768],{"class":763},"b",[358,770,716],{"class":374},[358,772,773],{"class":370},"=>",[358,775,776],{"class":374}," b[",[358,778,59],{"class":394},[358,780,781],{"class":374},"] ",[358,783,784],{"class":370},"-",[358,786,787],{"class":374}," a[",[358,789,59],{"class":394},[358,791,792],{"class":374},"]).",[358,794,795],{"class":407},"slice",[358,797,466],{"class":374},[358,799,48],{"class":394},[358,801,515],{"class":374},[358,803,62],{"class":394},[358,805,806],{"class":374},"));\n",[358,808,810,812,814,817],{"class":73,"line":809},18,[358,811,457],{"class":370},[358,813,426],{"class":374},[358,815,816],{"class":407},"close",[358,818,411],{"class":374},[358,820,822],{"class":73,"line":821},19,[358,823,824],{"class":363},"\u002F\u002F trace event names differ slightly between Chrome versions — check them in a\n",[358,826,828],{"class":73,"line":827},20,[358,829,830],{"class":363},"\u002F\u002F recorded trace if totals come out empty.\n",[358,832,834],{"class":73,"line":833},21,[358,835,836],{"class":363},"\u002F\u002F trade-off: CPU throttling scales main-thread work but not background\n",[358,838,840],{"class":73,"line":839},22,[358,841,842],{"class":363},"\u002F\u002F compilation threads equally, so throttled lab numbers are approximations.\n",[15,844,845],{},"Expected outcome: a ranked list of scripts by compile and evaluate milliseconds under throttling.",[340,847,849],{"id":848},"_2-derive-your-bytes-to-milliseconds-factor","2. Derive your bytes-to-milliseconds factor",[15,851,852],{},"Divide each script's compile + evaluate time by its uncompressed size. The median across your bundles is your project's conversion factor for budgets — for example \"about 0.4ms per KB on our mid-tier profile\".",[340,854,856],{"id":855},"_3-measure-in-the-field-with-long-animation-frames","3. Measure in the field with Long Animation Frames",[15,858,859,860,863,864,867],{},"LoAF script entries report ",[355,861,862],{},"invokerType: 'classic-script'"," or ",[355,865,866],{},"'module-script'"," for script evaluation, with durations. Summing them during load in RUM gives field evaluation cost per script URL on real devices.",[348,869,871],{"className":350,"code":870,"language":352,"meta":353,"style":353},"new PerformanceObserver((list) => {\n  for (const f of list.getEntries()) for (const s of f.scripts) {\n    if (s.invokerType === 'classic-script' || s.invokerType === 'module-script') {\n      evalCost[s.sourceURL] = (evalCost[s.sourceURL] ?? 0) + s.duration;\n    }\n  }\n}).observe({ type: 'long-animation-frame', buffered: true });\n\u002F\u002F trade-off: LoAF reports only scripts within long frames (over 50ms), so short\n\u002F\u002F evaluations are omitted. The data shows the worst offenders, not a full total.\n",[355,872,873,893,930,958,979,984,989,1011,1016],{"__ignoreMap":353},[358,874,875,878,881,883,886,888,890],{"class":73,"line":360},[358,876,877],{"class":370},"new",[358,879,880],{"class":407}," PerformanceObserver",[358,882,760],{"class":374},[358,884,885],{"class":763},"list",[358,887,716],{"class":374},[358,889,773],{"class":370},[358,891,892],{"class":374}," {\n",[358,894,895,898,900,902,905,907,910,913,916,918,920,922,925,927],{"class":73,"line":367},[358,896,897],{"class":370},"  for",[358,899,603],{"class":374},[358,901,391],{"class":370},[358,903,904],{"class":394}," f",[358,906,611],{"class":370},[358,908,909],{"class":374}," list.",[358,911,912],{"class":407},"getEntries",[358,914,915],{"class":374},"()) ",[358,917,600],{"class":370},[358,919,603],{"class":374},[358,921,391],{"class":370},[358,923,924],{"class":394}," s",[358,926,611],{"class":370},[358,928,929],{"class":374}," f.scripts) {\n",[358,931,932,935,938,941,944,947,950,952,955],{"class":73,"line":388},[358,933,934],{"class":370},"    if",[358,936,937],{"class":374}," (s.invokerType ",[358,939,940],{"class":370},"===",[358,942,943],{"class":381}," 'classic-script'",[358,945,946],{"class":370}," ||",[358,948,949],{"class":374}," s.invokerType ",[358,951,940],{"class":370},[358,953,954],{"class":381}," 'module-script'",[358,956,957],{"class":374},") {\n",[358,959,960,963,965,968,970,972,974,976],{"class":73,"line":414},[358,961,962],{"class":374},"      evalCost[s.sourceURL] ",[358,964,704],{"class":370},[358,966,967],{"class":374}," (evalCost[s.sourceURL] ",[358,969,710],{"class":370},[358,971,713],{"class":394},[358,973,716],{"class":374},[358,975,719],{"class":370},[358,977,978],{"class":374}," s.duration;\n",[358,980,981],{"class":73,"line":434},[358,982,983],{"class":374},"    }\n",[358,985,986],{"class":73,"line":454},[358,987,988],{"class":374},"  }\n",[358,990,991,994,997,1000,1003,1006,1009],{"class":73,"line":480},[358,992,993],{"class":374},"}).",[358,995,996],{"class":407},"observe",[358,998,999],{"class":374},"({ type: ",[358,1001,1002],{"class":381},"'long-animation-frame'",[358,1004,1005],{"class":374},", buffered: ",[358,1007,1008],{"class":394},"true",[358,1010,477],{"class":374},[358,1012,1013],{"class":73,"line":498},[358,1014,1015],{"class":363},"\u002F\u002F trade-off: LoAF reports only scripts within long frames (over 50ms), so short\n",[358,1017,1018],{"class":73,"line":529},[358,1019,1020],{"class":363},"\u002F\u002F evaluations are omitted. The data shows the worst offenders, not a full total.\n",[15,1022,1023,1024,566],{},"Expected outcome: field evidence of which scripts cost the most to evaluate on real hardware — see ",[19,1025,1027],{"href":1026},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Ffinding-slow-scripts-with-loaf-script-attribution\u002F","finding slow scripts with LoAF script attribution",[340,1029,1031],{"id":1030},"_4-check-code-caching-on-repeat-visits","4. Check code caching on repeat visits",[15,1033,1034],{},"Compare cold and warm traces. V8 caches compiled code for scripts loaded more than once with identical content; module scripts and service-worker-cached scripts get more aggressive caching. If warm compile time is close to cold, investigate cache-busting.",[15,1036,1037],{},[35,1038,42,1041,42,1044,42,1047,42,1049,42,1052,42,1054,42,1060,42,1066,42,1070,42,1073,42,1076,42,1079,42,1082,42,1085,42,1088,42,1091,42,1094,42,1098,42,1100,42,1104,42,1106,42,1109,42,1111,42,1114,42,1116,42],{"viewBox":1039,"width":38,"role":39,"ariaLabel":1040,"style":41},"0 0 760 228","Comparison of compile and evaluate costs on a first visit versus a repeat visit with V8 code caching.",[44,1042],{"className":1043,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,1045,1046],{},"Cold vs warm load of the same bundle",[55,1048,1040],{},[44,1050],{"x":59,"y":59,"width":60,"height":1051,"rx":62,"fill":63,"stroke":64,"style":65},"226",[67,1053,1046],{"x":69,"y":70,"fill":64,"style":71},[44,1055],{"x":69,"y":1056,"width":1057,"height":1058,"rx":1059,"fill":117,"stroke":78,"style":118},"56.0","340.0","150.0","6",[67,1061,1065],{"x":1062,"y":1063,"fill":64,"style":1064},"42.0","82.0","font-size:14px;font-weight:700","Cold (first visit)",[67,1067,1069],{"x":1062,"y":1068,"fill":64,"style":86},"108.0","•",[67,1071,1072],{"x":1056,"y":1068,"fill":64,"style":186,"textAnchor":506},"Full download",[67,1074,1069],{"x":1062,"y":1075,"fill":64,"style":86},"132.0",[67,1077,1078],{"x":1056,"y":1075,"fill":64,"style":186,"textAnchor":506},"Full parse and compile",[67,1080,1069],{"x":1062,"y":1081,"fill":64,"style":86},"156.0",[67,1083,1084],{"x":1056,"y":1081,"fill":64,"style":186,"textAnchor":506},"Evaluate all modules",[67,1086,1069],{"x":1062,"y":1087,"fill":64,"style":86},"180.0",[67,1089,1090],{"x":1056,"y":1087,"fill":64,"style":186,"textAnchor":506},"~175ms on mid-tier phone",[44,1092],{"x":1093,"y":1056,"width":1057,"height":1058,"rx":1059,"fill":95,"stroke":95,"style":96},"392.0",[67,1095,1097],{"x":1096,"y":1063,"fill":64,"style":1064},"406.0","Warm (code cache hit)",[67,1099,1069],{"x":1096,"y":1068,"fill":64,"style":86},[67,1101,1103],{"x":1102,"y":1068,"fill":64,"style":186,"textAnchor":506},"420.0","From HTTP cache",[67,1105,1069],{"x":1096,"y":1075,"fill":64,"style":86},[67,1107,1108],{"x":1102,"y":1075,"fill":64,"style":186,"textAnchor":506},"Compiled code reused",[67,1110,1069],{"x":1096,"y":1081,"fill":64,"style":86},[67,1112,1113],{"x":1102,"y":1081,"fill":64,"style":186,"textAnchor":506},"Evaluate still runs",[67,1115,1069],{"x":1096,"y":1087,"fill":64,"style":86},[67,1117,1118],{"x":1102,"y":1087,"fill":64,"style":186,"textAnchor":506},"~80ms on mid-tier phone",[193,1120,1122],{"id":1121},"verification","Verification",[15,1124,1125],{},"Track compile + evaluate time for your top routes as a lab metric over time, alongside bundle size. The two should move together; when size falls but time does not, look for eager top-level code. After optimisations, confirm field evaluation cost (from LoAF data) falls for the affected scripts, and that INP for interactions in the first seconds improves.",[193,1127,1129],{"id":1128},"worked-example-same-size-different-cost","Worked Example: Same Size, Different Cost",[15,1131,1132],{},"Two chunks of nearly identical size (about 120KB uncompressed each) appeared in a trace with very different costs: 22ms and 94ms of compile + evaluate on the mid-tier profile. The cheaper one was mostly function definitions — compiled lazily, executed later on demand. The expensive one was a configuration module that, at evaluation time, built a large object of validation schemas and ran them once to \"warm up\". Making schema construction lazy (built on first use) cut the module's startup cost to 18ms without changing its size. Budgets in bytes would never have found it; the per-script timing did.",[193,1134,1136],{"id":1135},"common-mistakes","Common Mistakes",[198,1138,1139,1145,1151,1157],{},[201,1140,1141,1144],{},[204,1142,1143],{},"Measuring on a developer laptop without throttling."," The numbers will look negligible and mislead every decision.",[201,1146,1147,1150],{},[204,1148,1149],{},"Measuring only with warm caches."," First visits from search and ads are cold, and they are the visits Core Web Vitals most often fail on.",[201,1152,1153,1156],{},[204,1154,1155],{},"Treating compressed size as the cost driver."," Compile time follows uncompressed size and code structure, not gzip output.",[201,1158,1159,1162],{},[204,1160,1161],{},"Ignoring evaluation."," Top-level side effects can cost more than compilation; profile what modules do when imported.",[193,1164,1166],{"id":1165},"faq","FAQ",[1168,1169,1172,1176],"details",{"className":1170},[1171],"faq-item",[1173,1174,1175],"summary",{},"Does V8's lazy parsing make bundle size irrelevant?",[15,1177,1178],{},"No. Lazy parsing defers full compilation of function bodies until they are called, which helps, but the engine still pre-parses all code to find function boundaries and syntax errors, and code that runs at startup is compiled anyway. Smaller bundles still load faster; lazy parsing only reduces the penalty for code that is shipped but not run.",[1168,1180,1182,1185],{"className":1181},[1171],[1173,1183,1184],{},"Is WebAssembly cheaper to compile than JavaScript?",[15,1186,1187],{},"Wasm is designed for fast, streaming compilation and is typically cheaper per byte to compile than JavaScript, though modules are often large. It is not a general replacement; it pays off for compute-heavy libraries (codecs, image processing), not for UI code.",[1168,1189,1191,1194],{"className":1190},[1171],[1173,1192,1193],{},"Do Safari and Firefox have similar costs?",[15,1195,1196],{},"The shape is similar — parse, compile, evaluate, with caching for repeat visits — but absolute numbers differ by engine and device. Apple devices generally have fast CPUs, so Safari users rarely sit at the slow end of your distribution. Measure Chromium on mid-tier Android for the pessimistic case.",[193,1198,1200],{"id":1199},"related","Related",[198,1202,1203,1210,1217],{},[201,1204,1205,1209],{},[19,1206,1208],{"href":1207},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fwhy-compressed-size-is-the-wrong-budget\u002F","Why compressed size is the wrong budget"," — the budgeting conclusion from these measurements.",[201,1211,1212,1216],{},[19,1213,1215],{"href":1214},"\u002Fcore-web-vitals-measurement\u002Foptimizing-first-input-delay-fid\u002Freducing-total-blocking-time-in-lighthouse\u002F","Reducing Total Blocking Time in Lighthouse"," — where compile and evaluate cost shows up in the lab.",[201,1218,1219,1223],{},[19,1220,1222],{"href":1221},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Fauditing-core-js-polyfill-weight\u002F","Auditing core-js polyfill weight"," — a common source of avoidable compile time.",[1225,1226,1228],"script",{"type":1227},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Measure JavaScript Parse and Compile Cost on Real Devices\",\n  \"description\": \"Measure the CPU cost of loading your JavaScript — parse, compile and evaluate — on the devices that matter, and use it to justify budgets.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Measure in the lab with tracing\",\n      \"text\": \"Use Puppeteer to capture a trace with the relevant categories and sum compile and evaluate durations per script.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Derive your bytes-to-milliseconds factor\",\n      \"text\": \"Divide each script's compile + evaluate time by its uncompressed size.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Measure in the field with Long Animation Frames\",\n      \"text\": \"LoAF script entries report invokerType: 'classic-script' or 'module-script' for script evaluation, with durations.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Check code caching on repeat visits\",\n      \"text\": \"Compare cold and warm traces.\"\n    }\n  ]\n}\n",[1225,1230,1231],{"type":1227},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Measure JavaScript Parse and Compile Cost on Real Devices\",\n  \"description\": \"Measure the CPU cost of loading your JavaScript — parse, compile and evaluate — on the devices that matter, and use it to justify budgets.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002F\"\n  }\n}\n",[1225,1233,1234],{"type":1227},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"JavaScript Bundle Optimization & Code Splitting\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"JavaScript Performance Budgets\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Measuring JavaScript Parse and Compile Cost\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002F\"\n    }\n  ]\n}\n",[1236,1237,1238],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":353,"searchDepth":367,"depth":367,"links":1240},[1241,1242,1243,1249,1250,1251,1252,1253],{"id":195,"depth":367,"text":196},{"id":228,"depth":367,"text":229},{"id":337,"depth":367,"text":338,"children":1244},[1245,1246,1247,1248],{"id":342,"depth":388,"text":343},{"id":848,"depth":388,"text":849},{"id":855,"depth":388,"text":856},{"id":1030,"depth":388,"text":1031},{"id":1121,"depth":367,"text":1122},{"id":1128,"depth":367,"text":1129},{"id":1135,"depth":367,"text":1136},{"id":1165,"depth":367,"text":1166},{"id":1199,"depth":367,"text":1200},"Measure the CPU cost of loading your JavaScript — parse, compile and evaluate — on the devices that matter, and use it to justify budgets.","md",{"slug":1257,"type":1258,"breadcrumb":1259,"datePublished":1266,"dateModified":1266},"measuring-javascript-parse-and-compile-cost","article",[1260,1262,1263,1264],{"name":1261,"url":725},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1265},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002F","2026-10-06",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost",{"title":5,"description":1270},"Measure how long your bundles take to parse, compile and evaluate on real devices with DevTools, tracing and RUM, and turn bytes into milliseconds for budgets.","javascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002Findex","YfPIrgEZknqrKZ0fp6fzHyfv2T7gmssFGH-LB5WYZ1M",[1274,1278],{"title":1275,"path":1276,"stem":1277},"Enforcing Bundle Budgets with size-limit","\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fenforcing-bundle-budgets-with-size-limit","javascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fenforcing-bundle-budgets-with-size-limit\u002Findex",{"title":1279,"path":1280,"stem":1281},"Tracking Bundle Size per Pull Request","\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Ftracking-bundle-size-per-pull-request","javascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Ftracking-bundle-size-per-pull-request\u002Findex",1791308079074]