routeRulesA Nuxt egyik legerősebb képessége, hogy útvonalanként más renderelési stratégiát adhatsz — és itt van a tananyag legőszintébb szakasza is: az isr és az swr nem azt csinálja Workers-en, amit a dokumentációt olvasva várnál. Megnézzük, mi történik valójában, és mit állíts be, hogy tényleg működjön.
| Mód | Mikor dől el a HTML | Fut a Worker? | Mire jó |
|---|---|---|---|
| Universal (SSR) az alapértelmezés |
Kérésenként, a szerveren | Igen, minden kérésnél | Bejelentkezett app, friss adat, publikus tartalom SEO-val |
SPAssr: false |
A böngészőben, JS-futás után | Csak a váz kiszolgálásához | Admin, belső eszköz — ahol nincs SEO-igény |
Prerenderprerender: true |
Build-időben, egyszer | Nem — statikus fájl | Marketing, dokumentáció, blog: a legjobb ár/érték |
HibridrouteRules |
Útvonalanként más | Útvonaltól függ | A valóság: egy appban mind a három egyszerre |
.output/public/-ba kerül, tehát static assetként szolgálódik ki. Ez azt jelenti: nem fut Worker, nem fogy CPU-idő, és a Cloudflare hivatalos árazása szerint az assetekre érkező kérés ingyenes. Egy prerenderelt marketing-oldal gyakorlatilag nulla futásidejű költséggel megy — miközben a világ minden pontján az edge-ről érkezik.routeRules — a teljes eszköztárA nuxt.config.ts-ben glob-mintákkal rendelsz szabályt útvonalcsoportokhoz:
| Szabály | Mit csinál |
|---|---|
prerender: true | Build-időben legenerálja, statikus fájlként szolgálja ki |
ssr: false | Az útvonal kliensoldali marad (SPA-sziget) |
swr: 300 | Nitro-cache 300 mp-re, elavulás után háttérben frissít — lásd a 7.3-at |
isr: 300 | CDN-szintű változat ugyanerre — platformfüggő |
cache: {…} | A részletes forma: maxAge, staleMaxAge, swr, varies |
headers: {…} | Fejlécek hozzáadása (cache-control, biztonsági fejlécek) |
redirect: {…} | Szerveroldali átirányítás, státuszkóddal |
cors: true | CORS-fejlécek — a cors npm-csomag helyett |
noScripts: true | Nem tölti be a Nuxt JS-t: tiszta statikus HTML |
appMiddleware | Route middleware ki-/bekapcsolása útvonalcsoportra |
// nuxt.config.ts — egy tipikus SaaS felosztása
export default defineNuxtConfig({
routeRules: {
// ① marketing: build-időben statikus — a Worker meg sem hívódik
'/': { prerender: true },
'/arak': { prerender: true },
'/blog/**': { prerender: true },
// ② publikus, megosztott nézet: ritkán változik, de nem build-time adat
'/p/**': { swr: 300 },
// ③ az alkalmazás: mindig friss, és SENKI ne cache-elje
'/app/**': { ssr: true, headers: { 'cache-control': 'private, no-store' } },
// ④ admin: nincs SEO-igény → nincs SSR-költség sem
'/admin/**': { ssr: false },
// ⑤ API
'/api/**': { cors: true, headers: { 'cache-control': 'no-store' } },
// ⑥ régi URL-ek életben tartása
'/pricing': { redirect: { to: '/arak', statusCode: 301 } },
},
})
private, no-store-t, akkor egy köztes cache — böngésző, vállalati proxy, vagy a te saját szabályod — eltárolhatja, és a következő látogatónak kiszolgálhatja. Ez az a hibaosztály, ami nem a te kódodban van, mégis a te felelősséged.isr és az swr — mit ígér a doksi, és mi történik Workers-enA Nuxt dokumentációja az ISR/SWR route rule-oknál kifejezetten Vercelt és Netlifyt említi: ott ezek a szabályok platform-natív képességre fordulnak le — a szolgáltató saját CDN-je végzi a tárolást és a háttérben történő frissítést.
Cloudflare-en nincs ilyen natív leképezés. Ott ezek a szabályok a Nitro saját cache-rétegére fordulnak, ami az unstorage storage-rendszerét használja. És itt van a lényeg:
memory driver. Workers-en ez az izolátum memóriája. Vagyis: a cache nem osztott a datacenterek között, nem osztott az izolátumok között, és eltűnik, amint az izolátumot kiürítik. Ha a szabály be van kapcsolva, technikailag működik — de a találati arány töredéke annak, amit vársz, és nincs semmilyen garancia a tartósságra. Ez nem hiba, hanem konfigurációs alapértelmezés, amit neked kell felülírnod.// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'cloudflare_module',
storage: {
// a „cache" mountpontot használja a Nitro cache-rétege (swr/isr/cachedEventHandler)
cache: {
driver: 'cloudflare-kv-binding',
binding: 'CACHE', // a wrangler.jsonc-ben deklarált binding neve
},
},
// fejlesztés közben maradjon fájlrendszer — gyorsabb és láthatóbb
devStorage: {
cache: { driver: 'fs', base: '.nitro/cache' },
},
},
})
// wrangler.jsonc
{
"kv_namespaces": [
{ "binding": "CACHE", "id": "…" }
]
}
Ezzel a cache tartós és globálisan elérhető lesz. Cserébe a KV tulajdonságait örökölöd, és ezeket ismerni kell:
| KV-tulajdonság | Mit jelent a cache-edre |
|---|---|
| Végső konzisztencia (jellemzően ~60 mp) | Az írás nem azonnal látszik mindenhol. Cache-nek ez rendben van — „azonnali invalidálás”-nak nem. |
| Kulcsonként korlátos írási ráta | Egy gyakran frissülő kulcsot ne ezen keresztül tarts karban. |
| Nagyon gyors, globális olvasás | Pont ezért jó cache-nek: sok olvasás, kevés írás. |
/p/riport) különböző tenantokhoz tartozik — vagyis ütközhetnek, és az egyik tenant cache-elt oldalát kapja a másik. Mielőtt bármilyen cache-szabályt élesítesz aldomain-modellben, ellenőrizd, hogy a hoszt része-e a kulcsnak (varies: ['host'], illetve saját getKey), és teszteld két tenanttal. Ha bizonytalan vagy: ne cache-elj. Egy lassabb oldal olcsóbb, mint egy adatszivárgás.Sok esetben jobb a routeRules helyett közvetlenül a drága API-végpontot cache-elni — mert ott te írod a kulcsot:
// server/api/public/report/[slug].get.ts
export default defineCachedEventHandler(async (event) => {
const tenant = event.context.tenant
const slug = getRouterParam(event, 'slug')!
return await buildPublicReport(event, tenant.id, slug)
}, {
maxAge: 300, // 5 percig friss
staleMaxAge: 3600, // utána még egy óráig kiszolgálható, közben frissül
swr: true,
// ← EZ a lényeg: a kulcsot te írod, és benne van a tenant
getKey: (event) =>
`report:${event.context.tenant.id}:${getRouterParam(event, 'slug')}`,
})
Ugyanez függvényszinten is megy (defineCachedFunction), ha nem egy egész végpontot, hanem egy drága részszámítást akarsz cache-elni.
export default defineNuxtConfig({
nitro: {
prerender: {
crawlLinks: true, // követi a talált <NuxtLink>-eket
routes: ['/', '/arak', '/sitemap.xml'],
failOnError: true, // a build bukjon el, ne csendben hiányozzon egy oldal
},
},
})
Amit érdemes tudni:
crawlLinks kényelmes, de kiszámíthatatlan. Ha egy link elgépelés miatt eltűnik, az oldal csendben kimarad. Kritikus oldalakat sorolj fel explicit módon is.swr-t választani.ssr: false szigetekAz ssr: false egy útvonalcsoportra azt jelenti: a Worker egy üres vázat ad vissza, a tartalom a böngészőben áll össze. Nem visszalépés, hanem tudatos csere.
| Nyered | Veszíted |
|---|---|
|
Nincs SSR-CPU kérésenként (Workers-en ez pénz) A váz statikus és cache-elhető Nincs hydration mismatch, nincs payload-szivárgás Egyszerűbb kód: csak kliens fut |
Nincs SEO és nincs link-előnézet Lassabb első hasznos festés A felhasználó spinnert lát (mint a mai SPA-dban) |
A tipikus jó jelöltek: /admin/**, belső riportnézetek, összetett szerkesztőfelületek, bármi, ami bejelentkezés mögött van és nagy kliensoldali interaktivitást igényel. Ha az egész appod ilyen, akkor érdemes visszaolvasni az 1. modul „mikor ne Nuxt” szakaszát — nem baj, ha a válasz az, hogy mégis Nuxt, de tudatosan.
A 4.5 kísérleti SSR-streaminget hozott: a szerver nem várja meg a teljes HTML elkészültét, hanem darabokban küldi. Az elvi haszon a jobb TTFB — a böngésző hamarabb kap fejlécet és fejrészt, hamarabb kezdi tölteni a CSS-t.
Workers-en ez elvileg jó illeszkedés, mert a runtime natívan streamel (a Cloudflare best practices kifejezetten javasolja a stream alapú válaszokat a memóriahasználat miatt). Három dolgot viszont mérlegelj, mielőtt bekapcsolod:
| Útvonalcsoport | Ajánlott szabály | Miért |
|---|---|---|
| Nyitóoldal, árak, funkciók | prerender: true | Nem változik kérésenként, SEO kell, és így nulla futásidejű költség |
| Blog, dokumentáció | prerender: true | Ugyanaz; új tartalom = új deploy |
Publikus, megosztott nézet (/p/**) | swr + KV-cache + tenant a kulcsban | Adatbázisból jön, de ritkán változik és sokan nézik |
Bejelentkezett app (/app/**) | SSR + private, no-store | Friss adat, felhasználó-specifikus payload — nem cache-elhető |
| Admin, belső eszközök | ssr: false | Nincs SEO-igény, spórolsz a CPU-időn |
API (/api/**) | no-store; a drága végpontokon defineCachedEventHandler | A kulcsot te írod, a tenanttal együtt |
Auth-oldalak (/login, /register) | SSR, no-store | CSRF-token és állapot van bennük |
server/api, a h3 event-modellje, validáció, hibakezelés — és egy teljes Express → h3 megfeleltetési tábla, hogy a meglévő API-d mintáit egy az egyben át tudd fordítani.Mert a prerenderelt HTML a .output/public/-ba kerül, és static assetként szolgálódik ki: nem indul el a Worker, nem fogy CPU-idő, és az assetekre érkező kérés nem számít bele a futtatási költségbe. Az SSR-elt oldalnál minden kérés lefuttatja a kódodat.
swr: 300-at, de a találati arány gyanúsan alacsony. Mi a legvalószínűbb ok Workers-en?
Hogy a Nitro cache-e az alapértelmezett memory driveren fut, ami Workers-en az izolátum memóriáját jelenti: nem osztott a datacenterek és izolátumok között, és eltűnik, amint az izolátumot kiürítik. A megoldás a cache storage-mount KV-re állítása a nitro.storage-ban, plusz a KV-binding felvétele a wrangler-konfigba.
Mert a route-rule cache kulcsa alapvetően az útvonalból képződik, és aldomain-modellben ugyanaz az útvonal különböző tenantokhoz tartozik — vagyis az egyik tenant cache-elt oldalát kaphatja a másik. A hosztot bele kell venni a kulcsba (varies, saját getKey), és két tenanttal tesztelni kell. Bizonytalanság esetén inkább ne cache-elj.
defineCachedEventHandler, mint a routeRules-alapú cache?
Amikor a kulcsot te akarod meghatározni — például mert a tenantnak, a felhasználónak vagy egy szűrőnek benne kell lennie. A getKey-jel pontosan megmondod, mi az azonosító, és a maxAge/staleMaxAge/swr hármassal a viselkedést is te szabod meg. A route rule kényelmesebb, de kevesebb kontrollt ad.
private, no-store a bejelentkezett felület HTML-jére?
Mert a HTML tartalmazza a szerveroldali lekérések payloadját, ami felhasználó-specifikus. Ha egy köztes cache (böngésző, vállalati proxy, saját szabály) eltárolja, a következő látogatónak szolgálhatja ki. Ez nem a kódod hibája, mégis a te felelősséged — és a fejléc az egyetlen, ami megakadályozza.
ssr: false, és mit adsz fel érte?
Bejelentkezés mögötti, SEO-t nem igénylő felületekre: admin, belső riportok, összetett szerkesztők. Nyered: nincs SSR-CPU kérésenként, a váz cache-elhető, nincs hydration mismatch és payload-szivárgás. Feladod: az indexelhetőséget, a link-előnézetet és a gyors első hasznos festést.