A 3. modul azt mutatta meg, hogy fut a Nuxt a Workersön. Ez a modul a napi valóság: mi történik build közben a motorháztető alatt, milyen presetek és modulok vannak, hogyan áll fel a projekt, milyen a dev-környezet, hova tedd a Cloudflare-specifikus kódot, és hol vannak a buktatók.
nuxt build-kor?A Nuxt szerveroldali motorja a Nitro, és a lényeg egyetlen szóban: preset. A Nitro egy platformfüggetlen szerver-réteget épít a kódodból, majd a preset megmondja, milyen „csomagolásban" adja ki — Node-szerverként, Lambda-handlerként, vagy éppen Worker-modulként. A te kódod (az server/api/*, a middleware-ek, az SSR) nem tud arról, hol fog futni; a fordítás lépése dönt.
Amit a preset konkrétan elintéz helyetted:
h3 app-ját becsomagolja a Workers export default { fetch } formába — beleértve a scheduled és queue handlereket is, ha vannak (7. modul).request, az env (bindingok!) és a ctx (ExecutionContext) bekerül a H3 event kontextusába — innen éred el őket a kódodban.nodejs_compat mellé).| Preset | Mire való | Használd? |
|---|---|---|
cloudflare_module | Worker modul-szintaxissal + Static Assets — a mai alapértelmezett út | igen, ez az alapeset |
cloudflare_durable | ugyanaz, de Durable Object-alapú kiegészítéssel (pl. WebSocket-kezelés, Nitro task-ok, amikhez állapot kell) | ha WebSocketet vagy DO-t használsz a Nitro-rétegből |
cloudflare-pages | a régi Pages-célpont (_worker.js + Pages Functions) | csak meglévő Pages-projekthez (3. modul: az irány a Workers) |
cloudflare (sima) | régi service-worker szintaxis | ne — elavult |
wrangler deploy-t, felajánlja a szükséges beállítást, telepíti az adaptert és legenerálja a wrangler.jsonc-t (a Workers Builds pedig PR-t nyit ugyanezzel). Kezdésnek kényelmes; éles projektnél viszont érdemes explicit kiírni a presetet és a konfigot, hogy verziózott és kiszámítható legyen (12. modul).npm create cloudflare@latest -- my-app --framework=nuxt
# → Nuxt projekt, Cloudflare-re konfigurálva: preset, wrangler.jsonc, dev-modul, scriptek
1) nuxt.config.ts — a preset és a dev-modul:
export default defineNuxtConfig({
nitro: {
preset: "cloudflare_module",
cloudflare: {
deployConfig: true, // a Nitro szinkronban tartja a wrangler-konfigot
nodeCompat: true // nodejs_compat bekapcsolása
}
},
modules: ["nitro-cloudflare-dev"] // bindingok a `nuxt dev` alatt (13.4)
});
2) wrangler.jsonc — a 12. modul szerint; a Nuxt-specifikus rész a két útvonal:
{
"name": "my-app",
"main": "./.output/server/index.mjs", // a Nitro által generált Worker
"compatibility_date": "2026-08-04",
"compatibility_flags": ["nodejs_compat"],
"assets": { "directory": "./.output/public", "binding": "ASSETS" },
"observability": { "enabled": true },
"upload_source_maps": true
// + bindingok és env-ek (12. modul)
}
3) package.json — a scriptek, amik a csapat napi felületét adják:
{
"scripts": {
"dev": "wrangler types && nuxt dev",
"build": "nuxt build",
"preview": "nuxt build && wrangler dev", // éles-szerű futtatás lokálisan
"deploy:staging": "nuxt build && wrangler deploy --env staging",
"deploy:prod": "nuxt build && wrangler deploy --env production",
"cf-typegen": "wrangler types"
}
}
4) .gitignore — a szokásos .nuxt, .output mellé: .dev.vars*, .wrangler/.
Ez az a pont, ahol a Nuxt+Cloudflare ökoszisztéma épp átalakulóban van, ezért érdemes tudni, mi a különbség:
A) nuxt dev + nitro-cloudflare-dev | B) Cloudflare Vite plugin | |
|---|---|---|
| Hol fut a szerverkód | Node-ban, a bindingok emulálva (getPlatformProxy a Miniflare fölött) | valódi workerd-ben |
| Bindingok | a wrangler-konfigból automatikusan, valódi lokális Miniflare-erőforrásokkal | ugyanúgy, natívan |
| Hűség az éleshez | jó, de a runtime Node — ami ott működik, a Workersön nem feltétlen | a legmagasabb: ami megy, az élesben is megy |
| Érettség Nuxttal | bevált, dokumentált, stabil | újabb; Nitro/Nuxt-oldalon fokozatosan válik alapértelmezetté |
| DX | a megszokott Nuxt HMR | Vite HMR, de a szerver-oldal is izolátumban |
Ajánlás: ma az (A) a biztos alapfelállás a napi fejlesztéshez, és mellé egy „élesség-ellenőrző" lépés: npm run preview (nuxt build && wrangler dev), ami a buildelt Workert futtatja a valódi workerd-ben. Így a gyors hurok megmarad, de commit előtt látod, hogy a runtime-különbségek nem harapnak. Ha a projekted már a Vite-plugin útra állt (vagy új projektet kezdesz), (B) a jövőálló irány.
# .dev.vars — NEM megy a repóba
STRIPE_SECRET_KEY="sk_test_…"
NUXT_SESSION_PASSWORD="legalabb-32-karakter-hosszu-titok"
A .dev.vars értékei ugyanúgy az env-en jelennek meg, mint élesben a wrangler secret-tel feltöltöttek. A NUXT_-prefixű változókat a Nitro ezen felül beleköti a runtimeConfig-ba — erről lentebb.
A 11. modulból ismerős: bindingonként "remote": true, és az adott erőforrás az éles (staging!) példány lesz, miközben a Nuxt lokálisan fut. Tipikus eset: lokális D1, de valódi R2 vagy AI-binding.
A nyers hozzáférés így néz ki bármelyik server route-ban:
server/api/hello.get.tsexport default defineEventHandler(async (event) => {
const { env, cf, context } = event.context.cloudflare;
// env.DB, env.UPLOADS, env.JOBS… — a 12. modulban deklarált bindingok
// cf: ország, colo, TLS-adatok… context: waitUntil (2. modul)
});
Futtasd a wrangler types-t, majd egyszer deklaráld a H3-kontextust — innentől az env.DB típusos mindenhol:
declare module "h3" {
interface H3EventContext {
cf: CfProperties;
cloudflare: {
request: Request;
env: Env; // a `wrangler types` által generált típus
context: ExecutionContext;
};
}
}
export {};
event.context.cloudflare.env-tőlNe szórd tele az egész kódbázist a Cloudflare-specifikus eléréssel — vezess be egy vékony hozzáférési réteget a server/utils/-ban (a Nitro ezt auto-importálja):
import type { H3Event } from "h3";
export const cf = (event: H3Event) => event.context.cloudflare;
export const useDb = (event: H3Event) => cf(event).env.DB;
export const useBucket = (event: H3Event) => cf(event).env.UPLOADS;
// háttérmunka: a válasz után is befejeződik (2. modul)
export const background = (event: H3Event, p: Promise<unknown>) =>
cf(event).context.waitUntil(p);
// tenant-feloldás egy helyen (5b. modul mintája)
export async function useTenant(event: H3Event) {
const host = getRequestHost(event);
const slug = host.split(".")[0];
const cached = await cf(event).env.CONFIG.get(`tenant:${slug}`, { type: "json" });
if (cached) return cached;
// … registry-lookup + KV-cache (6. modul)
}
server/api/invoices.get.ts — így lesz olvasható a hívó oldal
export default defineEventHandler(async (event) => {
const tenant = await useTenant(event);
const { results } = await useDb(event)
.prepare("SELECT * FROM invoices WHERE tenant_id = ? ORDER BY created_at DESC")
.bind(tenant.id).all();
background(event, logAccess(event, tenant.id));
return results;
});
runtimeConfig vs. bindings vs. secrets — mikor melyik?| Eszköz | Mire | Honnan jön |
|---|---|---|
bindings (env.DB) | Cloudflare-erőforrások | wrangler-konfig (12. modul) |
vars | nem titkos beállítás | wrangler-konfig, a repóban |
| secrets | API-kulcs, jelszó | wrangler secret put / .dev.vars |
runtimeConfig | a Nuxt saját konfig-rétege (szerver + public a kliensnek) | a NUXT_-prefixű env-értékek felülírják futásidőben |
Gyakorlat: a Cloudflare-erőforrásokhoz mindig bindingot használj. A runtimeConfig-ot arra tartsd, amire a Nuxt-világ szánta: kliens felé publikálható beállítások (public), illetve olyan szerveroldali értékek, amiket Nuxt-modulok várnak (pl. session-jelszó). Így nem lesz két párhuzamos konfig-rendszered ugyanarra.
routeRulesexport default defineNuxtConfig({
routeRules: {
"/": { swr: 600 },
"/blog/**": { isr: 3600 },
"/app/**": { ssr: true, cache: false }, // bejelentkezett rész
"/docs/**": { prerender: true }, // build-időben generált
"/api/**": { cors: true }
}
});
A cache-elt válaszok tárolására a Nitro a platform cache-ét használja. Fontos árnyalat: az isr/swr a PoP-onkénti cache-re támaszkodik, tehát nem globálisan egy példány frissül — ha szigorúan egységes időzítés kell, azt jobb explicit KV-be tett generált tartalommal megoldani.
useStorage() — a Nitro tárolási absztrakciójaHa a Nitro useStorage()-ét használod (cache, sessionok, kulcs-érték adat), Cloudflare-en driverrel köthető KV-hez vagy R2-hez:
nitro: {
storage: {
cache: { driver: "cloudflare-kv-binding", binding: "CONFIG" },
uploads: { driver: "cloudflare-r2-binding", binding: "UPLOADS" }
}
}
fs-drivere Workersön nem működik (nincs perzisztens fájlrendszer — 2. modul). Ha bárhol useStorage()-et használsz explicit driver nélkül, az memóriában landol, és isolate-enként elveszik. Éles használat előtt mindig kösd be a drivert.A Nitro WebSocket-támogatásához és a tartós kapcsolatokhoz Cloudflare-en Durable Object kell — erre való a cloudflare_durable preset. Ha komolyabb realtime funkciód lesz (jelenlét, kollaboráció), érdemes inkább saját DO-t írni a 7. modul mintái szerint, és a Nuxt-ot csak kliens-oldali kapcsolódásra használni: átláthatóbb és jobban skálázható.
A Nitro `scheduled`/`queue` handlerei a generált Workerbe kerülnek. A gyakorlatban két járható út van: vagy a Nitro task-jait használod és a wrangler-konfigban felveszed a triggers.crons-t, vagy — nagyobb rendszernél tisztább — a háttérmunkát külön Workerbe teszed, és service bindinggel kötöd össze (11. modul). Utóbbi mellett szól, hogy a háttér-Workert külön deployolhatod, külön limitekkel és külön skálázással.
A NuxtHub egy Nuxt-réteg a Cloudflare-primitívek fölött: `hubDatabase()` (D1), `hubKV()`, `hubBlob()` (R2), `hubAI()` — plusz admin-felület és egyszerűsített deploy. A mérleg:
| Mellette | Ellene |
|---|---|
| gyors indulás, kevesebb boilerplate, kényelmes API-k | egy absztrakciós réteggel több a stackben |
| Nuxt-idiomatikus (auto-import, composable-jelleg) | a natív bindingok tudásának egy része elfedve |
| szép admin/DB-böngésző dev alatt | ha kinövöd, vissza kell fejteni a natívra |
Az ajánlásom a te helyzetedben: maradj a natív bindingoknál. Egy meglévő, éles multitenant SaaS-nál a saját hozzáférési rétegedet (13.5) úgyis megírod, az pontosan illik a te modelledhez, és nem függ egy köztes csomag életciklusától. A NuxtHub új, kisebb projektnél vagy prototípusnál viszont teljesen jó választás.
Két elv, ami sokat számít éles rendszerben: ① a server/api maradjon vékony — validálás + hívás a server/utils-beli üzleti függvényre; így a logikád tesztelhető marad a HTTP-rétegtől függetlenül (11. modul). ② a tenant-feloldás middleware-ben történjen, egyszer, és az eredmény kerüljön az event kontextusába — ne minden endpoint oldja meg újra.
# kézzel
npm run build
npx wrangler deploy --env production
# előtte érdemes: éles-szerű lokális ellenőrzés
npm run preview # nuxt build && wrangler dev
Workers Builds beállítás Nuxthoz (8. modul):
| Mező | Érték |
|---|---|
| Build command | npm run build |
| Deploy command (production branch) | npx wrangler deploy --env production |
| Non-production branch deploy command | npx wrangler versions upload --env staging |
| Root directory | monorepóban az app almappája |
A séma-migrációk itt is a 8. modul szabálya szerint mennek: a deploy előtt, külön lépésben, stagingen automatikusan, éles környezetben kapuval.
| Tünet / helyzet | Ok | Megoldás |
|---|---|---|
Build hibázik natív modulra (sharp, canvas) | natív bináris nem fut isolate-ben (2. modul) | képfeldolgozás: Cloudflare Images vagy R2+resize-szolgáltatás; végső esetben Containers (10. modul) |
@nuxt/image nem működik alapból | a Node-alapú provider natív modult használ | váltás cloudflare provider vagy Images-integráció |
| „Worker exceeded size limit" | a bundle túllépi a 10 MB-ot | függőség-audit, nuxt build --analyze, nehéz libek lazy importja vagy külön Workerbe emelése |
| Session/cookie furcsán viselkedik | a session-tár memóriában van (isolate-enként!) | useStorage driver KV-re, vagy signed-cookie alapú session (nuxt-auth-utils jellegű megoldás) |
process.env.X undefined | Workersön nincs klasszikus process-környezet | bindingok / runtimeConfig; a NUXT_-prefix köti be az env-értékeket |
| Globális változóban cache-elt adat „eltűnik" | isolate-életciklus (2. modul) | KV vagy DO; globális állapotra soha ne építs |
| DB-kliens a modul tetején jön létre | a kapcsolat isolate-hez ragad | kliens a handleren belül (4. modul, Hyperdrive) |
| Lokálisan megy, élesben CPU-hiba (1102) | a limitek lokálisan nem érvényesülnek | npm run preview + staging; nehéz munka Queues/Workflows-ba (7. modul) |
| Nagy fájl feltöltése 413-mal hasal el | kérés-body limit | presigned URL, közvetlen R2-feltöltés (6. modul) |
| Prerenderelt oldalak hiányoznak | a prerender kimenete a public mappába kerül, de az asset-config nem stimmel | assets.directory ellenőrzése; not_found_handling beállítása (3. modul) |
A preset a platform-specifikus csomagolást végzi: egyetlen Worker-modullá bundle-ol, előállítja a export default { fetch, … } alakot, átvezeti a Cloudflare-kontextust (request/env/ctx) a H3 eventbe, és a statikus fájlokat a Static Assetsre bízza. A te forrásod platformfüggetlen marad — a preset cseréjével ugyanaz a kód Node-ra is fordítható.
nuxt dev + nitro-cloudflare-dev és a Cloudflare Vite plugin között?
Az előbbinél a szerverkód Node-ban fut, a bindingok emuláltak (getPlatformProxy/Miniflare) — gyors és bevált, de a runtime nem azonos az élessel. A Vite pluginnél a szerverkód valódi workerd-ben fut, tehát a hűség maximális. Átmeneti megoldásként a napi hurokban (A), commit előtt pedig nuxt build && wrangler dev ellenőrzés.
server/utils-ba zárni?
Hogy a Cloudflare-specifikus elérés (event.context.cloudflare.env) egy helyen legyen: olvashatóbb hívó kód, könnyebb tesztelés, és ha változik a modell (pl. per-tenant DB-feloldás jön), egyetlen fájlt kell módosítani.
runtimeConfig-ot és mikor bindingot?
Cloudflare-erőforráshoz (D1, R2, KV, Queue…) mindig binding. A runtimeConfig a Nuxt saját konfig-rétege: kliens felé publikálható értékek (public) és Nuxt-modulok által várt szerveroldali beállítások; ezeket a NUXT_-prefixű env-értékek írják felül futásidőben.
useStorage()-ot használod cache-re, és a dev-en tökéletes, élesben viszont „elfelejti" az adatot. Mi történt?
Nincs bekötve driver, így memóriában tárol — a Workersön viszont isolate-enként külön memória van, és az bármikor eldobható. Kösd be a cloudflare-kv-binding (vagy R2) drivert a nitro.storage-ban.
Build command: npm run build; Deploy command: npx wrangler deploy --env production; Non-production branch deploy command: npx wrangler versions upload --env staging (hogy a PR-preview a staging erőforrásokon fusson); Root directory: monorepóban az app almappája.