Architecture overview¶
The Website is a server-side rendered React application that runs entirely on Cloudflare Workers. There is no traditional Node server: the same Worker serves static assets, applies redirects and security headers, edge-caches blog pages, and renders pages with Vike.
High-level architecture¶
DNS · WAF · TLS · cache] Edge -->|Workers Routes| Worker[swapps-client Worker] Worker --> Assets[Static Assets
ASSETS binding] Worker -->|Service Binding| Platform[Platform · swapps-worker] Worker -->|fetch| App[App · app.swapps.com] Worker -->|fetch /api/ai/*| AI[AI · swapps-ai] Platform -->|WP REST API| WP[WordPress / Pantheon]
Core components¶
1. Cloudflare Workers runtime¶
The entry point is src/worker.ts, bundled to dist/worker.js by esbuild. The
fetch handler is the application server: for each request it runs, in order,
the blog cache-purge webhook, WordPress permalink/legacy redirects, trailing-slash
and canonical redirects, the Sentry tunnel, robots.txt / sitemap handlers,
static-asset serving, edge-cache lookup for blog posts, and finally Vike SSR.
See Cloudflare Workers for the full request lifecycle.
2. Server-side rendering (Vike)¶
Rendering is driven by Vike with vike-react. Routing is
file-based under pages/; +onRenderHtml.tsx produces the SSR HTML (including
SEO meta, hreflang, JSON-LD, GTM/gtag, and inlined critical CSS) and
+onRenderClient.tsx hydrates React on the client. SSR is enabled for all pages
(ssr: true) and client routing is disabled in favor of plain HTML navigation.
See SSR with Vike.
3. Service Bindings¶
The Website reaches the Platform Worker via a Service Binding (API_WORKER)
declared in wrangler.toml. This is a direct Worker-to-Worker call — no public
HTTP, no egress. The shared fetchData() helper (src/utils/api.ts) uses the
binding when present and falls back to plain HTTP against API_URL otherwise (for
local dev).
See Service bindings.
4. Static assets¶
Static assets ship in dist/client and are served through the Workers
Static Assets ASSETS binding. The Worker overrides cache headers per asset
type: content-hashed files get max-age=31536000, immutable, fonts 1 year,
images 30 days, and un-hashed JS/CSS 24 hours (see getCacheControlForAsset in
src/worker.ts).
Request → render flow¶
- Edge routing — Cloudflare routes
swapps.com/*to theswapps-clientWorker. - Pre-processing — the Worker resolves redirects, the Sentry tunnel,
robots.txt/ sitemaps, and static assets before any rendering. - Edge cache — for anonymous blog-post URLs, a cached HTML copy is served if present.
- Data fetching —
+data.tsfiles call the Platform Worker (blog, leads) via the Service Binding. - SSR — Vike renders React to HTML; the Worker injects security headers.
- Hydration — React hydrates on the client for interactivity.
Internationalization¶
The site is bilingual (English default, Spanish under /es/). The global
pages/+onBeforeRoute.ts hook rewrites Spanish URLs to their canonical English
route (using src/locales/routes.json) so a single set of page files serves both
locales, and injects locale / basePath into the page context. See
SSR with Vike.
Technology stack¶
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Cloudflare Workers | Serverless edge compute |
| Meta-framework | Vike (vike-react) |
File-based routing + SSR |
| UI | React 19 | Concurrent rendering and hydration |
| Language | TypeScript | Type safety |
| Styling | SCSS + BEM | Modular styles (CSS code splitting) |
| Client build | Vite 7 | Bundling and asset hashing |
| Worker build | esbuild | Worker bundle (dist/worker.js) |
| Assets | Workers Static Assets | Optimized static file serving |
| Errors | Sentry | Error tracking via Worker tunnel |
Deployment environments¶
| Environment | URL |
|---|---|
| Production | https://swapps.com |
| Preview | https://{alias}-swapps-client.swapps.workers.dev (per branch) |
| Local | http://localhost:3000 |
See Deployment.