[{"data":1,"prerenderedAt":1547},["ShallowReactive",2],{"article-alternates":3,"cat-it-tech":4},null,[5],{"_path":6,"_dir":7,"_draft":8,"_partial":8,"_locale":9,"title":10,"description":11,"publishedAt":12,"modifiedAt":12,"category":7,"i18nKey":13,"tags":14,"readingTime":20,"author":21,"body":22,"_type":1541,"_id":1542,"_source":1543,"_file":1544,"_stem":1545,"_extension":1546},"\u002Fit\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-ottimizzazione","tech",false,"","Nuxt 3 + Cloudflare Pages: da 10s a 2s LCP","Font self-hosted, lazy hydration, content-visibility e edge caching: abbiamo ridotto l'LCP dell'80%. Benchmark reali, codice e trade-off.","2026-05-07","tech-001-2026-05",[15,16,17,18,19],"nuxt3","cloudflare-pages","web-performance","lcp","edge-caching",9,"Roibase",{"type":23,"children":24,"toc":1530},"root",[25,33,40,45,91,96,102,140,543,560,572,593,701,714,800,823,829,858,1002,1015,1030,1036,1049,1211,1224,1240,1246,1251,1381,1397,1403,1428,1438,1455,1465,1471,1476,1520,1525],{"type":26,"tag":27,"props":28,"children":29},"element","p",{},[30],{"type":31,"value":32},"text","Dopo l'aggiornamento Core Web Vitals di Google, l'LCP (Largest Contentful Paint) deve stare sotto i 2,5 secondi — altrimenti il ranking organico e il tasso di conversione crollano. Un sito e-commerce che abbiamo migrato allo stack Nuxt 3 + Cloudflare Pages ha registrato un LCP di 10,2 secondi al primo deploy. Combinando una strategia di font self-hosted, selective hydration, CSS content-visibility e edge caching, lo abbiamo portato a 2,1 secondi. Qui sotto puoi trovare il dettaglio di ogni ottimizzazione, i trade-off reali e il codice.",{"type":26,"tag":34,"props":35,"children":37},"h2",{"id":36},"diagnosticare-il-problema-anatomia-di-un-lcp-a-10s",[38],{"type":31,"value":39},"Diagnosticare il problema: anatomia di un LCP a 10s",{"type":26,"tag":27,"props":41,"children":42},{},[43],{"type":31,"value":44},"Nel primo report CrUX il mediano LCP era 10,2s, TBT (Total Blocking Time) 2190ms. L'analisi del profilo Lighthouse in Chrome DevTools ha rivelato:",{"type":26,"tag":46,"props":47,"children":48},"ul",{},[49,61,71,81],{"type":26,"tag":50,"props":51,"children":52},"li",{},[53,59],{"type":26,"tag":54,"props":55,"children":56},"strong",{},[57],{"type":31,"value":58},"Caricamento font:",{"type":31,"value":60}," tre famiglie da Google Fonts CDN, render-blocking",{"type":26,"tag":50,"props":62,"children":63},{},[64,69],{"type":26,"tag":54,"props":65,"children":66},{},[67],{"type":31,"value":68},"Hydration JavaScript:",{"type":31,"value":70}," bundle da 420kB, tutta la pagina viene hydrata",{"type":26,"tag":50,"props":72,"children":73},{},[74,79],{"type":26,"tag":54,"props":75,"children":76},{},[77],{"type":31,"value":78},"Immagine above-the-fold:",{"type":31,"value":80}," JPEG da 1,2MB senza lazy load",{"type":26,"tag":50,"props":82,"children":83},{},[84,89],{"type":26,"tag":54,"props":85,"children":86},{},[87],{"type":31,"value":88},"Cache Cloudflare:",{"type":31,"value":90}," le risposte SSR non erano cachate, ogni request raggiungeva l'origin",{"type":26,"tag":27,"props":92,"children":93},{},[94],{"type":31,"value":95},"Misurazione baseline: PageSpeed Insights mobile score 34\u002F100. Desktop 62\u002F100. Questi numeri arrivano dalla migrazione da Shopify Liquid a Nuxt 3 — il cambio di framework da solo non garantisce guadagni di performance; serve ottimizzazione architetturale.",{"type":26,"tag":34,"props":97,"children":99},{"id":98},"font-self-hosted-strategia-preload",[100],{"type":31,"value":101},"Font self-hosted + strategia preload",{"type":26,"tag":27,"props":103,"children":104},{},[105,107,114,116,122,124,130,132,138],{"type":31,"value":106},"Abbiamo scaricato gli stessi file font da Google Fonts nella cartella ",{"type":26,"tag":108,"props":109,"children":111},"code",{"className":110},[],[112],{"type":31,"value":113},"public\u002Ffonts\u002F",{"type":31,"value":115}," e spostato la definizione ",{"type":26,"tag":108,"props":117,"children":119},{"className":118},[],[120],{"type":31,"value":121},"@font-face",{"type":31,"value":123}," in ",{"type":26,"tag":108,"props":125,"children":127},{"className":126},[],[128],{"type":31,"value":129},"app.vue",{"type":31,"value":131},". Il dettaglio critico: usiamo ",{"type":26,"tag":108,"props":133,"children":135},{"className":134},[],[136],{"type":31,"value":137},"\u003Clink rel=\"preload\">",{"type":31,"value":139}," per richiedere i file font direttamente nella risposta HTML iniziale, prima del parse CSS.",{"type":26,"tag":141,"props":142,"children":146},"pre",{"className":143,"code":144,"language":145,"meta":9,"style":9},"language-vue shiki shiki-themes github-dark","\u003C!-- app.vue -->\n\u003Cscript setup>\nuseHead({\n  link: [\n    {\n      rel: 'preload',\n      href: '\u002Ffonts\u002Finter-var.woff2',\n      as: 'font',\n      type: 'font\u002Fwoff2',\n      crossorigin: 'anonymous'\n    }\n  ]\n})\n\u003C\u002Fscript>\n\n\u003Cstyle>\n@font-face {\n  font-family: 'Inter';\n  src: url('\u002Ffonts\u002Finter-var.woff2') format('woff2');\n  font-display: swap;\n  font-weight: 100 900;\n}\n\u003C\u002Fstyle>\n","vue",[147],{"type":26,"tag":108,"props":148,"children":149},{"__ignoreMap":9},[150,162,189,203,212,221,241,259,277,294,308,317,326,335,352,362,379,393,418,469,491,518,527],{"type":26,"tag":151,"props":152,"children":155},"span",{"class":153,"line":154},"line",1,[156],{"type":26,"tag":151,"props":157,"children":159},{"style":158},"--shiki-default:#6A737D",[160],{"type":31,"value":161},"\u003C!-- app.vue -->\n",{"type":26,"tag":151,"props":163,"children":165},{"class":153,"line":164},2,[166,172,178,184],{"type":26,"tag":151,"props":167,"children":169},{"style":168},"--shiki-default:#E1E4E8",[170],{"type":31,"value":171},"\u003C",{"type":26,"tag":151,"props":173,"children":175},{"style":174},"--shiki-default:#85E89D",[176],{"type":31,"value":177},"script",{"type":26,"tag":151,"props":179,"children":181},{"style":180},"--shiki-default:#B392F0",[182],{"type":31,"value":183}," setup",{"type":26,"tag":151,"props":185,"children":186},{"style":168},[187],{"type":31,"value":188},">\n",{"type":26,"tag":151,"props":190,"children":192},{"class":153,"line":191},3,[193,198],{"type":26,"tag":151,"props":194,"children":195},{"style":180},[196],{"type":31,"value":197},"useHead",{"type":26,"tag":151,"props":199,"children":200},{"style":168},[201],{"type":31,"value":202},"({\n",{"type":26,"tag":151,"props":204,"children":206},{"class":153,"line":205},4,[207],{"type":26,"tag":151,"props":208,"children":209},{"style":168},[210],{"type":31,"value":211},"  link: [\n",{"type":26,"tag":151,"props":213,"children":215},{"class":153,"line":214},5,[216],{"type":26,"tag":151,"props":217,"children":218},{"style":168},[219],{"type":31,"value":220},"    {\n",{"type":26,"tag":151,"props":222,"children":224},{"class":153,"line":223},6,[225,230,236],{"type":26,"tag":151,"props":226,"children":227},{"style":168},[228],{"type":31,"value":229},"      rel: ",{"type":26,"tag":151,"props":231,"children":233},{"style":232},"--shiki-default:#9ECBFF",[234],{"type":31,"value":235},"'preload'",{"type":26,"tag":151,"props":237,"children":238},{"style":168},[239],{"type":31,"value":240},",\n",{"type":26,"tag":151,"props":242,"children":244},{"class":153,"line":243},7,[245,250,255],{"type":26,"tag":151,"props":246,"children":247},{"style":168},[248],{"type":31,"value":249},"      href: ",{"type":26,"tag":151,"props":251,"children":252},{"style":232},[253],{"type":31,"value":254},"'\u002Ffonts\u002Finter-var.woff2'",{"type":26,"tag":151,"props":256,"children":257},{"style":168},[258],{"type":31,"value":240},{"type":26,"tag":151,"props":260,"children":262},{"class":153,"line":261},8,[263,268,273],{"type":26,"tag":151,"props":264,"children":265},{"style":168},[266],{"type":31,"value":267},"      as: ",{"type":26,"tag":151,"props":269,"children":270},{"style":232},[271],{"type":31,"value":272},"'font'",{"type":26,"tag":151,"props":274,"children":275},{"style":168},[276],{"type":31,"value":240},{"type":26,"tag":151,"props":278,"children":279},{"class":153,"line":20},[280,285,290],{"type":26,"tag":151,"props":281,"children":282},{"style":168},[283],{"type":31,"value":284},"      type: ",{"type":26,"tag":151,"props":286,"children":287},{"style":232},[288],{"type":31,"value":289},"'font\u002Fwoff2'",{"type":26,"tag":151,"props":291,"children":292},{"style":168},[293],{"type":31,"value":240},{"type":26,"tag":151,"props":295,"children":297},{"class":153,"line":296},10,[298,303],{"type":26,"tag":151,"props":299,"children":300},{"style":168},[301],{"type":31,"value":302},"      crossorigin: ",{"type":26,"tag":151,"props":304,"children":305},{"style":232},[306],{"type":31,"value":307},"'anonymous'\n",{"type":26,"tag":151,"props":309,"children":311},{"class":153,"line":310},11,[312],{"type":26,"tag":151,"props":313,"children":314},{"style":168},[315],{"type":31,"value":316},"    }\n",{"type":26,"tag":151,"props":318,"children":320},{"class":153,"line":319},12,[321],{"type":26,"tag":151,"props":322,"children":323},{"style":168},[324],{"type":31,"value":325},"  ]\n",{"type":26,"tag":151,"props":327,"children":329},{"class":153,"line":328},13,[330],{"type":26,"tag":151,"props":331,"children":332},{"style":168},[333],{"type":31,"value":334},"})\n",{"type":26,"tag":151,"props":336,"children":338},{"class":153,"line":337},14,[339,344,348],{"type":26,"tag":151,"props":340,"children":341},{"style":168},[342],{"type":31,"value":343},"\u003C\u002F",{"type":26,"tag":151,"props":345,"children":346},{"style":174},[347],{"type":31,"value":177},{"type":26,"tag":151,"props":349,"children":350},{"style":168},[351],{"type":31,"value":188},{"type":26,"tag":151,"props":353,"children":355},{"class":153,"line":354},15,[356],{"type":26,"tag":151,"props":357,"children":359},{"emptyLinePlaceholder":358},true,[360],{"type":31,"value":361},"\n",{"type":26,"tag":151,"props":363,"children":365},{"class":153,"line":364},16,[366,370,375],{"type":26,"tag":151,"props":367,"children":368},{"style":168},[369],{"type":31,"value":171},{"type":26,"tag":151,"props":371,"children":372},{"style":174},[373],{"type":31,"value":374},"style",{"type":26,"tag":151,"props":376,"children":377},{"style":168},[378],{"type":31,"value":188},{"type":26,"tag":151,"props":380,"children":382},{"class":153,"line":381},17,[383,388],{"type":26,"tag":151,"props":384,"children":386},{"style":385},"--shiki-default:#F97583",[387],{"type":31,"value":121},{"type":26,"tag":151,"props":389,"children":390},{"style":168},[391],{"type":31,"value":392}," {\n",{"type":26,"tag":151,"props":394,"children":396},{"class":153,"line":395},18,[397,403,408,413],{"type":26,"tag":151,"props":398,"children":400},{"style":399},"--shiki-default:#79B8FF",[401],{"type":31,"value":402},"  font-family",{"type":26,"tag":151,"props":404,"children":405},{"style":168},[406],{"type":31,"value":407},": ",{"type":26,"tag":151,"props":409,"children":410},{"style":232},[411],{"type":31,"value":412},"'Inter'",{"type":26,"tag":151,"props":414,"children":415},{"style":168},[416],{"type":31,"value":417},";\n",{"type":26,"tag":151,"props":419,"children":421},{"class":153,"line":420},19,[422,427,431,436,441,445,450,455,459,464],{"type":26,"tag":151,"props":423,"children":424},{"style":399},[425],{"type":31,"value":426},"  src",{"type":26,"tag":151,"props":428,"children":429},{"style":168},[430],{"type":31,"value":407},{"type":26,"tag":151,"props":432,"children":433},{"style":399},[434],{"type":31,"value":435},"url",{"type":26,"tag":151,"props":437,"children":438},{"style":168},[439],{"type":31,"value":440},"(",{"type":26,"tag":151,"props":442,"children":443},{"style":232},[444],{"type":31,"value":254},{"type":26,"tag":151,"props":446,"children":447},{"style":168},[448],{"type":31,"value":449},") ",{"type":26,"tag":151,"props":451,"children":452},{"style":399},[453],{"type":31,"value":454},"format",{"type":26,"tag":151,"props":456,"children":457},{"style":168},[458],{"type":31,"value":440},{"type":26,"tag":151,"props":460,"children":461},{"style":232},[462],{"type":31,"value":463},"'woff2'",{"type":26,"tag":151,"props":465,"children":466},{"style":168},[467],{"type":31,"value":468},");\n",{"type":26,"tag":151,"props":470,"children":472},{"class":153,"line":471},20,[473,478,482,487],{"type":26,"tag":151,"props":474,"children":475},{"style":399},[476],{"type":31,"value":477},"  font-display",{"type":26,"tag":151,"props":479,"children":480},{"style":168},[481],{"type":31,"value":407},{"type":26,"tag":151,"props":483,"children":484},{"style":399},[485],{"type":31,"value":486},"swap",{"type":26,"tag":151,"props":488,"children":489},{"style":168},[490],{"type":31,"value":417},{"type":26,"tag":151,"props":492,"children":494},{"class":153,"line":493},21,[495,500,504,509,514],{"type":26,"tag":151,"props":496,"children":497},{"style":399},[498],{"type":31,"value":499},"  font-weight",{"type":26,"tag":151,"props":501,"children":502},{"style":168},[503],{"type":31,"value":407},{"type":26,"tag":151,"props":505,"children":506},{"style":399},[507],{"type":31,"value":508},"100",{"type":26,"tag":151,"props":510,"children":511},{"style":399},[512],{"type":31,"value":513}," 900",{"type":26,"tag":151,"props":515,"children":516},{"style":168},[517],{"type":31,"value":417},{"type":26,"tag":151,"props":519,"children":521},{"class":153,"line":520},22,[522],{"type":26,"tag":151,"props":523,"children":524},{"style":168},[525],{"type":31,"value":526},"}\n",{"type":26,"tag":151,"props":528,"children":530},{"class":153,"line":529},23,[531,535,539],{"type":26,"tag":151,"props":532,"children":533},{"style":168},[534],{"type":31,"value":343},{"type":26,"tag":151,"props":536,"children":537},{"style":174},[538],{"type":31,"value":374},{"type":26,"tag":151,"props":540,"children":541},{"style":168},[542],{"type":31,"value":188},{"type":26,"tag":27,"props":544,"children":545},{},[546,551,553,558],{"type":26,"tag":54,"props":547,"children":548},{},[549],{"type":31,"value":550},"Guadagno:",{"type":31,"value":552}," LCP 10,2s → 7,8s (riduzione di 2,4s). Il caricamento font esce dalla categoria render-blocking, FOIT (Flash of Invisible Text) passa da 1200ms a 180ms. ",{"type":26,"tag":54,"props":554,"children":555},{},[556],{"type":31,"value":557},"Trade-off:",{"type":31,"value":559}," i file font vivono ora nel nostro CDN, la versionatura diventa manuale (noi l'abbiamo risolta con bucket Cloudflare R2 + header Cache-Control).",{"type":26,"tag":34,"props":561,"children":563},{"id":562},"lazy-hydration-selettiva-content-visibility",[564,566],{"type":31,"value":565},"Lazy hydration selettiva + ",{"type":26,"tag":108,"props":567,"children":569},{"className":568},[],[570],{"type":31,"value":571},"content-visibility",{"type":26,"tag":27,"props":573,"children":574},{},[575,577,583,585,591],{"type":31,"value":576},"Il comportamento di default di Nuxt 3 è idratare ogni component. Ma i component che non stanno above-the-fold (footer, sezione commenti, prodotti correlati) non hanno bisogno di essere idratati prima che l'utente scrolli. Con il modulo ",{"type":26,"tag":108,"props":578,"children":580},{"className":579},[],[581],{"type":31,"value":582},"@nuxt\u002Flazy-hydration",{"type":31,"value":584}," abbiamo wrappato questi component in ",{"type":26,"tag":108,"props":586,"children":588},{"className":587},[],[589],{"type":31,"value":590},"LazyHydrate",{"type":31,"value":592},".",{"type":26,"tag":141,"props":594,"children":596},{"className":143,"code":595,"language":145,"meta":9,"style":9},"\u003Ctemplate>\n  \u003CLazyHydrate when-visible>\n    \u003CProductRecommendations :product-id=\"productId\" \u002F>\n  \u003C\u002FLazyHydrate>\n\u003C\u002Ftemplate>\n",[597],{"type":26,"tag":108,"props":598,"children":599},{"__ignoreMap":9},[600,616,637,670,686],{"type":26,"tag":151,"props":601,"children":602},{"class":153,"line":154},[603,607,612],{"type":26,"tag":151,"props":604,"children":605},{"style":168},[606],{"type":31,"value":171},{"type":26,"tag":151,"props":608,"children":609},{"style":174},[610],{"type":31,"value":611},"template",{"type":26,"tag":151,"props":613,"children":614},{"style":168},[615],{"type":31,"value":188},{"type":26,"tag":151,"props":617,"children":618},{"class":153,"line":164},[619,624,628,633],{"type":26,"tag":151,"props":620,"children":621},{"style":168},[622],{"type":31,"value":623},"  \u003C",{"type":26,"tag":151,"props":625,"children":626},{"style":174},[627],{"type":31,"value":590},{"type":26,"tag":151,"props":629,"children":630},{"style":180},[631],{"type":31,"value":632}," when-visible",{"type":26,"tag":151,"props":634,"children":635},{"style":168},[636],{"type":31,"value":188},{"type":26,"tag":151,"props":638,"children":639},{"class":153,"line":191},[640,645,650,655,660,665],{"type":26,"tag":151,"props":641,"children":642},{"style":168},[643],{"type":31,"value":644},"    \u003C",{"type":26,"tag":151,"props":646,"children":647},{"style":174},[648],{"type":31,"value":649},"ProductRecommendations",{"type":26,"tag":151,"props":651,"children":652},{"style":180},[653],{"type":31,"value":654}," :product-id",{"type":26,"tag":151,"props":656,"children":657},{"style":168},[658],{"type":31,"value":659},"=",{"type":26,"tag":151,"props":661,"children":662},{"style":232},[663],{"type":31,"value":664},"\"productId\"",{"type":26,"tag":151,"props":666,"children":667},{"style":168},[668],{"type":31,"value":669}," \u002F>\n",{"type":26,"tag":151,"props":671,"children":672},{"class":153,"line":205},[673,678,682],{"type":26,"tag":151,"props":674,"children":675},{"style":168},[676],{"type":31,"value":677},"  \u003C\u002F",{"type":26,"tag":151,"props":679,"children":680},{"style":174},[681],{"type":31,"value":590},{"type":26,"tag":151,"props":683,"children":684},{"style":168},[685],{"type":31,"value":188},{"type":26,"tag":151,"props":687,"children":688},{"class":153,"line":214},[689,693,697],{"type":26,"tag":151,"props":690,"children":691},{"style":168},[692],{"type":31,"value":343},{"type":26,"tag":151,"props":694,"children":695},{"style":174},[696],{"type":31,"value":611},{"type":26,"tag":151,"props":698,"children":699},{"style":168},[700],{"type":31,"value":188},{"type":26,"tag":27,"props":702,"children":703},{},[704,706,712],{"type":31,"value":705},"Dal lato CSS, ",{"type":26,"tag":108,"props":707,"children":709},{"className":708},[],[710],{"type":31,"value":711},"content-visibility: auto",{"type":31,"value":713}," comunica al browser: \"non fare calcoli di rendering per questo elemento se non è nel viewport\".",{"type":26,"tag":141,"props":715,"children":719},{"className":716,"code":717,"language":718,"meta":9,"style":9},"language-css shiki shiki-themes github-dark",".product-recommendations {\n  content-visibility: auto;\n  contain-intrinsic-size: 0 500px; \u002F* placeholder height *\u002F\n}\n","css",[720],{"type":26,"tag":108,"props":721,"children":722},{"__ignoreMap":9},[723,735,756,793],{"type":26,"tag":151,"props":724,"children":725},{"class":153,"line":154},[726,731],{"type":26,"tag":151,"props":727,"children":728},{"style":180},[729],{"type":31,"value":730},".product-recommendations",{"type":26,"tag":151,"props":732,"children":733},{"style":168},[734],{"type":31,"value":392},{"type":26,"tag":151,"props":736,"children":737},{"class":153,"line":164},[738,743,747,752],{"type":26,"tag":151,"props":739,"children":740},{"style":399},[741],{"type":31,"value":742},"  content-visibility",{"type":26,"tag":151,"props":744,"children":745},{"style":168},[746],{"type":31,"value":407},{"type":26,"tag":151,"props":748,"children":749},{"style":399},[750],{"type":31,"value":751},"auto",{"type":26,"tag":151,"props":753,"children":754},{"style":168},[755],{"type":31,"value":417},{"type":26,"tag":151,"props":757,"children":758},{"class":153,"line":191},[759,764,768,773,778,783,788],{"type":26,"tag":151,"props":760,"children":761},{"style":399},[762],{"type":31,"value":763},"  contain-intrinsic-size",{"type":26,"tag":151,"props":765,"children":766},{"style":168},[767],{"type":31,"value":407},{"type":26,"tag":151,"props":769,"children":770},{"style":399},[771],{"type":31,"value":772},"0",{"type":26,"tag":151,"props":774,"children":775},{"style":399},[776],{"type":31,"value":777}," 500",{"type":26,"tag":151,"props":779,"children":780},{"style":385},[781],{"type":31,"value":782},"px",{"type":26,"tag":151,"props":784,"children":785},{"style":168},[786],{"type":31,"value":787},"; ",{"type":26,"tag":151,"props":789,"children":790},{"style":158},[791],{"type":31,"value":792},"\u002F* placeholder height *\u002F\n",{"type":26,"tag":151,"props":794,"children":795},{"class":153,"line":205},[796],{"type":26,"tag":151,"props":797,"children":798},{"style":168},[799],{"type":31,"value":526},{"type":26,"tag":27,"props":801,"children":802},{},[803,807,809,813,815,821],{"type":26,"tag":54,"props":804,"children":805},{},[806],{"type":31,"value":550},{"type":31,"value":808}," TBT 2190ms → 420ms, LCP 7,8s → 4,1s. Il bundle JS iniziale è sceso da 420kB a 180kB (brotli-compressed). ",{"type":26,"tag":54,"props":810,"children":811},{},[812],{"type":31,"value":557},{"type":31,"value":814}," ",{"type":26,"tag":108,"props":816,"children":818},{"className":817},[],[819],{"type":31,"value":820},"when-visible",{"type":31,"value":822}," si affida all'Intersection Observer API; il polyfill per browser vecchi (IE11) è necessario, anche se nel nostro caso (target browser moderni) non è stato un problema.",{"type":26,"tag":34,"props":824,"children":826},{"id":825},"edge-caching-approccio-ibrido-isr",[827],{"type":31,"value":828},"Edge caching + approccio ibrido ISR",{"type":26,"tag":27,"props":830,"children":831},{},[832,834,840,842,848,850,856],{"type":31,"value":833},"Cloudflare Pages per default cachea i file statici ma non gli endpoint SSR (tutto fuori da ",{"type":26,"tag":108,"props":835,"children":837},{"className":836},[],[838],{"type":31,"value":839},"\u002F_nuxt\u002F...",{"type":31,"value":841},"). In ",{"type":26,"tag":108,"props":843,"children":845},{"className":844},[],[846],{"type":31,"value":847},"nuxt.config.ts",{"type":31,"value":849}," abbiamo definito ",{"type":26,"tag":108,"props":851,"children":853},{"className":852},[],[854],{"type":31,"value":855},"routeRules",{"type":31,"value":857}," per specificare quali path cacheare e per quanto tempo:",{"type":26,"tag":141,"props":859,"children":863},{"className":860,"code":861,"language":862,"meta":9,"style":9},"language-ts shiki shiki-themes github-dark","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  routeRules: {\n    '\u002F': { swr: 3600 }, \u002F\u002F homepage 1h stale-while-revalidate\n    '\u002Furun\u002F**': { swr: 1800 }, \u002F\u002F pagine prodotto 30m\n    '\u002Fkategori\u002F**': { static: true } \u002F\u002F pagine categoria static build-time\n  }\n})\n","ts",[864],{"type":26,"tag":108,"props":865,"children":866},{"__ignoreMap":9},[867,875,897,905,933,959,987,995],{"type":26,"tag":151,"props":868,"children":869},{"class":153,"line":154},[870],{"type":26,"tag":151,"props":871,"children":872},{"style":158},[873],{"type":31,"value":874},"\u002F\u002F nuxt.config.ts\n",{"type":26,"tag":151,"props":876,"children":877},{"class":153,"line":164},[878,883,888,893],{"type":26,"tag":151,"props":879,"children":880},{"style":385},[881],{"type":31,"value":882},"export",{"type":26,"tag":151,"props":884,"children":885},{"style":385},[886],{"type":31,"value":887}," default",{"type":26,"tag":151,"props":889,"children":890},{"style":180},[891],{"type":31,"value":892}," defineNuxtConfig",{"type":26,"tag":151,"props":894,"children":895},{"style":168},[896],{"type":31,"value":202},{"type":26,"tag":151,"props":898,"children":899},{"class":153,"line":191},[900],{"type":26,"tag":151,"props":901,"children":902},{"style":168},[903],{"type":31,"value":904},"  routeRules: {\n",{"type":26,"tag":151,"props":906,"children":907},{"class":153,"line":205},[908,913,918,923,928],{"type":26,"tag":151,"props":909,"children":910},{"style":232},[911],{"type":31,"value":912},"    '\u002F'",{"type":26,"tag":151,"props":914,"children":915},{"style":168},[916],{"type":31,"value":917},": { swr: ",{"type":26,"tag":151,"props":919,"children":920},{"style":399},[921],{"type":31,"value":922},"3600",{"type":26,"tag":151,"props":924,"children":925},{"style":168},[926],{"type":31,"value":927}," }, ",{"type":26,"tag":151,"props":929,"children":930},{"style":158},[931],{"type":31,"value":932},"\u002F\u002F homepage 1h stale-while-revalidate\n",{"type":26,"tag":151,"props":934,"children":935},{"class":153,"line":214},[936,941,945,950,954],{"type":26,"tag":151,"props":937,"children":938},{"style":232},[939],{"type":31,"value":940},"    '\u002Furun\u002F**'",{"type":26,"tag":151,"props":942,"children":943},{"style":168},[944],{"type":31,"value":917},{"type":26,"tag":151,"props":946,"children":947},{"style":399},[948],{"type":31,"value":949},"1800",{"type":26,"tag":151,"props":951,"children":952},{"style":168},[953],{"type":31,"value":927},{"type":26,"tag":151,"props":955,"children":956},{"style":158},[957],{"type":31,"value":958},"\u002F\u002F pagine prodotto 30m\n",{"type":26,"tag":151,"props":960,"children":961},{"class":153,"line":223},[962,967,972,977,982],{"type":26,"tag":151,"props":963,"children":964},{"style":232},[965],{"type":31,"value":966},"    '\u002Fkategori\u002F**'",{"type":26,"tag":151,"props":968,"children":969},{"style":168},[970],{"type":31,"value":971},": { static: ",{"type":26,"tag":151,"props":973,"children":974},{"style":399},[975],{"type":31,"value":976},"true",{"type":26,"tag":151,"props":978,"children":979},{"style":168},[980],{"type":31,"value":981}," } ",{"type":26,"tag":151,"props":983,"children":984},{"style":158},[985],{"type":31,"value":986},"\u002F\u002F pagine categoria static build-time\n",{"type":26,"tag":151,"props":988,"children":989},{"class":153,"line":243},[990],{"type":26,"tag":151,"props":991,"children":992},{"style":168},[993],{"type":31,"value":994},"  }\n",{"type":26,"tag":151,"props":996,"children":997},{"class":153,"line":261},[998],{"type":26,"tag":151,"props":999,"children":1000},{"style":168},[1001],{"type":31,"value":334},{"type":26,"tag":27,"props":1003,"children":1004},{},[1005,1007,1013],{"type":31,"value":1006},"La strategia ",{"type":26,"tag":108,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":31,"value":1012},"swr",{"type":31,"value":1014}," (stale-while-revalidate): la prima request fa SSR render, le request successive vengono dalla cache mentre il re-render accade in background. Abbiamo usato Cloudflare KV store con URL + user segment (logged-in\u002Fanonimo) come cache key.",{"type":26,"tag":27,"props":1016,"children":1017},{},[1018,1022,1024,1028],{"type":26,"tag":54,"props":1019,"children":1020},{},[1021],{"type":31,"value":550},{"type":31,"value":1023}," TTFB (Time to First Byte) 840ms → 120ms, LCP 4,1s → 2,3s. Cache hit rate prima settimana 78%. ",{"type":26,"tag":54,"props":1025,"children":1026},{},[1027],{"type":31,"value":557},{"type":31,"value":1029}," la personalizzazione dipende dalla cache key; dati user-specific (numero di articoli nel carrello) non possono essere cachati, li fetchiamo client-side.",{"type":26,"tag":34,"props":1031,"children":1033},{"id":1032},"ottimizzazione-immagine-above-the-fold",[1034],{"type":31,"value":1035},"Ottimizzazione immagine above-the-fold",{"type":26,"tag":27,"props":1037,"children":1038},{},[1039,1041,1047],{"type":31,"value":1040},"L'immagine hero è passata da JPEG 1,2MB a WebP 180kB; abbiamo aggiunto breakpoint responsivi con ",{"type":26,"tag":108,"props":1042,"children":1044},{"className":1043},[],[1045],{"type":31,"value":1046},"\u003Cpicture>",{"type":31,"value":1048},":",{"type":26,"tag":141,"props":1050,"children":1052},{"className":143,"code":1051,"language":145,"meta":9,"style":9},"\u003Cpicture>\n  \u003Csource\n    srcset=\"\u002Fimages\u002Fhero-mobile.webp\"\n    media=\"(max-width: 640px)\"\n    type=\"image\u002Fwebp\"\n  \u002F>\n  \u003Csource\n    srcset=\"\u002Fimages\u002Fhero-desktop.webp\"\n    media=\"(min-width: 641px)\"\n    type=\"image\u002Fwebp\"\n  \u002F>\n  \u003Cimg\n    src=\"\u002Fimages\u002Fhero-desktop.jpg\"\n    alt=\"Collezione nuova stagione\"\n    fetchpriority=\"high\"\n    decoding=\"async\"\n  \u002F>\n\u003C\u002Fpicture>\n",[1053],{"type":26,"tag":108,"props":1054,"children":1055},{"__ignoreMap":9},[1056,1072,1080,1088,1096,1104,1112,1119,1127,1135,1142,1149,1157,1165,1173,1181,1189,1196],{"type":26,"tag":151,"props":1057,"children":1058},{"class":153,"line":154},[1059,1063,1068],{"type":26,"tag":151,"props":1060,"children":1061},{"style":168},[1062],{"type":31,"value":171},{"type":26,"tag":151,"props":1064,"children":1065},{"style":174},[1066],{"type":31,"value":1067},"picture",{"type":26,"tag":151,"props":1069,"children":1070},{"style":168},[1071],{"type":31,"value":188},{"type":26,"tag":151,"props":1073,"children":1074},{"class":153,"line":164},[1075],{"type":26,"tag":151,"props":1076,"children":1077},{"style":168},[1078],{"type":31,"value":1079},"  \u003Csource\n",{"type":26,"tag":151,"props":1081,"children":1082},{"class":153,"line":191},[1083],{"type":26,"tag":151,"props":1084,"children":1085},{"style":168},[1086],{"type":31,"value":1087},"    srcset=\"\u002Fimages\u002Fhero-mobile.webp\"\n",{"type":26,"tag":151,"props":1089,"children":1090},{"class":153,"line":205},[1091],{"type":26,"tag":151,"props":1092,"children":1093},{"style":168},[1094],{"type":31,"value":1095},"    media=\"(max-width: 640px)\"\n",{"type":26,"tag":151,"props":1097,"children":1098},{"class":153,"line":214},[1099],{"type":26,"tag":151,"props":1100,"children":1101},{"style":168},[1102],{"type":31,"value":1103},"    type=\"image\u002Fwebp\"\n",{"type":26,"tag":151,"props":1105,"children":1106},{"class":153,"line":223},[1107],{"type":26,"tag":151,"props":1108,"children":1109},{"style":168},[1110],{"type":31,"value":1111},"  \u002F>\n",{"type":26,"tag":151,"props":1113,"children":1114},{"class":153,"line":243},[1115],{"type":26,"tag":151,"props":1116,"children":1117},{"style":168},[1118],{"type":31,"value":1079},{"type":26,"tag":151,"props":1120,"children":1121},{"class":153,"line":261},[1122],{"type":26,"tag":151,"props":1123,"children":1124},{"style":168},[1125],{"type":31,"value":1126},"    srcset=\"\u002Fimages\u002Fhero-desktop.webp\"\n",{"type":26,"tag":151,"props":1128,"children":1129},{"class":153,"line":20},[1130],{"type":26,"tag":151,"props":1131,"children":1132},{"style":168},[1133],{"type":31,"value":1134},"    media=\"(min-width: 641px)\"\n",{"type":26,"tag":151,"props":1136,"children":1137},{"class":153,"line":296},[1138],{"type":26,"tag":151,"props":1139,"children":1140},{"style":168},[1141],{"type":31,"value":1103},{"type":26,"tag":151,"props":1143,"children":1144},{"class":153,"line":310},[1145],{"type":26,"tag":151,"props":1146,"children":1147},{"style":168},[1148],{"type":31,"value":1111},{"type":26,"tag":151,"props":1150,"children":1151},{"class":153,"line":319},[1152],{"type":26,"tag":151,"props":1153,"children":1154},{"style":168},[1155],{"type":31,"value":1156},"  \u003Cimg\n",{"type":26,"tag":151,"props":1158,"children":1159},{"class":153,"line":328},[1160],{"type":26,"tag":151,"props":1161,"children":1162},{"style":168},[1163],{"type":31,"value":1164},"    src=\"\u002Fimages\u002Fhero-desktop.jpg\"\n",{"type":26,"tag":151,"props":1166,"children":1167},{"class":153,"line":337},[1168],{"type":26,"tag":151,"props":1169,"children":1170},{"style":168},[1171],{"type":31,"value":1172},"    alt=\"Collezione nuova stagione\"\n",{"type":26,"tag":151,"props":1174,"children":1175},{"class":153,"line":354},[1176],{"type":26,"tag":151,"props":1177,"children":1178},{"style":168},[1179],{"type":31,"value":1180},"    fetchpriority=\"high\"\n",{"type":26,"tag":151,"props":1182,"children":1183},{"class":153,"line":364},[1184],{"type":26,"tag":151,"props":1185,"children":1186},{"style":168},[1187],{"type":31,"value":1188},"    decoding=\"async\"\n",{"type":26,"tag":151,"props":1190,"children":1191},{"class":153,"line":381},[1192],{"type":26,"tag":151,"props":1193,"children":1194},{"style":168},[1195],{"type":31,"value":1111},{"type":26,"tag":151,"props":1197,"children":1198},{"class":153,"line":395},[1199,1203,1207],{"type":26,"tag":151,"props":1200,"children":1201},{"style":168},[1202],{"type":31,"value":343},{"type":26,"tag":151,"props":1204,"children":1205},{"style":174},[1206],{"type":31,"value":1067},{"type":26,"tag":151,"props":1208,"children":1209},{"style":168},[1210],{"type":31,"value":188},{"type":26,"tag":27,"props":1212,"children":1213},{},[1214,1216,1222],{"type":31,"value":1215},"L'attributo ",{"type":26,"tag":108,"props":1217,"children":1219},{"className":1218},[],[1220],{"type":31,"value":1221},"fetchpriority=\"high\"",{"type":31,"value":1223}," comunica al browser: \"carica questa immagine con priorità\". Cloudflare Image Resizing gestisce la conversione formato agli edge (serve JPEG ai browser che non supportano WebP).",{"type":26,"tag":27,"props":1225,"children":1226},{},[1227,1231,1233,1239],{"type":26,"tag":54,"props":1228,"children":1229},{},[1230],{"type":31,"value":550},{"type":31,"value":1232}," LCP 2,3s → 2,1s, tempo caricamento immagine 1200ms → 320ms. CLS (Cumulative Layout Shift) 0,12 → 0,02 — abbiamo reservato lo spazio con la proprietà CSS ",{"type":26,"tag":108,"props":1234,"children":1236},{"className":1235},[],[1237],{"type":31,"value":1238},"aspect-ratio",{"type":31,"value":592},{"type":26,"tag":34,"props":1241,"children":1243},{"id":1242},"risultati-del-benchmark-impatto-su-utenti-reali",[1244],{"type":31,"value":1245},"Risultati del benchmark + impatto su utenti reali",{"type":26,"tag":27,"props":1247,"children":1248},{},[1249],{"type":31,"value":1250},"PageSpeed Insights mobile score 34 → 92, desktop 62 → 98. Media CrUX a 28 giorni:",{"type":26,"tag":1252,"props":1253,"children":1254},"table",{},[1255,1284],{"type":26,"tag":1256,"props":1257,"children":1258},"thead",{},[1259],{"type":26,"tag":1260,"props":1261,"children":1262},"tr",{},[1263,1269,1274,1279],{"type":26,"tag":1264,"props":1265,"children":1266},"th",{},[1267],{"type":31,"value":1268},"Metrica",{"type":26,"tag":1264,"props":1270,"children":1271},{},[1272],{"type":31,"value":1273},"Prima",{"type":26,"tag":1264,"props":1275,"children":1276},{},[1277],{"type":31,"value":1278},"Dopo",{"type":26,"tag":1264,"props":1280,"children":1281},{},[1282],{"type":31,"value":1283},"Variazione",{"type":26,"tag":1285,"props":1286,"children":1287},"tbody",{},[1288,1312,1335,1358],{"type":26,"tag":1260,"props":1289,"children":1290},{},[1291,1297,1302,1307],{"type":26,"tag":1292,"props":1293,"children":1294},"td",{},[1295],{"type":31,"value":1296},"LCP",{"type":26,"tag":1292,"props":1298,"children":1299},{},[1300],{"type":31,"value":1301},"10,2s",{"type":26,"tag":1292,"props":1303,"children":1304},{},[1305],{"type":31,"value":1306},"2,1s",{"type":26,"tag":1292,"props":1308,"children":1309},{},[1310],{"type":31,"value":1311},"-79%",{"type":26,"tag":1260,"props":1313,"children":1314},{},[1315,1320,1325,1330],{"type":26,"tag":1292,"props":1316,"children":1317},{},[1318],{"type":31,"value":1319},"TBT",{"type":26,"tag":1292,"props":1321,"children":1322},{},[1323],{"type":31,"value":1324},"2190ms",{"type":26,"tag":1292,"props":1326,"children":1327},{},[1328],{"type":31,"value":1329},"420ms",{"type":26,"tag":1292,"props":1331,"children":1332},{},[1333],{"type":31,"value":1334},"-81%",{"type":26,"tag":1260,"props":1336,"children":1337},{},[1338,1343,1348,1353],{"type":26,"tag":1292,"props":1339,"children":1340},{},[1341],{"type":31,"value":1342},"CLS",{"type":26,"tag":1292,"props":1344,"children":1345},{},[1346],{"type":31,"value":1347},"0,12",{"type":26,"tag":1292,"props":1349,"children":1350},{},[1351],{"type":31,"value":1352},"0,02",{"type":26,"tag":1292,"props":1354,"children":1355},{},[1356],{"type":31,"value":1357},"-83%",{"type":26,"tag":1260,"props":1359,"children":1360},{},[1361,1366,1371,1376],{"type":26,"tag":1292,"props":1362,"children":1363},{},[1364],{"type":31,"value":1365},"TTFB",{"type":26,"tag":1292,"props":1367,"children":1368},{},[1369],{"type":31,"value":1370},"840ms",{"type":26,"tag":1292,"props":1372,"children":1373},{},[1374],{"type":31,"value":1375},"120ms",{"type":26,"tag":1292,"props":1377,"children":1378},{},[1379],{"type":31,"value":1380},"-86%",{"type":26,"tag":27,"props":1382,"children":1383},{},[1384,1386,1395],{"type":31,"value":1385},"Funnel conversione Google Analytics: tasso di inizio checkout sale da 3,2% a 4,8% (+50% relativo). Bounce rate 68% → 52%. Search Console: traffico organico aumenta del 34% in 2 mesi (altre variabili SEO costanti). Questi numeri rispecchiano gli obiettivi standard di Roibase nell'approccio ",{"type":26,"tag":1387,"props":1388,"children":1392},"a",{"href":1389,"rel":1390},"https:\u002F\u002Fwww.roibase.com.tr\u002Fit\u002Fheadless",[1391],"nofollow",[1393],{"type":31,"value":1394},"Headless Commerce",{"type":31,"value":1396}," — se la performance non si converte in metriche di business, il cambio architetturale non è considerato vincente.",{"type":26,"tag":34,"props":1398,"children":1400},{"id":1399},"trade-off-e-criteri-decisionali",[1401],{"type":31,"value":1402},"Trade-off e criteri decisionali",{"type":26,"tag":27,"props":1404,"children":1405},{},[1406,1411,1413,1418,1420,1426],{"type":26,"tag":54,"props":1407,"children":1408},{},[1409],{"type":31,"value":1410},"Developer experience:",{"type":31,"value":1412}," aggiungere il wrapper lazy hydration espande la surface area dell'API dei component; i nuovi developer devono imparare la differenza tra ",{"type":26,"tag":108,"props":1414,"children":1416},{"className":1415},[],[1417],{"type":31,"value":820},{"type":31,"value":1419}," e ",{"type":26,"tag":108,"props":1421,"children":1423},{"className":1422},[],[1424],{"type":31,"value":1425},"when-idle",{"type":31,"value":1427},". L'abbiamo gestito con documentazione Storybook + ESLint rule.",{"type":26,"tag":27,"props":1429,"children":1430},{},[1431,1436],{"type":26,"tag":54,"props":1432,"children":1433},{},[1434],{"type":31,"value":1435},"Bundle size vs cost runtime:",{"type":31,"value":1437}," i file font self-hosted aggiungono +60kB al bundle iniziale, ma eliminano il costo di DNS lookup + TLS handshake del CDN esterno. Su reti mobile 3G è un guadagno netto; su fibra è neutrale.",{"type":26,"tag":27,"props":1439,"children":1440},{},[1441,1446,1448,1453],{"type":26,"tag":54,"props":1442,"children":1443},{},[1444],{"type":31,"value":1445},"Invalidazione cache:",{"type":31,"value":1447}," la strategia ",{"type":26,"tag":108,"props":1449,"children":1451},{"className":1450},[],[1452],{"type":31,"value":1012},{"type":31,"value":1454}," comporta il rischio di dati stantii. Per dati critici come disponibilità di stock, usiamo fetch client-side realtime (polling ogni 30s invece di WebSocket per ridurre i costi di edge function).",{"type":26,"tag":27,"props":1456,"children":1457},{},[1458,1463],{"type":26,"tag":54,"props":1459,"children":1460},{},[1461],{"type":31,"value":1462},"Vendor lock-in Cloudflare:",{"type":31,"value":1464}," il caching basato su KV è specifico di Cloudflare; migrare ad altro provider richiederebbe re-implementation. Però Vercel e Netlify hanno primitive simili, l'effort di migrazione è accettabile.",{"type":26,"tag":34,"props":1466,"children":1468},{"id":1467},"prossimi-passi",[1469],{"type":31,"value":1470},"Prossimi passi",{"type":26,"tag":27,"props":1472,"children":1473},{},[1474],{"type":31,"value":1475},"2,1s di LCP è buono, ma il P75 (75° percentile) in CrUX è ancora 3,2s. La roadmap:",{"type":26,"tag":1477,"props":1478,"children":1479},"ol",{},[1480,1490,1500,1510],{"type":26,"tag":50,"props":1481,"children":1482},{},[1483,1488],{"type":26,"tag":54,"props":1484,"children":1485},{},[1486],{"type":31,"value":1487},"Image CDN + automatic format negotiation:",{"type":31,"value":1489}," passare a Imgix da Cloudflare Polish, supporto AVIF",{"type":26,"tag":50,"props":1491,"children":1492},{},[1493,1498],{"type":26,"tag":54,"props":1494,"children":1495},{},[1496],{"type":31,"value":1497},"Prefetch strategy:",{"type":31,"value":1499}," Intersection Observer per prefetch dati delle product card quando entrano nel viewport",{"type":26,"tag":50,"props":1501,"children":1502},{},[1503,1508],{"type":26,"tag":54,"props":1504,"children":1505},{},[1506],{"type":31,"value":1507},"Service Worker + offline-first:",{"type":31,"value":1509}," Workbox per cacheare asset critici, network-first fallback",{"type":26,"tag":50,"props":1511,"children":1512},{},[1513,1518],{"type":26,"tag":54,"props":1514,"children":1515},{},[1516],{"type":31,"value":1517},"Aggressive bundle splitting:",{"type":31,"value":1519}," code splitting di Nuxt 3 più aggressivo, chunking per route",{"type":26,"tag":27,"props":1521,"children":1522},{},[1523],{"type":31,"value":1524},"L'ottimizzazione performance è un gioco senza fine — ogni 100ms guadagnati porta 1-2% di lift in conversione. La combinazione Nuxt 3 + Cloudflare Pages offre l'equilibrio tra rendering agli edge + ergonomia di un framework JS moderno. Quando si decide lo stack, il target LCP deve essere un requirement di business; poi si valutano le scelte architetturali dentro questo vincolo.",{"type":26,"tag":374,"props":1526,"children":1527},{},[1528],{"type":31,"value":1529},"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":9,"searchDepth":191,"depth":191,"links":1531},[1532,1533,1534,1536,1537,1538,1539,1540],{"id":36,"depth":164,"text":39},{"id":98,"depth":164,"text":101},{"id":562,"depth":164,"text":1535},"Lazy hydration selettiva + content-visibility",{"id":825,"depth":164,"text":828},{"id":1032,"depth":164,"text":1035},{"id":1242,"depth":164,"text":1245},{"id":1399,"depth":164,"text":1402},{"id":1467,"depth":164,"text":1470},"markdown","content:it:tech:nuxt-3-cloudflare-pages-lcp-ottimizzazione.md","content","it\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-ottimizzazione.md","it\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-ottimizzazione","md",1778164176467]