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

graph TD User[Browser] -->|HTTPS| Edge[Cloudflare edge
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

  1. Edge routing — Cloudflare routes swapps.com/* to the swapps-client Worker.
  2. Pre-processing — the Worker resolves redirects, the Sentry tunnel, robots.txt / sitemaps, and static assets before any rendering.
  3. Edge cache — for anonymous blog-post URLs, a cached HTML copy is served if present.
  4. Data fetching+data.ts files call the Platform Worker (blog, leads) via the Service Binding.
  5. SSR — Vike renders React to HTML; the Worker injects security headers.
  6. 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.

Next steps