Cloudflare: Client-side
Client-side router + view transitions
Section titled “Client-side router + view transitions”| Astro | phaze-cloudflare | |
|---|---|---|
| Opt-in | <ClientRouter /> component in layout | plugin option router: true |
| Click intercept | yes | yes |
| HTML fetch | yes | yes, with phaze-router: 1 header so the server can detect/optimise |
| View Transitions | document.startViewTransition | same — falls through to plain swap on browsers without support |
| Re-hydration | per-island | single re-hydrate via startClient() reuse |
| Bundle cost | ~925 B brotli page.*.js (always) + ClientRouter runtime | ~400-500 B brotli, opt-in — folds into entry only when router: true |
transition:persist / transition:name | yes | not yet — view-transition element-level persistence is a known gap |
Prefetch
Section titled “Prefetch”| Astro | phaze-cloudflare | |
|---|---|---|
| Strategies | tap / hover / viewport / load | viewport only |
| Opt-out per link | data-astro-prefetch="false" | data-no-prefetch |
| Dynamic DOM | MutationObserver | same |
fetch priority | low hint | low hint |
| Bundle cost | bundled into page.*.js always | ~300 B brotli, opt-in |
The hover/tap strategies are a known gap — useful for nav menus where viewport-trigger is too eager. Cheap to add when needed.
Head metadata
Section titled “Head metadata”Astro: head is part of the .astro template; per-route SEO via prop-driven layout component.
phaze-cloudflare: export const head: HeadFn = (ctx) => ({ title, description, raw }).
export const head: HeadFn<Env> = ({ params }) => ({ title: `User ${params.id} — Acme`, description: 'Profile page', raw: '<link rel="canonical" href="https://acme.com/users/42">',})Advantage: head() runs in parallel with loader() and the first chunk goes out as soon as head resolves — Astro waits for the page render to begin.