Skip to content

Cloudflare: Routing & components

Astrophaze-cloudflare
Routes scanned fromsrc/pages/**src/pages/** (pages + content endpoints + co-located layouts) + src/api/** (HTTP handlers)
Page extension.astro / .tsx / .md / .mdx.tsx / .jsx / .phaze
Routable basenamesevery file routes; _* prefix opts outstrict allowlist — only index / page / layout (.tsx/.jsx/.phaze) OR <name>.<content-ext>.ts for content endpoints; everything else is a co-located helper, never publicly addressable
HTTP handler dirmixed with pages (src/pages/api/)separate top-level dir (src/api/**, URL auto-prefixed with /api/)
Dynamic segments[id], [...rest] as basename OR folder[id]/page.tsx, [...rest]/page.tsxfolder-only (dynamic basename shorthand removed under strict allowlist)
Co-located layoutsn/apages/<dir>/layout.{tsx,jsx,phaze} auto-pairs with sibling page (same-folder only)
Specificity sortyesyes
Page + API collisionn/a (.astro vs .ts differ)impossible by directory separation (src/pages/ vs src/api/); within-dir duplicates throw at discovery

Advantage: the strict allowlist closes the “every file is a route” risk (internal-debug.ts, OldThing.tsx, notes.tsx are never accidentally publishable). Helpers co-locate freely under src/pages/ without becoming URLs. The page/API split by directory makes the mental model explicit (“pages/ for what users see; api/ for what services call”).

Astrophaze-cloudflare
Top-level page.astro template with fenced frontmatterTSX function component, default export
Reactive islands<Component client:load/> / client:idle / client:visible / client:only="phaze"Whole page is one reactive tree; no island gating
Shared layoutLayout .astro files + <slot/> + named <slot name="X"/>Component imported + children + <Fragment slot="X">…</Fragment> extracted by phaze-compile
Slot lazy contracteagerly serialised into the parent’s HTMLphaze-compile wraps named-slot children in () => … arrows — layout decides when to evaluate; lets layouts ship without computed
Multi-child JSX wrapn/aemits arrayExpression instead of JSXFragment when wrapping reactive multi-child — keeps the Fragment symbol out of phaze
<For> runtimen/a (lists use .map() in islands)default <For for:item={items}> compile-strips to {() => items().map(...)} — zero shipped For bytes. phaze flag opts into the runtime For (~900 B) when row identity has to survive reorders. See <For> reference.

Advantage: the island / page split disappears. Astro emits a small per-island hydration shim (~96 B + ~66 B brotli per client:only directive); phaze-cloudflare’s whole page hydrates from one entry. The trade-off is no static-only zones inside a page — the entire page is reactive. For form-heavy and CRUD-style apps this is the correct trade.