[{"data":1,"prerenderedAt":2252},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fit\u002Ftech\u002Fperformance-budget-decisioning":13},{"i18nKey":4,"paths":5},"tech-004-2026-07",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Ftech\u002Fweb-performance-budgets-entscheidungsmechanismus","\u002Fen\u002Ftech\u002Fweb-performance-budgets-decision-framework","\u002Fes\u002Ftech\u002Fpresupuestos-de-rendimiento-web","\u002Ffr\u002Ftech\u002Fbudgets-de-performance-web-mecanismes-de-decision","\u002Fit\u002Ftech\u002Fperformance-budget-decisioning","\u002Fru\u002Ftech\u002Fbudzhety-veb-proizvoditelnosti-svyazyvanie-s-mekhanizmom-prinyatiya-resheniy","\u002Ftr\u002Ftech\u002Fweb-performance-budgetlari-karar-mekanizmasina-baglamak",{"_path":10,"_dir":14,"_draft":15,"_partial":15,"_locale":16,"title":17,"description":18,"publishedAt":19,"modifiedAt":19,"category":14,"i18nKey":4,"tags":20,"readingTime":26,"author":27,"body":28,"_type":2246,"_id":2247,"_source":2248,"_file":2249,"_stem":2250,"_extension":2251},"tech",false,"","Performance Budget: Collegare le Metriche alle Decisioni","Lighthouse CI, RUM e alarm di regressione trasformano la performance web in KPI misurabili. Decidi con i numeri, non con le ipotesi.","2026-07-12",[21,22,23,24,25],"web-performance","lighthouse-ci","rum","core-web-vitals","devops",9,"Roibase",{"type":29,"children":30,"toc":2230},"root",[31,39,46,51,56,178,192,198,211,224,618,623,630,635,731,742,748,753,758,990,1003,1127,1132,1138,1143,1224,1269,1275,1280,1285,1540,1545,1551,1564,1601,1606,1612,1617,1622,1912,1917,1978,1983,1989,1994,1999,2005,2021,2034,2219,2224],{"type":32,"tag":33,"props":34,"children":35},"element","p",{},[36],{"type":37,"value":38},"text","La performance web non è \"dovrebbe essere buona\"—è un numero che influenza le decisioni. Nel 2026, INP (Interaction to Next Paint) che ha sostituito FID, se non rimane sotto i 200ms, il conversion rate mobile cala del 15-20% (Google Chrome UX Report 2025). Per mantenere questo livello servono controlli automatici nella pipeline CI, non previsioni. Quando configurate Lighthouse CI, RUM e sistemi di allarme di regressione, quali soglie posizionate dove? Quale metrica governa quale decisione? Questo articolo illustra l'architettura concreta per collegare il performance budget dal test al processo decisionale, con numeri reali.",{"type":32,"tag":40,"props":41,"children":43},"h2",{"id":42},"che-cosè-un-performance-budget-e-come-si-lega-al-piano-sprint",[44],{"type":37,"value":45},"Che Cos'è un Performance Budget e Come Si Lega al Piano Sprint",{"type":32,"tag":33,"props":47,"children":48},{},[49],{"type":37,"value":50},"Un performance budget è il limite massimo per il tempo di caricamento di una pagina, la dimensione del bundle e le metriche di runtime. Il bundle totale non supererà 250KB, FCP non uscirà da 1.2s, INP non supererà 200ms—questi sono i vincoli. Si definiscono all'inizio dello sprint, diventano criteri per il merge dei PR. Se una nuova feature sfonda questi limiti, o refactorizzate il codice, o rinviate la feature, oppure aggiornate il budget (accettando però la perdita di conversioni).",{"type":32,"tag":33,"props":52,"children":53},{},[54],{"type":37,"value":55},"Per definire il budget usate tre fonti: (1) le soglie Core Web Vitals di Google (LCP \u003C2.5s, INP \u003C200ms, CLS \u003C0.1), (2) il benchmark p75 dai dati RUM (se il 75% del vostro traffico sta sotto quel livello, è \"buono\"), (3) il rapporto di correlazione con le conversioni (se LCP aumenta di 100ms il tasso di conversione cala del 2%, allora spostare la soglia da 2.5s a 3s significa perdere il 10%). Il budget non è un numero solo, si divide per metrica:",{"type":32,"tag":57,"props":58,"children":59},"table",{},[60,84],{"type":32,"tag":61,"props":62,"children":63},"thead",{},[64],{"type":32,"tag":65,"props":66,"children":67},"tr",{},[68,74,79],{"type":32,"tag":69,"props":70,"children":71},"th",{},[72],{"type":37,"value":73},"Metrica",{"type":32,"tag":69,"props":75,"children":76},{},[77],{"type":37,"value":78},"Soglia",{"type":32,"tag":69,"props":80,"children":81},{},[82],{"type":37,"value":83},"Fonte",{"type":32,"tag":85,"props":86,"children":87},"tbody",{},[88,107,125,142,160],{"type":32,"tag":65,"props":89,"children":90},{},[91,97,102],{"type":32,"tag":92,"props":93,"children":94},"td",{},[95],{"type":37,"value":96},"LCP",{"type":32,"tag":92,"props":98,"children":99},{},[100],{"type":37,"value":101},"\u003C2.5s",{"type":32,"tag":92,"props":103,"children":104},{},[105],{"type":37,"value":106},"CWV ufficiale",{"type":32,"tag":65,"props":108,"children":109},{},[110,115,120],{"type":32,"tag":92,"props":111,"children":112},{},[113],{"type":37,"value":114},"INP",{"type":32,"tag":92,"props":116,"children":117},{},[118],{"type":37,"value":119},"\u003C200ms",{"type":32,"tag":92,"props":121,"children":122},{},[123],{"type":37,"value":124},"CWV 2024+",{"type":32,"tag":65,"props":126,"children":127},{},[128,133,138],{"type":32,"tag":92,"props":129,"children":130},{},[131],{"type":37,"value":132},"CLS",{"type":32,"tag":92,"props":134,"children":135},{},[136],{"type":37,"value":137},"\u003C0.1",{"type":32,"tag":92,"props":139,"children":140},{},[141],{"type":37,"value":106},{"type":32,"tag":65,"props":143,"children":144},{},[145,150,155],{"type":32,"tag":92,"props":146,"children":147},{},[148],{"type":37,"value":149},"Total JS",{"type":32,"tag":92,"props":151,"children":152},{},[153],{"type":37,"value":154},"\u003C300KB gzip",{"type":32,"tag":92,"props":156,"children":157},{},[158],{"type":37,"value":159},"HTTP Archive p75",{"type":32,"tag":65,"props":161,"children":162},{},[163,168,173],{"type":32,"tag":92,"props":164,"children":165},{},[166],{"type":37,"value":167},"FCP",{"type":32,"tag":92,"props":169,"children":170},{},[171],{"type":37,"value":172},"\u003C1.8s",{"type":32,"tag":92,"props":174,"children":175},{},[176],{"type":37,"value":177},"RUM interno",{"type":32,"tag":33,"props":179,"children":180},{},[181,183,190],{"type":37,"value":182},"Scrivete questa tabella in un file ",{"type":32,"tag":184,"props":185,"children":187},"code",{"className":186},[],[188],{"type":37,"value":189},"performance.config.json",{"type":37,"value":191},", Lighthouse CI lo legge, un violazione della soglia nei PR fallisce il merge.",{"type":32,"tag":40,"props":193,"children":195},{"id":194},"lighthouse-ci-il-criterio-di-merge-per-la-performance",[196],{"type":37,"value":197},"Lighthouse CI: Il Criterio di Merge per la Performance",{"type":32,"tag":33,"props":199,"children":200},{},[201,203,209],{"type":37,"value":202},"Lighthouse CI esegue l'audit Lighthouse su ogni PR e riporta i risultati nel log della CI (è uno strumento open source di Google). Si integra con GitHub Actions, GitLab CI, CircleCI. Flusso di base: (1) aprite un PR, (2) la CI compila, (3) il comando ",{"type":32,"tag":184,"props":204,"children":206},{"className":205},[],[207],{"type":37,"value":208},"lhci autorun",{"type":37,"value":210}," visita la pagina nell'ambiente di test, (4) confronta i punteggi Lighthouse con il budget in performance.config.json, (5) se viola una soglia il PR fallisce e il merge è bloccato.",{"type":32,"tag":33,"props":212,"children":213},{},[214,216,222],{"type":37,"value":215},"Configurazione di esempio (",{"type":32,"tag":184,"props":217,"children":219},{"className":218},[],[220],{"type":37,"value":221},".lighthouserc.json",{"type":37,"value":223},"):",{"type":32,"tag":225,"props":226,"children":230},"pre",{"className":227,"code":228,"language":229,"meta":16,"style":16},"language-json shiki shiki-themes github-dark","{\n  \"ci\": {\n    \"collect\": {\n      \"url\": [\"http:\u002F\u002Flocalhost:3000\u002F\", \"http:\u002F\u002Flocalhost:3000\u002Fproduct\u002Fsample\"],\n      \"numberOfRuns\": 3\n    },\n    \"assert\": {\n      \"preset\": \"lighthouse:no-pwa\",\n      \"assertions\": {\n        \"largest-contentful-paint\": [\"error\", {\"maxNumericValue\": 2500}],\n        \"interactive\": [\"error\", {\"maxNumericValue\": 3500}],\n        \"cumulative-layout-shift\": [\"error\", {\"maxNumericValue\": 0.1}],\n        \"total-byte-weight\": [\"warn\", {\"maxNumericValue\": 307200}]\n      }\n    },\n    \"upload\": {\n      \"target\": \"temporary-public-storage\"\n    }\n  }\n}\n","json",[231],{"type":32,"tag":184,"props":232,"children":233},{"__ignoreMap":16},[234,246,261,274,309,328,337,350,373,385,427,465,503,543,552,560,573,591,600,609],{"type":32,"tag":235,"props":236,"children":239},"span",{"class":237,"line":238},"line",1,[240],{"type":32,"tag":235,"props":241,"children":243},{"style":242},"--shiki-default:#E1E4E8",[244],{"type":37,"value":245},"{\n",{"type":32,"tag":235,"props":247,"children":249},{"class":237,"line":248},2,[250,256],{"type":32,"tag":235,"props":251,"children":253},{"style":252},"--shiki-default:#79B8FF",[254],{"type":37,"value":255},"  \"ci\"",{"type":32,"tag":235,"props":257,"children":258},{"style":242},[259],{"type":37,"value":260},": {\n",{"type":32,"tag":235,"props":262,"children":264},{"class":237,"line":263},3,[265,270],{"type":32,"tag":235,"props":266,"children":267},{"style":252},[268],{"type":37,"value":269},"    \"collect\"",{"type":32,"tag":235,"props":271,"children":272},{"style":242},[273],{"type":37,"value":260},{"type":32,"tag":235,"props":275,"children":277},{"class":237,"line":276},4,[278,283,288,294,299,304],{"type":32,"tag":235,"props":279,"children":280},{"style":252},[281],{"type":37,"value":282},"      \"url\"",{"type":32,"tag":235,"props":284,"children":285},{"style":242},[286],{"type":37,"value":287},": [",{"type":32,"tag":235,"props":289,"children":291},{"style":290},"--shiki-default:#9ECBFF",[292],{"type":37,"value":293},"\"http:\u002F\u002Flocalhost:3000\u002F\"",{"type":32,"tag":235,"props":295,"children":296},{"style":242},[297],{"type":37,"value":298},", ",{"type":32,"tag":235,"props":300,"children":301},{"style":290},[302],{"type":37,"value":303},"\"http:\u002F\u002Flocalhost:3000\u002Fproduct\u002Fsample\"",{"type":32,"tag":235,"props":305,"children":306},{"style":242},[307],{"type":37,"value":308},"],\n",{"type":32,"tag":235,"props":310,"children":312},{"class":237,"line":311},5,[313,318,323],{"type":32,"tag":235,"props":314,"children":315},{"style":252},[316],{"type":37,"value":317},"      \"numberOfRuns\"",{"type":32,"tag":235,"props":319,"children":320},{"style":242},[321],{"type":37,"value":322},": ",{"type":32,"tag":235,"props":324,"children":325},{"style":252},[326],{"type":37,"value":327},"3\n",{"type":32,"tag":235,"props":329,"children":331},{"class":237,"line":330},6,[332],{"type":32,"tag":235,"props":333,"children":334},{"style":242},[335],{"type":37,"value":336},"    },\n",{"type":32,"tag":235,"props":338,"children":340},{"class":237,"line":339},7,[341,346],{"type":32,"tag":235,"props":342,"children":343},{"style":252},[344],{"type":37,"value":345},"    \"assert\"",{"type":32,"tag":235,"props":347,"children":348},{"style":242},[349],{"type":37,"value":260},{"type":32,"tag":235,"props":351,"children":353},{"class":237,"line":352},8,[354,359,363,368],{"type":32,"tag":235,"props":355,"children":356},{"style":252},[357],{"type":37,"value":358},"      \"preset\"",{"type":32,"tag":235,"props":360,"children":361},{"style":242},[362],{"type":37,"value":322},{"type":32,"tag":235,"props":364,"children":365},{"style":290},[366],{"type":37,"value":367},"\"lighthouse:no-pwa\"",{"type":32,"tag":235,"props":369,"children":370},{"style":242},[371],{"type":37,"value":372},",\n",{"type":32,"tag":235,"props":374,"children":375},{"class":237,"line":26},[376,381],{"type":32,"tag":235,"props":377,"children":378},{"style":252},[379],{"type":37,"value":380},"      \"assertions\"",{"type":32,"tag":235,"props":382,"children":383},{"style":242},[384],{"type":37,"value":260},{"type":32,"tag":235,"props":386,"children":388},{"class":237,"line":387},10,[389,394,398,403,408,413,417,422],{"type":32,"tag":235,"props":390,"children":391},{"style":252},[392],{"type":37,"value":393},"        \"largest-contentful-paint\"",{"type":32,"tag":235,"props":395,"children":396},{"style":242},[397],{"type":37,"value":287},{"type":32,"tag":235,"props":399,"children":400},{"style":290},[401],{"type":37,"value":402},"\"error\"",{"type":32,"tag":235,"props":404,"children":405},{"style":242},[406],{"type":37,"value":407},", {",{"type":32,"tag":235,"props":409,"children":410},{"style":252},[411],{"type":37,"value":412},"\"maxNumericValue\"",{"type":32,"tag":235,"props":414,"children":415},{"style":242},[416],{"type":37,"value":322},{"type":32,"tag":235,"props":418,"children":419},{"style":252},[420],{"type":37,"value":421},"2500",{"type":32,"tag":235,"props":423,"children":424},{"style":242},[425],{"type":37,"value":426},"}],\n",{"type":32,"tag":235,"props":428,"children":430},{"class":237,"line":429},11,[431,436,440,444,448,452,456,461],{"type":32,"tag":235,"props":432,"children":433},{"style":252},[434],{"type":37,"value":435},"        \"interactive\"",{"type":32,"tag":235,"props":437,"children":438},{"style":242},[439],{"type":37,"value":287},{"type":32,"tag":235,"props":441,"children":442},{"style":290},[443],{"type":37,"value":402},{"type":32,"tag":235,"props":445,"children":446},{"style":242},[447],{"type":37,"value":407},{"type":32,"tag":235,"props":449,"children":450},{"style":252},[451],{"type":37,"value":412},{"type":32,"tag":235,"props":453,"children":454},{"style":242},[455],{"type":37,"value":322},{"type":32,"tag":235,"props":457,"children":458},{"style":252},[459],{"type":37,"value":460},"3500",{"type":32,"tag":235,"props":462,"children":463},{"style":242},[464],{"type":37,"value":426},{"type":32,"tag":235,"props":466,"children":468},{"class":237,"line":467},12,[469,474,478,482,486,490,494,499],{"type":32,"tag":235,"props":470,"children":471},{"style":252},[472],{"type":37,"value":473},"        \"cumulative-layout-shift\"",{"type":32,"tag":235,"props":475,"children":476},{"style":242},[477],{"type":37,"value":287},{"type":32,"tag":235,"props":479,"children":480},{"style":290},[481],{"type":37,"value":402},{"type":32,"tag":235,"props":483,"children":484},{"style":242},[485],{"type":37,"value":407},{"type":32,"tag":235,"props":487,"children":488},{"style":252},[489],{"type":37,"value":412},{"type":32,"tag":235,"props":491,"children":492},{"style":242},[493],{"type":37,"value":322},{"type":32,"tag":235,"props":495,"children":496},{"style":252},[497],{"type":37,"value":498},"0.1",{"type":32,"tag":235,"props":500,"children":501},{"style":242},[502],{"type":37,"value":426},{"type":32,"tag":235,"props":504,"children":506},{"class":237,"line":505},13,[507,512,516,521,525,529,533,538],{"type":32,"tag":235,"props":508,"children":509},{"style":252},[510],{"type":37,"value":511},"        \"total-byte-weight\"",{"type":32,"tag":235,"props":513,"children":514},{"style":242},[515],{"type":37,"value":287},{"type":32,"tag":235,"props":517,"children":518},{"style":290},[519],{"type":37,"value":520},"\"warn\"",{"type":32,"tag":235,"props":522,"children":523},{"style":242},[524],{"type":37,"value":407},{"type":32,"tag":235,"props":526,"children":527},{"style":252},[528],{"type":37,"value":412},{"type":32,"tag":235,"props":530,"children":531},{"style":242},[532],{"type":37,"value":322},{"type":32,"tag":235,"props":534,"children":535},{"style":252},[536],{"type":37,"value":537},"307200",{"type":32,"tag":235,"props":539,"children":540},{"style":242},[541],{"type":37,"value":542},"}]\n",{"type":32,"tag":235,"props":544,"children":546},{"class":237,"line":545},14,[547],{"type":32,"tag":235,"props":548,"children":549},{"style":242},[550],{"type":37,"value":551},"      }\n",{"type":32,"tag":235,"props":553,"children":555},{"class":237,"line":554},15,[556],{"type":32,"tag":235,"props":557,"children":558},{"style":242},[559],{"type":37,"value":336},{"type":32,"tag":235,"props":561,"children":563},{"class":237,"line":562},16,[564,569],{"type":32,"tag":235,"props":565,"children":566},{"style":252},[567],{"type":37,"value":568},"    \"upload\"",{"type":32,"tag":235,"props":570,"children":571},{"style":242},[572],{"type":37,"value":260},{"type":32,"tag":235,"props":574,"children":576},{"class":237,"line":575},17,[577,582,586],{"type":32,"tag":235,"props":578,"children":579},{"style":252},[580],{"type":37,"value":581},"      \"target\"",{"type":32,"tag":235,"props":583,"children":584},{"style":242},[585],{"type":37,"value":322},{"type":32,"tag":235,"props":587,"children":588},{"style":290},[589],{"type":37,"value":590},"\"temporary-public-storage\"\n",{"type":32,"tag":235,"props":592,"children":594},{"class":237,"line":593},18,[595],{"type":32,"tag":235,"props":596,"children":597},{"style":242},[598],{"type":37,"value":599},"    }\n",{"type":32,"tag":235,"props":601,"children":603},{"class":237,"line":602},19,[604],{"type":32,"tag":235,"props":605,"children":606},{"style":242},[607],{"type":37,"value":608},"  }\n",{"type":32,"tag":235,"props":610,"children":612},{"class":237,"line":611},20,[613],{"type":32,"tag":235,"props":614,"children":615},{"style":242},[616],{"type":37,"value":617},"}\n",{"type":32,"tag":33,"props":619,"children":620},{},[621],{"type":37,"value":622},"Questa config fa fallire il PR se LCP >2.5s, avverte se il totale byte supera i 300KB (ma consente comunque il merge). Si eseguono 3 run perché una singola run ha variance di rete alta. Il compromesso di Lighthouse CI: gira sul server dev locale, non può simulare il CDN di production. I risultati si considerano \"worst case\", in produzione di solito performano meglio ma le soglie vanno comunque rispettate.",{"type":32,"tag":624,"props":625,"children":627},"h3",{"id":626},"lighthouse-ci-vercel-preview-test-realistico-di-staging",[628],{"type":37,"value":629},"Lighthouse CI + Vercel Preview: Test Realistico di Staging",{"type":32,"tag":33,"props":631,"children":632},{},[633],{"type":37,"value":634},"Sulle piattaforme Vercel\u002FNetlify un URL di preview PR viene generato automaticamente. Se collegate Lighthouse CI a questo URL testate in un ambiente simile a production. Esempio con GitHub Actions:",{"type":32,"tag":225,"props":636,"children":640},{"className":637,"code":638,"language":639,"meta":16,"style":16},"language-yaml shiki shiki-themes github-dark","- name: Run Lighthouse CI\n  env:\n    LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_TOKEN }}\n  run: |\n    npm install -g @lhci\u002Fcli\n    lhci autorun --collect.url=${{ steps.vercel.outputs.preview-url }}\n","yaml",[641],{"type":32,"tag":184,"props":642,"children":643},{"__ignoreMap":16},[644,667,680,697,715,723],{"type":32,"tag":235,"props":645,"children":646},{"class":237,"line":238},[647,652,658,662],{"type":32,"tag":235,"props":648,"children":649},{"style":242},[650],{"type":37,"value":651},"- ",{"type":32,"tag":235,"props":653,"children":655},{"style":654},"--shiki-default:#85E89D",[656],{"type":37,"value":657},"name",{"type":32,"tag":235,"props":659,"children":660},{"style":242},[661],{"type":37,"value":322},{"type":32,"tag":235,"props":663,"children":664},{"style":290},[665],{"type":37,"value":666},"Run Lighthouse CI\n",{"type":32,"tag":235,"props":668,"children":669},{"class":237,"line":248},[670,675],{"type":32,"tag":235,"props":671,"children":672},{"style":654},[673],{"type":37,"value":674},"  env",{"type":32,"tag":235,"props":676,"children":677},{"style":242},[678],{"type":37,"value":679},":\n",{"type":32,"tag":235,"props":681,"children":682},{"class":237,"line":263},[683,688,692],{"type":32,"tag":235,"props":684,"children":685},{"style":654},[686],{"type":37,"value":687},"    LHCI_GITHUB_APP_TOKEN",{"type":32,"tag":235,"props":689,"children":690},{"style":242},[691],{"type":37,"value":322},{"type":32,"tag":235,"props":693,"children":694},{"style":290},[695],{"type":37,"value":696},"${{ secrets.LHCI_TOKEN }}\n",{"type":32,"tag":235,"props":698,"children":699},{"class":237,"line":276},[700,705,709],{"type":32,"tag":235,"props":701,"children":702},{"style":654},[703],{"type":37,"value":704},"  run",{"type":32,"tag":235,"props":706,"children":707},{"style":242},[708],{"type":37,"value":322},{"type":32,"tag":235,"props":710,"children":712},{"style":711},"--shiki-default:#F97583",[713],{"type":37,"value":714},"|\n",{"type":32,"tag":235,"props":716,"children":717},{"class":237,"line":311},[718],{"type":32,"tag":235,"props":719,"children":720},{"style":290},[721],{"type":37,"value":722},"    npm install -g @lhci\u002Fcli\n",{"type":32,"tag":235,"props":724,"children":725},{"class":237,"line":330},[726],{"type":32,"tag":235,"props":727,"children":728},{"style":290},[729],{"type":37,"value":730},"    lhci autorun --collect.url=${{ steps.vercel.outputs.preview-url }}\n",{"type":32,"tag":33,"props":732,"children":733},{},[734,740],{"type":32,"tag":184,"props":735,"children":737},{"className":736},[],[738],{"type":37,"value":739},"steps.vercel.outputs.preview-url",{"type":37,"value":741}," viene dall'action Vercel. Con questo setup testate il caching CDN, l'SSR edge, l'ottimizzazione delle immagini. Se viola una soglia il PR riceve un commento, la squadra riceve notifiche (aggiungendo webhook Slack).",{"type":32,"tag":40,"props":743,"children":745},{"id":744},"rum-calibrare-il-budget-dai-dati-dei-veri-utenti",[746],{"type":37,"value":747},"RUM: Calibrare il Budget dai Dati dei Veri Utenti",{"type":32,"tag":33,"props":749,"children":750},{},[751],{"type":37,"value":752},"Lighthouse CI è test sintetico—ambiente controllato, sempre le stesse condizioni di rete. RUM (Real User Monitoring) raccoglie metriche dai veri visitatori. La differenza è critica: Lighthouse simula 3G throttled, RUM vede il mix 4G\u002F5G\u002Ffiber; Lighthouse testa cache fredda, RUM cattura l'effetto cache dei repeat visitor. Se calibrate il budget solo su Lighthouse perdete l'esperienza reale dell'utente.",{"type":32,"tag":33,"props":754,"children":755},{},[756],{"type":37,"value":757},"Come raccoglitore RUM usate Web Vitals (la libreria ufficiale di Google). Su ogni caricamento misura le metriche CWV e invia i dati a un endpoint beacon. Implementazione di esempio:",{"type":32,"tag":225,"props":759,"children":763},{"className":760,"code":761,"language":762,"meta":16,"style":16},"language-javascript shiki shiki-themes github-dark","import {onCLS, onINP, onLCP} from 'web-vitals';\n\nfunction sendToAnalytics(metric) {\n  const body = JSON.stringify({\n    name: metric.name,\n    value: metric.value,\n    id: metric.id,\n    rating: metric.rating\n  });\n  navigator.sendBeacon('\u002Fanalytics', body);\n}\n\nonCLS(sendToAnalytics);\nonINP(sendToAnalytics);\nonLCP(sendToAnalytics);\n","javascript",[764],{"type":32,"tag":184,"props":765,"children":766},{"__ignoreMap":16},[767,795,804,834,872,880,888,896,904,912,939,946,953,966,978],{"type":32,"tag":235,"props":768,"children":769},{"class":237,"line":238},[770,775,780,785,790],{"type":32,"tag":235,"props":771,"children":772},{"style":711},[773],{"type":37,"value":774},"import",{"type":32,"tag":235,"props":776,"children":777},{"style":242},[778],{"type":37,"value":779}," {onCLS, onINP, onLCP} ",{"type":32,"tag":235,"props":781,"children":782},{"style":711},[783],{"type":37,"value":784},"from",{"type":32,"tag":235,"props":786,"children":787},{"style":290},[788],{"type":37,"value":789}," 'web-vitals'",{"type":32,"tag":235,"props":791,"children":792},{"style":242},[793],{"type":37,"value":794},";\n",{"type":32,"tag":235,"props":796,"children":797},{"class":237,"line":248},[798],{"type":32,"tag":235,"props":799,"children":801},{"emptyLinePlaceholder":800},true,[802],{"type":37,"value":803},"\n",{"type":32,"tag":235,"props":805,"children":806},{"class":237,"line":263},[807,812,818,823,829],{"type":32,"tag":235,"props":808,"children":809},{"style":711},[810],{"type":37,"value":811},"function",{"type":32,"tag":235,"props":813,"children":815},{"style":814},"--shiki-default:#B392F0",[816],{"type":37,"value":817}," sendToAnalytics",{"type":32,"tag":235,"props":819,"children":820},{"style":242},[821],{"type":37,"value":822},"(",{"type":32,"tag":235,"props":824,"children":826},{"style":825},"--shiki-default:#FFAB70",[827],{"type":37,"value":828},"metric",{"type":32,"tag":235,"props":830,"children":831},{"style":242},[832],{"type":37,"value":833},") {\n",{"type":32,"tag":235,"props":835,"children":836},{"class":237,"line":276},[837,842,847,852,857,862,867],{"type":32,"tag":235,"props":838,"children":839},{"style":711},[840],{"type":37,"value":841},"  const",{"type":32,"tag":235,"props":843,"children":844},{"style":252},[845],{"type":37,"value":846}," body",{"type":32,"tag":235,"props":848,"children":849},{"style":711},[850],{"type":37,"value":851}," =",{"type":32,"tag":235,"props":853,"children":854},{"style":252},[855],{"type":37,"value":856}," JSON",{"type":32,"tag":235,"props":858,"children":859},{"style":242},[860],{"type":37,"value":861},".",{"type":32,"tag":235,"props":863,"children":864},{"style":814},[865],{"type":37,"value":866},"stringify",{"type":32,"tag":235,"props":868,"children":869},{"style":242},[870],{"type":37,"value":871},"({\n",{"type":32,"tag":235,"props":873,"children":874},{"class":237,"line":311},[875],{"type":32,"tag":235,"props":876,"children":877},{"style":242},[878],{"type":37,"value":879},"    name: metric.name,\n",{"type":32,"tag":235,"props":881,"children":882},{"class":237,"line":330},[883],{"type":32,"tag":235,"props":884,"children":885},{"style":242},[886],{"type":37,"value":887},"    value: metric.value,\n",{"type":32,"tag":235,"props":889,"children":890},{"class":237,"line":339},[891],{"type":32,"tag":235,"props":892,"children":893},{"style":242},[894],{"type":37,"value":895},"    id: metric.id,\n",{"type":32,"tag":235,"props":897,"children":898},{"class":237,"line":352},[899],{"type":32,"tag":235,"props":900,"children":901},{"style":242},[902],{"type":37,"value":903},"    rating: metric.rating\n",{"type":32,"tag":235,"props":905,"children":906},{"class":237,"line":26},[907],{"type":32,"tag":235,"props":908,"children":909},{"style":242},[910],{"type":37,"value":911},"  });\n",{"type":32,"tag":235,"props":913,"children":914},{"class":237,"line":387},[915,920,925,929,934],{"type":32,"tag":235,"props":916,"children":917},{"style":242},[918],{"type":37,"value":919},"  navigator.",{"type":32,"tag":235,"props":921,"children":922},{"style":814},[923],{"type":37,"value":924},"sendBeacon",{"type":32,"tag":235,"props":926,"children":927},{"style":242},[928],{"type":37,"value":822},{"type":32,"tag":235,"props":930,"children":931},{"style":290},[932],{"type":37,"value":933},"'\u002Fanalytics'",{"type":32,"tag":235,"props":935,"children":936},{"style":242},[937],{"type":37,"value":938},", body);\n",{"type":32,"tag":235,"props":940,"children":941},{"class":237,"line":429},[942],{"type":32,"tag":235,"props":943,"children":944},{"style":242},[945],{"type":37,"value":617},{"type":32,"tag":235,"props":947,"children":948},{"class":237,"line":467},[949],{"type":32,"tag":235,"props":950,"children":951},{"emptyLinePlaceholder":800},[952],{"type":37,"value":803},{"type":32,"tag":235,"props":954,"children":955},{"class":237,"line":505},[956,961],{"type":32,"tag":235,"props":957,"children":958},{"style":814},[959],{"type":37,"value":960},"onCLS",{"type":32,"tag":235,"props":962,"children":963},{"style":242},[964],{"type":37,"value":965},"(sendToAnalytics);\n",{"type":32,"tag":235,"props":967,"children":968},{"class":237,"line":545},[969,974],{"type":32,"tag":235,"props":970,"children":971},{"style":814},[972],{"type":37,"value":973},"onINP",{"type":32,"tag":235,"props":975,"children":976},{"style":242},[977],{"type":37,"value":965},{"type":32,"tag":235,"props":979,"children":980},{"class":237,"line":554},[981,986],{"type":32,"tag":235,"props":982,"children":983},{"style":814},[984],{"type":37,"value":985},"onLCP",{"type":32,"tag":235,"props":987,"children":988},{"style":242},[989],{"type":37,"value":965},{"type":32,"tag":33,"props":991,"children":992},{},[993,995,1001],{"type":37,"value":994},"L'endpoint backend ",{"type":32,"tag":184,"props":996,"children":998},{"className":997},[],[999],{"type":37,"value":1000},"\u002Fanalytics",{"type":37,"value":1002}," scrive i dati in BigQuery (se preferite dati first-party invece di Google Analytics 4, GA4 fa sampling). In BigQuery calcolate il p75:",{"type":32,"tag":225,"props":1004,"children":1008},{"className":1005,"code":1006,"language":1007,"meta":16,"style":16},"language-sql shiki shiki-themes github-dark","SELECT\n  APPROX_QUANTILES(value, 100)[OFFSET(75)] AS p75_lcp\nFROM metrics\nWHERE name = 'LCP' AND date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);\n","sql",[1009],{"type":32,"tag":184,"props":1010,"children":1011},{"__ignoreMap":16},[1012,1020,1057,1070],{"type":32,"tag":235,"props":1013,"children":1014},{"class":237,"line":238},[1015],{"type":32,"tag":235,"props":1016,"children":1017},{"style":711},[1018],{"type":37,"value":1019},"SELECT\n",{"type":32,"tag":235,"props":1021,"children":1022},{"class":237,"line":248},[1023,1028,1033,1037,1042,1047,1052],{"type":32,"tag":235,"props":1024,"children":1025},{"style":242},[1026],{"type":37,"value":1027},"  APPROX_QUANTILES(",{"type":32,"tag":235,"props":1029,"children":1030},{"style":711},[1031],{"type":37,"value":1032},"value",{"type":32,"tag":235,"props":1034,"children":1035},{"style":242},[1036],{"type":37,"value":298},{"type":32,"tag":235,"props":1038,"children":1039},{"style":252},[1040],{"type":37,"value":1041},"100",{"type":32,"tag":235,"props":1043,"children":1044},{"style":242},[1045],{"type":37,"value":1046},")[OFFSET(75)] ",{"type":32,"tag":235,"props":1048,"children":1049},{"style":711},[1050],{"type":37,"value":1051},"AS",{"type":32,"tag":235,"props":1053,"children":1054},{"style":242},[1055],{"type":37,"value":1056}," p75_lcp\n",{"type":32,"tag":235,"props":1058,"children":1059},{"class":237,"line":263},[1060,1065],{"type":32,"tag":235,"props":1061,"children":1062},{"style":711},[1063],{"type":37,"value":1064},"FROM",{"type":32,"tag":235,"props":1066,"children":1067},{"style":242},[1068],{"type":37,"value":1069}," metrics\n",{"type":32,"tag":235,"props":1071,"children":1072},{"class":237,"line":276},[1073,1078,1083,1087,1092,1097,1102,1107,1112,1117,1122],{"type":32,"tag":235,"props":1074,"children":1075},{"style":711},[1076],{"type":37,"value":1077},"WHERE",{"type":32,"tag":235,"props":1079,"children":1080},{"style":711},[1081],{"type":37,"value":1082}," name",{"type":32,"tag":235,"props":1084,"children":1085},{"style":711},[1086],{"type":37,"value":851},{"type":32,"tag":235,"props":1088,"children":1089},{"style":290},[1090],{"type":37,"value":1091}," 'LCP'",{"type":32,"tag":235,"props":1093,"children":1094},{"style":711},[1095],{"type":37,"value":1096}," AND",{"type":32,"tag":235,"props":1098,"children":1099},{"style":711},[1100],{"type":37,"value":1101}," date",{"type":32,"tag":235,"props":1103,"children":1104},{"style":711},[1105],{"type":37,"value":1106}," >=",{"type":32,"tag":235,"props":1108,"children":1109},{"style":242},[1110],{"type":37,"value":1111}," DATE_SUB(CURRENT_DATE(), INTERVAL ",{"type":32,"tag":235,"props":1113,"children":1114},{"style":252},[1115],{"type":37,"value":1116},"30",{"type":32,"tag":235,"props":1118,"children":1119},{"style":711},[1120],{"type":37,"value":1121}," DAY",{"type":32,"tag":235,"props":1123,"children":1124},{"style":242},[1125],{"type":37,"value":1126},");\n",{"type":32,"tag":33,"props":1128,"children":1129},{},[1130],{"type":37,"value":1131},"Se risulta 2.8s e il vostro budget è 2.5s, il budget è sotto la realtà del traffico—o lo alzate a 2.8s oppure ottimizzate il codice. Si usa p75 perché significa che il 75% degli utenti sta sotto quel livello, e Google calcola i punteggi CWV sul p75.",{"type":32,"tag":624,"props":1133,"children":1135},{"id":1134},"rum-segmentazione-budget-per-dispositivo-e-regione",[1136],{"type":37,"value":1137},"RUM + Segmentazione: Budget per Dispositivo e Regione",{"type":32,"tag":33,"props":1139,"children":1140},{},[1141],{"type":37,"value":1142},"Non gestite tutto il traffico con un budget solo. LCP mobile è il 40% più alto di desktop (Chrome UX Report 2025), il traffico dall'India è il 60% più lento di quello dagli USA. Segmentate i dati RUM e differentiate il budget:",{"type":32,"tag":57,"props":1144,"children":1145},{},[1146,1167],{"type":32,"tag":61,"props":1147,"children":1148},{},[1149],{"type":32,"tag":65,"props":1150,"children":1151},{},[1152,1157,1162],{"type":32,"tag":69,"props":1153,"children":1154},{},[1155],{"type":37,"value":1156},"Segmento",{"type":32,"tag":69,"props":1158,"children":1159},{},[1160],{"type":37,"value":1161},"Budget LCP",{"type":32,"tag":69,"props":1163,"children":1164},{},[1165],{"type":37,"value":1166},"Budget INP",{"type":32,"tag":85,"props":1168,"children":1169},{},[1170,1188,1206],{"type":32,"tag":65,"props":1171,"children":1172},{},[1173,1178,1183],{"type":32,"tag":92,"props":1174,"children":1175},{},[1176],{"type":37,"value":1177},"Desktop",{"type":32,"tag":92,"props":1179,"children":1180},{},[1181],{"type":37,"value":1182},"2.2s",{"type":32,"tag":92,"props":1184,"children":1185},{},[1186],{"type":37,"value":1187},"180ms",{"type":32,"tag":65,"props":1189,"children":1190},{},[1191,1196,1201],{"type":32,"tag":92,"props":1192,"children":1193},{},[1194],{"type":37,"value":1195},"Mobile",{"type":32,"tag":92,"props":1197,"children":1198},{},[1199],{"type":37,"value":1200},"3.0s",{"type":32,"tag":92,"props":1202,"children":1203},{},[1204],{"type":37,"value":1205},"220ms",{"type":32,"tag":65,"props":1207,"children":1208},{},[1209,1214,1219],{"type":32,"tag":92,"props":1210,"children":1211},{},[1212],{"type":37,"value":1213},"India",{"type":32,"tag":92,"props":1215,"children":1216},{},[1217],{"type":37,"value":1218},"3.5s",{"type":32,"tag":92,"props":1220,"children":1221},{},[1222],{"type":37,"value":1223},"250ms",{"type":32,"tag":33,"props":1225,"children":1226},{},[1227,1229,1235,1237,1243,1245,1251,1253,1259,1261,1267],{"type":37,"value":1228},"Per farlo aggiungete campi al beacon RUM come ",{"type":32,"tag":184,"props":1230,"children":1232},{"className":1231},[],[1233],{"type":37,"value":1234},"deviceType",{"type":37,"value":1236}," e ",{"type":32,"tag":184,"props":1238,"children":1240},{"className":1239},[],[1241],{"type":37,"value":1242},"country",{"type":37,"value":1244}," (lookup GeoIP nel backend), poi analizzate in BigQuery con ",{"type":32,"tag":184,"props":1246,"children":1248},{"className":1247},[],[1249],{"type":37,"value":1250},"GROUP BY device",{"type":37,"value":1252},". Lighthouse CI non supporta config multi-target nativamente, ma potete creare workflow separati (",{"type":32,"tag":184,"props":1254,"children":1256},{"className":1255},[],[1257],{"type":37,"value":1258},"lhci-mobile.json",{"type":37,"value":1260}," + ",{"type":32,"tag":184,"props":1262,"children":1264},{"className":1263},[],[1265],{"type":37,"value":1266},"lhci-desktop.json",{"type":37,"value":1268},").",{"type":32,"tag":40,"props":1270,"children":1272},{"id":1271},"allarmi-di-regressione-la-performance-crolla-slack-riceve-una-notifica",[1273],{"type":37,"value":1274},"Allarmi di Regressione: La Performance Crolla, Slack Riceve una Notifica",{"type":32,"tag":33,"props":1276,"children":1277},{},[1278],{"type":37,"value":1279},"Budget definito, CI controlla, RUM raccoglie—ma cosa succede se in produzione la performance regredisce? Dopo un deploy nuovo LCP salta da 2.3s a 2.9s, e lo scoprite fra 3 ore invece che in 5 minuti? Servite un job che analizza i dati RUM ogni 5 minuti (Cloudflare Workers Cron, AWS Lambda EventBridge, GCP Cloud Scheduler).",{"type":32,"tag":33,"props":1281,"children":1282},{},[1283],{"type":37,"value":1284},"Logica di allarme di esempio (pseudo-code):",{"type":32,"tag":225,"props":1286,"children":1288},{"className":760,"code":1287,"language":762,"meta":16,"style":16},"\u002F\u002F Worker che gira ogni 5min\nasync function checkRegression() {\n  const current = await query('SELECT AVG(value) FROM metrics WHERE name=\"LCP\" AND timestamp > NOW() - INTERVAL 5 MINUTE');\n  const baseline = await query('SELECT AVG(value) FROM metrics WHERE name=\"LCP\" AND timestamp BETWEEN NOW() - INTERVAL 1 DAY AND NOW() - INTERVAL 1 HOUR');\n  \n  if (current > baseline * 1.15) { \u002F\u002F +15%\n    await sendSlack({\n      text: `🚨 LCP regression: ${current}ms (baseline ${baseline}ms)`,\n      channel: '#performance-alerts'\n    });\n  }\n}\n",[1289],{"type":32,"tag":184,"props":1290,"children":1291},{"__ignoreMap":16},[1292,1301,1324,1363,1400,1408,1451,1468,1505,1518,1526,1533],{"type":32,"tag":235,"props":1293,"children":1294},{"class":237,"line":238},[1295],{"type":32,"tag":235,"props":1296,"children":1298},{"style":1297},"--shiki-default:#6A737D",[1299],{"type":37,"value":1300},"\u002F\u002F Worker che gira ogni 5min\n",{"type":32,"tag":235,"props":1302,"children":1303},{"class":237,"line":248},[1304,1309,1314,1319],{"type":32,"tag":235,"props":1305,"children":1306},{"style":711},[1307],{"type":37,"value":1308},"async",{"type":32,"tag":235,"props":1310,"children":1311},{"style":711},[1312],{"type":37,"value":1313}," function",{"type":32,"tag":235,"props":1315,"children":1316},{"style":814},[1317],{"type":37,"value":1318}," checkRegression",{"type":32,"tag":235,"props":1320,"children":1321},{"style":242},[1322],{"type":37,"value":1323},"() {\n",{"type":32,"tag":235,"props":1325,"children":1326},{"class":237,"line":263},[1327,1331,1336,1340,1345,1350,1354,1359],{"type":32,"tag":235,"props":1328,"children":1329},{"style":711},[1330],{"type":37,"value":841},{"type":32,"tag":235,"props":1332,"children":1333},{"style":252},[1334],{"type":37,"value":1335}," current",{"type":32,"tag":235,"props":1337,"children":1338},{"style":711},[1339],{"type":37,"value":851},{"type":32,"tag":235,"props":1341,"children":1342},{"style":711},[1343],{"type":37,"value":1344}," await",{"type":32,"tag":235,"props":1346,"children":1347},{"style":814},[1348],{"type":37,"value":1349}," query",{"type":32,"tag":235,"props":1351,"children":1352},{"style":242},[1353],{"type":37,"value":822},{"type":32,"tag":235,"props":1355,"children":1356},{"style":290},[1357],{"type":37,"value":1358},"'SELECT AVG(value) FROM metrics WHERE name=\"LCP\" AND timestamp > NOW() - INTERVAL 5 MINUTE'",{"type":32,"tag":235,"props":1360,"children":1361},{"style":242},[1362],{"type":37,"value":1126},{"type":32,"tag":235,"props":1364,"children":1365},{"class":237,"line":276},[1366,1370,1375,1379,1383,1387,1391,1396],{"type":32,"tag":235,"props":1367,"children":1368},{"style":711},[1369],{"type":37,"value":841},{"type":32,"tag":235,"props":1371,"children":1372},{"style":252},[1373],{"type":37,"value":1374}," baseline",{"type":32,"tag":235,"props":1376,"children":1377},{"style":711},[1378],{"type":37,"value":851},{"type":32,"tag":235,"props":1380,"children":1381},{"style":711},[1382],{"type":37,"value":1344},{"type":32,"tag":235,"props":1384,"children":1385},{"style":814},[1386],{"type":37,"value":1349},{"type":32,"tag":235,"props":1388,"children":1389},{"style":242},[1390],{"type":37,"value":822},{"type":32,"tag":235,"props":1392,"children":1393},{"style":290},[1394],{"type":37,"value":1395},"'SELECT AVG(value) FROM metrics WHERE name=\"LCP\" AND timestamp BETWEEN NOW() - INTERVAL 1 DAY AND NOW() - INTERVAL 1 HOUR'",{"type":32,"tag":235,"props":1397,"children":1398},{"style":242},[1399],{"type":37,"value":1126},{"type":32,"tag":235,"props":1401,"children":1402},{"class":237,"line":311},[1403],{"type":32,"tag":235,"props":1404,"children":1405},{"style":242},[1406],{"type":37,"value":1407},"  \n",{"type":32,"tag":235,"props":1409,"children":1410},{"class":237,"line":330},[1411,1416,1421,1426,1431,1436,1441,1446],{"type":32,"tag":235,"props":1412,"children":1413},{"style":711},[1414],{"type":37,"value":1415},"  if",{"type":32,"tag":235,"props":1417,"children":1418},{"style":242},[1419],{"type":37,"value":1420}," (current ",{"type":32,"tag":235,"props":1422,"children":1423},{"style":711},[1424],{"type":37,"value":1425},">",{"type":32,"tag":235,"props":1427,"children":1428},{"style":242},[1429],{"type":37,"value":1430}," baseline ",{"type":32,"tag":235,"props":1432,"children":1433},{"style":711},[1434],{"type":37,"value":1435},"*",{"type":32,"tag":235,"props":1437,"children":1438},{"style":252},[1439],{"type":37,"value":1440}," 1.15",{"type":32,"tag":235,"props":1442,"children":1443},{"style":242},[1444],{"type":37,"value":1445},") { ",{"type":32,"tag":235,"props":1447,"children":1448},{"style":1297},[1449],{"type":37,"value":1450},"\u002F\u002F +15%\n",{"type":32,"tag":235,"props":1452,"children":1453},{"class":237,"line":339},[1454,1459,1464],{"type":32,"tag":235,"props":1455,"children":1456},{"style":711},[1457],{"type":37,"value":1458},"    await",{"type":32,"tag":235,"props":1460,"children":1461},{"style":814},[1462],{"type":37,"value":1463}," sendSlack",{"type":32,"tag":235,"props":1465,"children":1466},{"style":242},[1467],{"type":37,"value":871},{"type":32,"tag":235,"props":1469,"children":1470},{"class":237,"line":352},[1471,1476,1481,1486,1491,1496,1501],{"type":32,"tag":235,"props":1472,"children":1473},{"style":242},[1474],{"type":37,"value":1475},"      text: ",{"type":32,"tag":235,"props":1477,"children":1478},{"style":290},[1479],{"type":37,"value":1480},"`🚨 LCP regression: ${",{"type":32,"tag":235,"props":1482,"children":1483},{"style":242},[1484],{"type":37,"value":1485},"current",{"type":32,"tag":235,"props":1487,"children":1488},{"style":290},[1489],{"type":37,"value":1490},"}ms (baseline ${",{"type":32,"tag":235,"props":1492,"children":1493},{"style":242},[1494],{"type":37,"value":1495},"baseline",{"type":32,"tag":235,"props":1497,"children":1498},{"style":290},[1499],{"type":37,"value":1500},"}ms)`",{"type":32,"tag":235,"props":1502,"children":1503},{"style":242},[1504],{"type":37,"value":372},{"type":32,"tag":235,"props":1506,"children":1507},{"class":237,"line":26},[1508,1513],{"type":32,"tag":235,"props":1509,"children":1510},{"style":242},[1511],{"type":37,"value":1512},"      channel: ",{"type":32,"tag":235,"props":1514,"children":1515},{"style":290},[1516],{"type":37,"value":1517},"'#performance-alerts'\n",{"type":32,"tag":235,"props":1519,"children":1520},{"class":237,"line":387},[1521],{"type":32,"tag":235,"props":1522,"children":1523},{"style":242},[1524],{"type":37,"value":1525},"    });\n",{"type":32,"tag":235,"props":1527,"children":1528},{"class":237,"line":429},[1529],{"type":32,"tag":235,"props":1530,"children":1531},{"style":242},[1532],{"type":37,"value":608},{"type":32,"tag":235,"props":1534,"children":1535},{"class":237,"line":467},[1536],{"type":32,"tag":235,"props":1537,"children":1538},{"style":242},[1539],{"type":37,"value":617},{"type":32,"tag":33,"props":1541,"children":1542},{},[1543],{"type":37,"value":1544},"Il baseline va 1 ora indietro perché il deploy potrebbe essere stato allora. La soglia del 15% si calibra—10% è troppo sensibile (falsi positivi), 25% è troppo tardi. Potete integrare con PagerDuty o Opsgenie per on-call. Quando arriva l'allarme il team decide se rollback o hotfix.",{"type":32,"tag":624,"props":1546,"children":1548},{"id":1547},"root-cause-regression-lighthouse-diff",[1549],{"type":37,"value":1550},"Root Cause Regression: Lighthouse Diff",{"type":32,"tag":33,"props":1552,"children":1553},{},[1554,1556,1562],{"type":37,"value":1555},"Allarme ricevuto, LCP è scoppiato—perché? Lighthouse CI fa solo il controllo della soglia, non dà l'analisi della causa. Con Lighthouse Diff vedete le differenze di audit fra due build. Il comando ",{"type":32,"tag":184,"props":1557,"children":1559},{"className":1558},[],[1560],{"type":37,"value":1561},"lhci compare",{"type":37,"value":1563}," prende due report Lighthouse e calcola i delta:",{"type":32,"tag":225,"props":1565,"children":1569},{"className":1566,"code":1567,"language":1568,"meta":16,"style":16},"language-bash shiki shiki-themes github-dark","lhci compare --base=build-1234 --head=build-1235 --preset=lighthouse:all\n","bash",[1570],{"type":32,"tag":184,"props":1571,"children":1572},{"__ignoreMap":16},[1573],{"type":32,"tag":235,"props":1574,"children":1575},{"class":237,"line":238},[1576,1581,1586,1591,1596],{"type":32,"tag":235,"props":1577,"children":1578},{"style":814},[1579],{"type":37,"value":1580},"lhci",{"type":32,"tag":235,"props":1582,"children":1583},{"style":290},[1584],{"type":37,"value":1585}," compare",{"type":32,"tag":235,"props":1587,"children":1588},{"style":252},[1589],{"type":37,"value":1590}," --base=build-1234",{"type":32,"tag":235,"props":1592,"children":1593},{"style":252},[1594],{"type":37,"value":1595}," --head=build-1235",{"type":32,"tag":235,"props":1597,"children":1598},{"style":252},[1599],{"type":37,"value":1600}," --preset=lighthouse:all\n",{"type":32,"tag":33,"props":1602,"children":1603},{},[1604],{"type":37,"value":1605},"Output: \"unused-javascript increased by 45KB\", \"server-response-time +120ms\". Questi numeri restringono la causa. Con bundle analyzer (webpack-bundle-analyzer, Next.js analyze) trovate da dove vengono i 45KB, il trace log del server vi mostra dove vanno i 120ms di delay.",{"type":32,"tag":40,"props":1607,"children":1609},{"id":1608},"legare-performance-a-conversione-attribution-model",[1610],{"type":37,"value":1611},"Legare Performance a Conversione: Attribution Model",{"type":32,"tag":33,"props":1613,"children":1614},{},[1615],{"type":37,"value":1616},"I budget sono numeri tecnici, ma per collegarli alle decisioni vanno convertiti in metriche di business. Servite un rapporto tipo \"se LCP passa da 2.5s a 3s, il tasso di conversione cala del 4%\". Si produce con A\u002FB test o analisi di coorti. A\u002FB test: il 50% del traffico riceve una build rallentata (Lighthouse aggiunge 500ms), confrontate le conversioni. Analisi di coorti: nei dati RUM confrontate il tasso di conversione degli utenti con LCP \u003C2s vs LCP >3s.",{"type":32,"tag":33,"props":1618,"children":1619},{},[1620],{"type":37,"value":1621},"Con Google Analytics 4 + BigQuery export, la query di correlazione:",{"type":32,"tag":225,"props":1623,"children":1625},{"className":1005,"code":1624,"language":1007,"meta":16,"style":16},"SELECT\n  CASE \n    WHEN lcp \u003C 2000 THEN 'fast'\n    WHEN lcp BETWEEN 2000 AND 4000 THEN 'medium'\n    ELSE 'slow'\n  END AS lcp_bucket,\n  COUNT(DISTINCT user_pseudo_id) AS users,\n  COUNTIF(event_name = 'purchase') \u002F COUNT(DISTINCT session_id) AS conversion_rate\nFROM analytics_events\nLEFT JOIN rum_metrics ON analytics_events.session_id = rum_metrics.session_id\nGROUP BY lcp_bucket;\n",[1626],{"type":32,"tag":184,"props":1627,"children":1628},{"__ignoreMap":16},[1629,1636,1649,1682,1720,1733,1751,1782,1837,1849,1899],{"type":32,"tag":235,"props":1630,"children":1631},{"class":237,"line":238},[1632],{"type":32,"tag":235,"props":1633,"children":1634},{"style":711},[1635],{"type":37,"value":1019},{"type":32,"tag":235,"props":1637,"children":1638},{"class":237,"line":248},[1639,1644],{"type":32,"tag":235,"props":1640,"children":1641},{"style":711},[1642],{"type":37,"value":1643},"  CASE",{"type":32,"tag":235,"props":1645,"children":1646},{"style":242},[1647],{"type":37,"value":1648}," \n",{"type":32,"tag":235,"props":1650,"children":1651},{"class":237,"line":263},[1652,1657,1662,1667,1672,1677],{"type":32,"tag":235,"props":1653,"children":1654},{"style":711},[1655],{"type":37,"value":1656},"    WHEN",{"type":32,"tag":235,"props":1658,"children":1659},{"style":242},[1660],{"type":37,"value":1661}," lcp ",{"type":32,"tag":235,"props":1663,"children":1664},{"style":711},[1665],{"type":37,"value":1666},"\u003C",{"type":32,"tag":235,"props":1668,"children":1669},{"style":252},[1670],{"type":37,"value":1671}," 2000",{"type":32,"tag":235,"props":1673,"children":1674},{"style":711},[1675],{"type":37,"value":1676}," THEN",{"type":32,"tag":235,"props":1678,"children":1679},{"style":290},[1680],{"type":37,"value":1681}," 'fast'\n",{"type":32,"tag":235,"props":1683,"children":1684},{"class":237,"line":276},[1685,1689,1693,1698,1702,1706,1711,1715],{"type":32,"tag":235,"props":1686,"children":1687},{"style":711},[1688],{"type":37,"value":1656},{"type":32,"tag":235,"props":1690,"children":1691},{"style":242},[1692],{"type":37,"value":1661},{"type":32,"tag":235,"props":1694,"children":1695},{"style":711},[1696],{"type":37,"value":1697},"BETWEEN",{"type":32,"tag":235,"props":1699,"children":1700},{"style":252},[1701],{"type":37,"value":1671},{"type":32,"tag":235,"props":1703,"children":1704},{"style":711},[1705],{"type":37,"value":1096},{"type":32,"tag":235,"props":1707,"children":1708},{"style":252},[1709],{"type":37,"value":1710}," 4000",{"type":32,"tag":235,"props":1712,"children":1713},{"style":711},[1714],{"type":37,"value":1676},{"type":32,"tag":235,"props":1716,"children":1717},{"style":290},[1718],{"type":37,"value":1719}," 'medium'\n",{"type":32,"tag":235,"props":1721,"children":1722},{"class":237,"line":311},[1723,1728],{"type":32,"tag":235,"props":1724,"children":1725},{"style":711},[1726],{"type":37,"value":1727},"    ELSE",{"type":32,"tag":235,"props":1729,"children":1730},{"style":290},[1731],{"type":37,"value":1732}," 'slow'\n",{"type":32,"tag":235,"props":1734,"children":1735},{"class":237,"line":330},[1736,1741,1746],{"type":32,"tag":235,"props":1737,"children":1738},{"style":711},[1739],{"type":37,"value":1740},"  END",{"type":32,"tag":235,"props":1742,"children":1743},{"style":711},[1744],{"type":37,"value":1745}," AS",{"type":32,"tag":235,"props":1747,"children":1748},{"style":242},[1749],{"type":37,"value":1750}," lcp_bucket,\n",{"type":32,"tag":235,"props":1752,"children":1753},{"class":237,"line":339},[1754,1759,1763,1768,1773,1777],{"type":32,"tag":235,"props":1755,"children":1756},{"style":252},[1757],{"type":37,"value":1758},"  COUNT",{"type":32,"tag":235,"props":1760,"children":1761},{"style":242},[1762],{"type":37,"value":822},{"type":32,"tag":235,"props":1764,"children":1765},{"style":711},[1766],{"type":37,"value":1767},"DISTINCT",{"type":32,"tag":235,"props":1769,"children":1770},{"style":242},[1771],{"type":37,"value":1772}," user_pseudo_id) ",{"type":32,"tag":235,"props":1774,"children":1775},{"style":711},[1776],{"type":37,"value":1051},{"type":32,"tag":235,"props":1778,"children":1779},{"style":242},[1780],{"type":37,"value":1781}," users,\n",{"type":32,"tag":235,"props":1783,"children":1784},{"class":237,"line":352},[1785,1790,1795,1800,1805,1810,1815,1819,1823,1828,1832],{"type":32,"tag":235,"props":1786,"children":1787},{"style":242},[1788],{"type":37,"value":1789},"  COUNTIF(event_name ",{"type":32,"tag":235,"props":1791,"children":1792},{"style":711},[1793],{"type":37,"value":1794},"=",{"type":32,"tag":235,"props":1796,"children":1797},{"style":290},[1798],{"type":37,"value":1799}," 'purchase'",{"type":32,"tag":235,"props":1801,"children":1802},{"style":242},[1803],{"type":37,"value":1804},") ",{"type":32,"tag":235,"props":1806,"children":1807},{"style":711},[1808],{"type":37,"value":1809},"\u002F",{"type":32,"tag":235,"props":1811,"children":1812},{"style":252},[1813],{"type":37,"value":1814}," COUNT",{"type":32,"tag":235,"props":1816,"children":1817},{"style":242},[1818],{"type":37,"value":822},{"type":32,"tag":235,"props":1820,"children":1821},{"style":711},[1822],{"type":37,"value":1767},{"type":32,"tag":235,"props":1824,"children":1825},{"style":242},[1826],{"type":37,"value":1827}," session_id) ",{"type":32,"tag":235,"props":1829,"children":1830},{"style":711},[1831],{"type":37,"value":1051},{"type":32,"tag":235,"props":1833,"children":1834},{"style":242},[1835],{"type":37,"value":1836}," conversion_rate\n",{"type":32,"tag":235,"props":1838,"children":1839},{"class":237,"line":26},[1840,1844],{"type":32,"tag":235,"props":1841,"children":1842},{"style":711},[1843],{"type":37,"value":1064},{"type":32,"tag":235,"props":1845,"children":1846},{"style":242},[1847],{"type":37,"value":1848}," analytics_events\n",{"type":32,"tag":235,"props":1850,"children":1851},{"class":237,"line":387},[1852,1857,1862,1867,1872,1876,1881,1885,1890,1894],{"type":32,"tag":235,"props":1853,"children":1854},{"style":711},[1855],{"type":37,"value":1856},"LEFT JOIN",{"type":32,"tag":235,"props":1858,"children":1859},{"style":242},[1860],{"type":37,"value":1861}," rum_metrics ",{"type":32,"tag":235,"props":1863,"children":1864},{"style":711},[1865],{"type":37,"value":1866},"ON",{"type":32,"tag":235,"props":1868,"children":1869},{"style":252},[1870],{"type":37,"value":1871}," analytics_events",{"type":32,"tag":235,"props":1873,"children":1874},{"style":242},[1875],{"type":37,"value":861},{"type":32,"tag":235,"props":1877,"children":1878},{"style":252},[1879],{"type":37,"value":1880},"session_id",{"type":32,"tag":235,"props":1882,"children":1883},{"style":711},[1884],{"type":37,"value":851},{"type":32,"tag":235,"props":1886,"children":1887},{"style":252},[1888],{"type":37,"value":1889}," rum_metrics",{"type":32,"tag":235,"props":1891,"children":1892},{"style":242},[1893],{"type":37,"value":861},{"type":32,"tag":235,"props":1895,"children":1896},{"style":252},[1897],{"type":37,"value":1898},"session_id\n",{"type":32,"tag":235,"props":1900,"children":1901},{"class":237,"line":429},[1902,1907],{"type":32,"tag":235,"props":1903,"children":1904},{"style":711},[1905],{"type":37,"value":1906},"GROUP BY",{"type":32,"tag":235,"props":1908,"children":1909},{"style":242},[1910],{"type":37,"value":1911}," lcp_bucket;\n",{"type":32,"tag":33,"props":1913,"children":1914},{},[1915],{"type":37,"value":1916},"La tabella risultante:",{"type":32,"tag":57,"props":1918,"children":1919},{},[1920,1936],{"type":32,"tag":61,"props":1921,"children":1922},{},[1923],{"type":32,"tag":65,"props":1924,"children":1925},{},[1926,1931],{"type":32,"tag":69,"props":1927,"children":1928},{},[1929],{"type":37,"value":1930},"LCP Bucket",{"type":32,"tag":69,"props":1932,"children":1933},{},[1934],{"type":37,"value":1935},"Tasso di Conversione",{"type":32,"tag":85,"props":1937,"children":1938},{},[1939,1952,1965],{"type":32,"tag":65,"props":1940,"children":1941},{},[1942,1947],{"type":32,"tag":92,"props":1943,"children":1944},{},[1945],{"type":37,"value":1946},"fast",{"type":32,"tag":92,"props":1948,"children":1949},{},[1950],{"type":37,"value":1951},"4.2%",{"type":32,"tag":65,"props":1953,"children":1954},{},[1955,1960],{"type":32,"tag":92,"props":1956,"children":1957},{},[1958],{"type":37,"value":1959},"medium",{"type":32,"tag":92,"props":1961,"children":1962},{},[1963],{"type":37,"value":1964},"3.6%",{"type":32,"tag":65,"props":1966,"children":1967},{},[1968,1973],{"type":32,"tag":92,"props":1969,"children":1970},{},[1971],{"type":37,"value":1972},"slow",{"type":32,"tag":92,"props":1974,"children":1975},{},[1976],{"type":37,"value":1977},"2.9%",{"type":32,"tag":33,"props":1979,"children":1980},{},[1981],{"type":37,"value":1982},"Con questi numeri calcolate il ROI del budget: abbassare LCP da 3s a 2.5s alza il conversion rate da 3.6% a 4.2%, un lift del 16.7%. Con 100K visitatori al mese +1670 conversioni, AOV $50 = +$83K di revenue. Questo rapporto non va al CTO, va al CFO—qui si decide la priorità dello sprint di ottimizzazione performance.",{"type":32,"tag":624,"props":1984,"children":1986},{"id":1985},"violazione-del-budget-la-decisione-del-tradeoff",[1987],{"type":37,"value":1988},"Violazione del Budget: La Decisione del Tradeoff",{"type":32,"tag":33,"props":1990,"children":1991},{},[1992],{"type":37,"value":1993},"Uno sprint, una nuova feature arriva e il bundle cresce di 50KB, il budget scoppia. Che fate? Tre opzioni: (1) refactorizzate la feature (code-split, lazy load), (2) alzate il budget e accettate la perdita di conversioni, (3) rinviate la feature. La decisione è numerata: 50KB di extra causano +200ms di LCP (da Lighthouse trace), +200ms causa -2% di conversione (da RUM correlation), se la feature porta +5% di lift il guadagno netto è +3%—andate avanti. Se il lift è +1%, perdete il 1%—rinviate.",{"type":32,"tag":33,"props":1995,"children":1996},{},[1997],{"type":37,"value":1998},"Per fare questo calcolo costruite uno \"performance cost estimator\" (tool interno). Input: delta bundle size, output: delta LCP stimato + impatto su conversione. Modello: regressione semplice, ogni 10KB +30ms LCP, ogni 100ms LCP -%0.8 conversione (ricavato dai vostri dati RUM). Il tool si mostra al PM, la roadmap feature si prioritizza di conseguenza.",{"type":32,"tag":40,"props":2000,"children":2002},{"id":2001},"headless-commerce-il-budget-di-performance-lega-il-prezzo-alla-velocità",[2003],{"type":37,"value":2004},"Headless Commerce: Il Budget di Performance Lega il Prezzo alla Velocità",{"type":32,"tag":33,"props":2006,"children":2007},{},[2008,2010,2019],{"type":37,"value":2009},"In e-commerce la performance = revenue. Con architettura ",{"type":32,"tag":2011,"props":2012,"children":2016},"a",{"href":2013,"rel":2014},"https:\u002F\u002Fwww.roibase.com.tr\u002Fit\u002Fheadless",[2015],"nofollow",[2017],{"type":37,"value":2018},"headless commerce",{"type":37,"value":2020}," (Shopify Hydrogen, Remix, Next.js) controllate il bundle del frontend ma la latenza dell'API backend conta pure nel budget. L'API Storefront Shopify restituisce in media 150ms, lo aggiungete al budget: LCP = TTFB (150ms) + FCP (800ms) + LCP delta (600ms) = 1550ms. Se il budget è 2500ms avete 950ms di margine.",{"type":32,"tag":33,"props":2022,"children":2023},{},[2024,2026,2032],{"type":37,"value":2025},"In headless la fonte di regressione è generalmente: (1) la complessità della query GraphQL aumenta (profondità +2 level = +50ms), (2) il numero di componenti SSR cresce (20 component = +100ms di hydration), (3) script di terze parti si aggiungono (tag analytics = +200ms). Lighthouse CI non distingue questi tre, serve il RUM trace log. Aggiungete l'header ",{"type":32,"tag":184,"props":2027,"children":2029},{"className":2028},[],[2030],{"type":37,"value":2031},"Server-Timing",{"type":37,"value":2033}," nel middleware Next.js per breakdown della latenza API:",{"type":32,"tag":225,"props":2035,"children":2037},{"className":760,"code":2036,"language":762,"meta":16,"style":16},"export function middleware(req) {\n  const start = Date.now();\n  const res = NextResponse.next();\n  res.headers.set('Server-Timing', `api;dur=${Date.now() - start}`);\n  return res;\n}\n",[2038],{"type":32,"tag":184,"props":2039,"children":2040},{"__ignoreMap":16},[2041,2071,2102,2132,2199,2212],{"type":32,"tag":235,"props":2042,"children":2043},{"class":237,"line":238},[2044,2049,2053,2058,2062,2067],{"type":32,"tag":235,"props":2045,"children":2046},{"style":711},[2047],{"type":37,"value":2048},"export",{"type":32,"tag":235,"props":2050,"children":2051},{"style":711},[2052],{"type":37,"value":1313},{"type":32,"tag":235,"props":2054,"children":2055},{"style":814},[2056],{"type":37,"value":2057}," middleware",{"type":32,"tag":235,"props":2059,"children":2060},{"style":242},[2061],{"type":37,"value":822},{"type":32,"tag":235,"props":2063,"children":2064},{"style":825},[2065],{"type":37,"value":2066},"req",{"type":32,"tag":235,"props":2068,"children":2069},{"style":242},[2070],{"type":37,"value":833},{"type":32,"tag":235,"props":2072,"children":2073},{"class":237,"line":248},[2074,2078,2083,2087,2092,2097],{"type":32,"tag":235,"props":2075,"children":2076},{"style":711},[2077],{"type":37,"value":841},{"type":32,"tag":235,"props":2079,"children":2080},{"style":252},[2081],{"type":37,"value":2082}," start",{"type":32,"tag":235,"props":2084,"children":2085},{"style":711},[2086],{"type":37,"value":851},{"type":32,"tag":235,"props":2088,"children":2089},{"style":242},[2090],{"type":37,"value":2091}," Date.",{"type":32,"tag":235,"props":2093,"children":2094},{"style":814},[2095],{"type":37,"value":2096},"now",{"type":32,"tag":235,"props":2098,"children":2099},{"style":242},[2100],{"type":37,"value":2101},"();\n",{"type":32,"tag":235,"props":2103,"children":2104},{"class":237,"line":263},[2105,2109,2114,2118,2123,2128],{"type":32,"tag":235,"props":2106,"children":2107},{"style":711},[2108],{"type":37,"value":841},{"type":32,"tag":235,"props":2110,"children":2111},{"style":252},[2112],{"type":37,"value":2113}," res",{"type":32,"tag":235,"props":2115,"children":2116},{"style":711},[2117],{"type":37,"value":851},{"type":32,"tag":235,"props":2119,"children":2120},{"style":242},[2121],{"type":37,"value":2122}," NextResponse.",{"type":32,"tag":235,"props":2124,"children":2125},{"style":814},[2126],{"type":37,"value":2127},"next",{"type":32,"tag":235,"props":2129,"children":2130},{"style":242},[2131],{"type":37,"value":2101},{"type":32,"tag":235,"props":2133,"children":2134},{"class":237,"line":276},[2135,2140,2145,2149,2154,2158,2163,2168,2172,2176,2181,2186,2190,2195],{"type":32,"tag":235,"props":2136,"children":2137},{"style":242},[2138],{"type":37,"value":2139},"  res.headers.",{"type":32,"tag":235,"props":2141,"children":2142},{"style":814},[2143],{"type":37,"value":2144},"set",{"type":32,"tag":235,"props":2146,"children":2147},{"style":242},[2148],{"type":37,"value":822},{"type":32,"tag":235,"props":2150,"children":2151},{"style":290},[2152],{"type":37,"value":2153},"'Server-Timing'",{"type":32,"tag":235,"props":2155,"children":2156},{"style":242},[2157],{"type":37,"value":298},{"type":32,"tag":235,"props":2159,"children":2160},{"style":290},[2161],{"type":37,"value":2162},"`api;dur=${",{"type":32,"tag":235,"props":2164,"children":2165},{"style":242},[2166],{"type":37,"value":2167},"Date",{"type":32,"tag":235,"props":2169,"children":2170},{"style":290},[2171],{"type":37,"value":861},{"type":32,"tag":235,"props":2173,"children":2174},{"style":814},[2175],{"type":37,"value":2096},{"type":32,"tag":235,"props":2177,"children":2178},{"style":290},[2179],{"type":37,"value":2180},"() ",{"type":32,"tag":235,"props":2182,"children":2183},{"style":711},[2184],{"type":37,"value":2185},"-",{"type":32,"tag":235,"props":2187,"children":2188},{"style":242},[2189],{"type":37,"value":2082},{"type":32,"tag":235,"props":2191,"children":2192},{"style":290},[2193],{"type":37,"value":2194},"}`",{"type":32,"tag":235,"props":2196,"children":2197},{"style":242},[2198],{"type":37,"value":1126},{"type":32,"tag":235,"props":2200,"children":2201},{"class":237,"line":311},[2202,2207],{"type":32,"tag":235,"props":2203,"children":2204},{"style":711},[2205],{"type":37,"value":2206},"  return",{"type":32,"tag":235,"props":2208,"children":2209},{"style":242},[2210],{"type":37,"value":2211}," res;\n",{"type":32,"tag":235,"props":2213,"children":2214},{"class":237,"line":330},[2215],{"type":32,"tag":235,"props":2216,"children":2217},{"style":242},[2218],{"type":37,"value":617},{"type":32,"tag":33,"props":2220,"children":2221},{},[2222],{"type":37,"value":2223},"Appare in Chrome DevTools Network tab, lo aggiungete al beacon RUM, configurate l'allarme di re",{"type":32,"tag":2225,"props":2226,"children":2227},"style",{},[2228],{"type":37,"value":2229},"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);}",{"title":16,"searchDepth":263,"depth":263,"links":2231},[2232,2233,2236,2239,2242,2245],{"id":42,"depth":248,"text":45},{"id":194,"depth":248,"text":197,"children":2234},[2235],{"id":626,"depth":263,"text":629},{"id":744,"depth":248,"text":747,"children":2237},[2238],{"id":1134,"depth":263,"text":1137},{"id":1271,"depth":248,"text":1274,"children":2240},[2241],{"id":1547,"depth":263,"text":1550},{"id":1608,"depth":248,"text":1611,"children":2243},[2244],{"id":1985,"depth":263,"text":1988},{"id":2001,"depth":248,"text":2004},"markdown","content:it:tech:performance-budget-decisioning.md","content","it\u002Ftech\u002Fperformance-budget-decisioning.md","it\u002Ftech\u002Fperformance-budget-decisioning","md",1785189895945]