[{"data":1,"prerenderedAt":1559},["ShallowReactive",2],{"article-alternates":3,"cat-ru-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":1553,"_id":1554,"_source":1555,"_file":1556,"_stem":1557,"_extension":1558},"\u002Fru\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-optimization","tech",false,"","Nuxt 3 + Cloudflare Pages: From 10s LCP to 2s","Self-hosted fonts, lazy hydration, content-visibility, and edge caching reduced LCP by 80%. Real benchmarks, code examples, and tradeoffs included.","2026-05-07","tech-001-2026-05",[15,16,17,18,19],"nuxt3","cloudflare-pages","web-performance","lcp","edge-caching",8,"Roibase",{"type":23,"children":24,"toc":1542},"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,1223,1240,1246,1251,1381,1397,1403,1435,1445,1461,1477,1483,1488,1532,1537],{"type":26,"tag":27,"props":28,"children":29},"element","p",{},[30],{"type":31,"value":32},"text","After Google's Core Web Vitals update, LCP (Largest Contentful Paint) must stay below 2.5 seconds—otherwise both organic rankings and conversion rates drop. When we migrated an e-commerce site to the Nuxt 3 + Cloudflare Pages stack, the first deploy landed LCP at 10.2 seconds. By combining self-hosted fonts, selective hydration, CSS content-visibility, and edge caching, we brought it down to 2.1 seconds. Below, we break down which change delivered which gain, explain the tradeoffs, and share the code.",{"type":26,"tag":34,"props":35,"children":37},"h2",{"id":36},"diagnosing-the-problem-anatomy-of-10s-lcp",[38],{"type":31,"value":39},"Diagnosing the problem: anatomy of 10s LCP",{"type":26,"tag":27,"props":41,"children":42},{},[43],{"type":31,"value":44},"The initial CrUX report showed a median LCP of 10.2s and TBT (Total Blocking Time) of 2190ms. Chrome DevTools Lighthouse profiling revealed:",{"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},"Font loading:",{"type":31,"value":60}," Three font families from 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},"JavaScript hydration:",{"type":31,"value":70}," 420kB bundle, entire page hydrated",{"type":26,"tag":50,"props":72,"children":73},{},[74,79],{"type":26,"tag":54,"props":75,"children":76},{},[77],{"type":31,"value":78},"Above-the-fold image:",{"type":31,"value":80}," 1.2MB JPEG, no lazy loading",{"type":26,"tag":50,"props":82,"children":83},{},[84,89],{"type":26,"tag":54,"props":85,"children":86},{},[87],{"type":31,"value":88},"Cloudflare cache:",{"type":31,"value":90}," SSR responses not cached; every request hit origin",{"type":26,"tag":27,"props":92,"children":93},{},[94],{"type":31,"value":95},"Baseline: PageSpeed Insights mobile score 34\u002F100. Desktop 62\u002F100. These numbers came right after transitioning from Shopify Liquid to Nuxt 3—a framework change alone doesn't guarantee performance gains; architectural optimization is required.",{"type":26,"tag":34,"props":97,"children":99},{"id":98},"self-hosted-fonts-preload-strategy",[100],{"type":31,"value":101},"Self-hosted fonts + preload strategy",{"type":26,"tag":27,"props":103,"children":104},{},[105,107,114,116,122,124,130,132,138],{"type":31,"value":106},"We downloaded the same fonts from Google Fonts into ",{"type":26,"tag":108,"props":109,"children":111},"code",{"className":110},[],[112],{"type":31,"value":113},"public\u002Ffonts\u002F",{"type":31,"value":115}," and moved the ",{"type":26,"tag":108,"props":117,"children":119},{"className":118},[],[120],{"type":31,"value":121},"@font-face",{"type":31,"value":123}," definition into ",{"type":26,"tag":108,"props":125,"children":127},{"className":126},[],[128],{"type":31,"value":129},"app.vue",{"type":31,"value":131},". The critical difference: ",{"type":26,"tag":108,"props":133,"children":135},{"className":134},[],[136],{"type":31,"value":137},"\u003Clink rel=\"preload\">",{"type":31,"value":139}," requests font files within the initial HTML response, before CSS parsing.",{"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,276,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":261},{"class":153,"line":20},[262,267,272],{"type":26,"tag":151,"props":263,"children":264},{"style":168},[265],{"type":31,"value":266},"      as: ",{"type":26,"tag":151,"props":268,"children":269},{"style":232},[270],{"type":31,"value":271},"'font'",{"type":26,"tag":151,"props":273,"children":274},{"style":168},[275],{"type":31,"value":240},{"type":26,"tag":151,"props":277,"children":279},{"class":153,"line":278},9,[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},"Gain:",{"type":31,"value":552}," LCP 10.2s → 7.8s (2.4s drop). Font loading moved out of the render-blocking path; FOIT (Flash of Invisible Text) dropped from 1200ms to 180ms. ",{"type":26,"tag":54,"props":554,"children":555},{},[556],{"type":31,"value":557},"Tradeoff:",{"type":31,"value":559}," Font files now live on our CDN, version management is manual. We solved this via Cloudflare R2 bucket + Cache-Control headers.",{"type":26,"tag":34,"props":561,"children":563},{"id":562},"selective-hydration-content-visibility",[564,566],{"type":31,"value":565},"Selective hydration + ",{"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},"Nuxt 3's default behavior hydrates every component. But components below the fold (footer, comments, related products) don't need hydration before the user scrolls. We wrapped non-critical components with ",{"type":26,"tag":108,"props":578,"children":580},{"className":579},[],[581],{"type":31,"value":582},"@nuxt\u002Flazy-hydration",{"type":31,"value":584},"'s ",{"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},"On the CSS side, ",{"type":26,"tag":108,"props":707,"children":709},{"className":708},[],[710],{"type":31,"value":711},"content-visibility: auto",{"type":31,"value":713}," signals the browser: \"don't do rendering work for elements outside the 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. Initial JS bundle 420kB → 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}," relies on intersection observer; older browsers like IE11 need polyfills. We target modern browsers, so no blocker.",{"type":26,"tag":34,"props":824,"children":826},{"id":825},"edge-caching-isr-hybrid-approach",[827],{"type":31,"value":828},"Edge caching + ISR hybrid approach",{"type":26,"tag":27,"props":830,"children":831},{},[832,834,840,842,848,850,856],{"type":31,"value":833},"Cloudflare Pages caches static files by default but not SSR endpoints outside ",{"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},", we defined ",{"type":26,"tag":108,"props":851,"children":853},{"className":852},[],[854],{"type":31,"value":855},"routeRules",{"type":31,"value":857}," to specify cache duration per path:",{"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 product pages 30m\n    '\u002Fkategori\u002F**': { static: true } \u002F\u002F category pages build-time static\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 product pages 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 category pages build-time static\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":20},[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},"The ",{"type":26,"tag":108,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":31,"value":1012},"swr",{"type":31,"value":1014}," (stale-while-revalidate) strategy: the first request triggers SSR rendering, subsequent requests serve from cache, and the page silently re-renders in the background. We used Cloudflare KV store with URL + user segment (logged-in\u002Fanonymous) as the 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 840ms → 120ms, LCP 4.1s → 2.3s. Cache hit rate reached 78% in the first week. ",{"type":26,"tag":54,"props":1025,"children":1026},{},[1027],{"type":31,"value":557},{"type":31,"value":1029}," Personalization is cache-key bound. User-specific data like cart item count can't be cached; we fetch it client-side instead.",{"type":26,"tag":34,"props":1031,"children":1033},{"id":1032},"above-the-fold-image-optimization",[1034],{"type":31,"value":1035},"Above-the-fold image optimization",{"type":26,"tag":27,"props":1037,"children":1038},{},[1039,1041,1047],{"type":31,"value":1040},"We converted the hero image from 1.2MB JPEG to 180kB WebP and added responsive breakpoints via ",{"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=\"New season collection\"\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":20},[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":278},[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=\"New season collection\"\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,1215,1221],{"type":31,"value":1006},{"type":26,"tag":108,"props":1216,"children":1218},{"className":1217},[],[1219],{"type":31,"value":1220},"fetchpriority=\"high\"",{"type":31,"value":1222}," attribute signals the browser: \"load this image first.\" We use Cloudflare Image Resizing at edge to auto-convert formats; older browsers get JPEG fallback.",{"type":26,"tag":27,"props":1224,"children":1225},{},[1226,1230,1232,1238],{"type":26,"tag":54,"props":1227,"children":1228},{},[1229],{"type":31,"value":550},{"type":31,"value":1231}," LCP 2.3s → 2.1s, image load time 1200ms → 320ms. CLS (Cumulative Layout Shift) 0.12 → 0.02 because we reserved space using the ",{"type":26,"tag":108,"props":1233,"children":1235},{"className":1234},[],[1236],{"type":31,"value":1237},"aspect-ratio",{"type":31,"value":1239}," CSS property.",{"type":26,"tag":34,"props":1241,"children":1243},{"id":1242},"benchmark-results-real-user-impact",[1244],{"type":31,"value":1245},"Benchmark results + real user impact",{"type":26,"tag":27,"props":1247,"children":1248},{},[1249],{"type":31,"value":1250},"PageSpeed Insights mobile score 34 → 92, desktop 62 → 98. 28-day CrUX average:",{"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},"Metric",{"type":26,"tag":1264,"props":1270,"children":1271},{},[1272],{"type":31,"value":1273},"Before",{"type":26,"tag":1264,"props":1275,"children":1276},{},[1277],{"type":31,"value":1278},"After",{"type":26,"tag":1264,"props":1280,"children":1281},{},[1282],{"type":31,"value":1283},"Change",{"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},"Google Analytics funnel: checkout initiation rate 3.2% → 4.8% (+50% relative lift). Bounce rate 68% → 52%. Search Console: organic traffic up 34% over two months (other SEO changes held constant). These numbers align with Roibase's standard targets in ",{"type":26,"tag":1387,"props":1388,"children":1392},"a",{"href":1389,"rel":1390},"https:\u002F\u002Fwww.roibase.com.tr\u002Fru\u002Fheadless",[1391],"nofollow",[1393],{"type":31,"value":1394},"headless commerce",{"type":31,"value":1396},"—if performance doesn't translate to business metrics, the architecture change hasn't succeeded.",{"type":26,"tag":34,"props":1398,"children":1400},{"id":1399},"tradeoffs-and-decision-criteria",[1401],{"type":31,"value":1402},"Tradeoffs and decision criteria",{"type":26,"tag":27,"props":1404,"children":1405},{},[1406,1411,1413,1418,1420,1425,1427,1433],{"type":26,"tag":54,"props":1407,"children":1408},{},[1409],{"type":31,"value":1410},"Developer experience:",{"type":31,"value":1412}," Wrapping components in ",{"type":26,"tag":108,"props":1414,"children":1416},{"className":1415},[],[1417],{"type":31,"value":590},{"type":31,"value":1419}," expands the API surface; new team members must learn ",{"type":26,"tag":108,"props":1421,"children":1423},{"className":1422},[],[1424],{"type":31,"value":820},{"type":31,"value":1426}," vs. ",{"type":26,"tag":108,"props":1428,"children":1430},{"className":1429},[],[1431],{"type":31,"value":1432},"when-idle",{"type":31,"value":1434},". We handled this with Storybook documentation and ESLint rules.",{"type":26,"tag":27,"props":1436,"children":1437},{},[1438,1443],{"type":26,"tag":54,"props":1439,"children":1440},{},[1441],{"type":31,"value":1442},"Bundle size vs. runtime cost:",{"type":31,"value":1444}," Self-hosted fonts added 60kB to the initial bundle but eliminated DNS lookup + TLS handshake overhead. This tradeoff is a net win on mobile 3G, neutral on fiber.",{"type":26,"tag":27,"props":1446,"children":1447},{},[1448,1453,1454,1459],{"type":26,"tag":54,"props":1449,"children":1450},{},[1451],{"type":31,"value":1452},"Cache invalidation:",{"type":31,"value":814},{"type":26,"tag":108,"props":1455,"children":1457},{"className":1456},[],[1458],{"type":31,"value":1012},{"type":31,"value":1460}," strategy carries stale-data risk. Critical data like inventory is kept fresh via client-side polling every 30s (cheaper than WebSocket or edge functions).",{"type":26,"tag":27,"props":1462,"children":1463},{},[1464,1469,1470,1475],{"type":26,"tag":54,"props":1465,"children":1466},{},[1467],{"type":31,"value":1468},"Cloudflare vendor lock-in:",{"type":31,"value":814},{"type":26,"tag":108,"props":1471,"children":1473},{"className":1472},[],[1474],{"type":31,"value":855},{"type":31,"value":1476}," KV-based caching is Cloudflare-specific. Migrating platforms requires re-implementation. That said, Vercel and Netlify have similar primitives; migration effort is manageable.",{"type":26,"tag":34,"props":1478,"children":1480},{"id":1479},"next-steps",[1481],{"type":31,"value":1482},"Next steps",{"type":26,"tag":27,"props":1484,"children":1485},{},[1486],{"type":31,"value":1487},"2.1s LCP is solid, but CrUX P75 (75th percentile) still sits at 3.2s. Our roadmap:",{"type":26,"tag":1489,"props":1490,"children":1491},"ol",{},[1492,1502,1512,1522],{"type":26,"tag":50,"props":1493,"children":1494},{},[1495,1500],{"type":26,"tag":54,"props":1496,"children":1497},{},[1498],{"type":31,"value":1499},"Image CDN + automatic format negotiation:",{"type":31,"value":1501}," Imgix integration instead of Cloudflare Polish, AVIF support",{"type":26,"tag":50,"props":1503,"children":1504},{},[1505,1510],{"type":26,"tag":54,"props":1506,"children":1507},{},[1508],{"type":31,"value":1509},"Prefetch strategy:",{"type":31,"value":1511}," Intersection Observer to prefetch data for product cards as they approach viewport",{"type":26,"tag":50,"props":1513,"children":1514},{},[1515,1520],{"type":26,"tag":54,"props":1516,"children":1517},{},[1518],{"type":31,"value":1519},"Service Worker + offline-first:",{"type":31,"value":1521}," Workbox to cache critical assets, network-first fallback",{"type":26,"tag":50,"props":1523,"children":1524},{},[1525,1530],{"type":26,"tag":54,"props":1526,"children":1527},{},[1528],{"type":31,"value":1529},"Aggressive bundle splitting:",{"type":31,"value":1531}," Route-based chunking with Nuxt 3's code splitting",{"type":26,"tag":27,"props":1533,"children":1534},{},[1535],{"type":31,"value":1536},"Performance optimization never ends—every 100ms saved lifts conversion by 1–2%. Nuxt 3 + Cloudflare Pages offers a balance between edge rendering and modern JS framework ergonomics. When making stack decisions, define LCP targets as business requirements first, then evaluate architectural options within that constraint.",{"type":26,"tag":374,"props":1538,"children":1539},{},[1540],{"type":31,"value":1541},"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":1543},[1544,1545,1546,1548,1549,1550,1551,1552],{"id":36,"depth":164,"text":39},{"id":98,"depth":164,"text":101},{"id":562,"depth":164,"text":1547},"Selective hydration + 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":1479,"depth":164,"text":1482},"markdown","content:ru:tech:nuxt-3-cloudflare-pages-lcp-optimization.md","content","ru\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-optimization.md","ru\u002Ftech\u002Fnuxt-3-cloudflare-pages-lcp-optimization","md",1778164176614]