From e55edb3757ffb1c943c31377aa3c8f6b010cc657 Mon Sep 17 00:00:00 2001 From: Nayan Date: Tue, 11 Aug 2026 04:29:09 +0530 Subject: [PATCH] perf(web): prerender the site instead of rendering it per request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/web had no request-dependent output — one route, all copy imported from src/content/*.json at build time, and not a server function or loader in the app — so every request paid for an SSR invocation that produced byte-identical HTML. tanstackStart({ prerender: { enabled: true } }) runs that same server bundle once at build time and writes dist/client/index.html, which is already the worker's assets directory. Cloudflare now serves the page from the asset layer: verified under wrangler dev, GET / returns CF-Cache-Status: HIT, so the worker never runs. It is still built and deployed, and still answers what the assets miss — GET /nope returns a worker-rendered 404 exactly as before. Also ignore .wrangler/, the local state dir `make web:preview` writes. --- .gitignore | 4 ++++ CONTRIBUTING.md | 12 ++++++++++++ apps/web/vite.config.ts | 15 ++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8fb9eb8..b3da1b6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,10 @@ dist/ .nitro/ .tanstack/ +# Wrangler's local state and scratch dirs, written by `make web:preview` +# (wrangler dev). Machine-local simulation of the Cloudflare runtime. +.wrangler/ + # Turbo .turbo/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1e0337..49a7e16 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -300,6 +300,18 @@ until the merge. Build logs live in the dashboard, not in the Actions tab. This is why `apps/web/wrangler.jsonc` declares no `env` block — one worker, and the branch decides the command. `make web:deploy` remains as a manual override that authenticates as you. +**What gets deployed is prerendered, not server-rendered.** `vite.config.ts` passes +`prerender: { enabled: true }` to `tanstackStart()`, so the build runs the server bundle once and +writes `dist/client/index.html` — which is the worker's assets directory, so Cloudflare serves +the page as a static file and the worker is never invoked for a normal view. It is still built +and still deployed: it answers whatever the assets do not match, which is what renders the 404. + +That has a consequence worth knowing before you reach for one. **A server function or route +loader added to this app will run at build time, not per request** — its result gets baked into +the HTML. That is correct for this site, which has one route and imports all of its copy from +`src/content/*.json`, but the day the page genuinely needs request-dependent output, turning +prerendering off is the change to make, not working around it. + ## Releases `@airshiplabs/cli` is the only package published to npm. Everything else in the workspace is diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 837b188..764b90b 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -11,7 +11,20 @@ import { defineConfig } from "vite"; // // Port 5173; airship's overlay always takes TARGET + 1, so `make run` serves the // editor on 5174. See the root Makefile. +// +// Prerendered, because nothing on this page depends on the request. There is one +// route, its copy is imported from content/*.json at build time, and there is not +// a server function or loader in the app — so SSR was rendering the same bytes on +// every hit. `prerender` runs that same server bundle once at build time and +// writes dist/client/index.html, which is already the worker's assets directory: +// Cloudflare serves it as a static file and the worker never wakes up for a normal +// page view. The worker is still built and still deployed — it is what answers +// paths the assets do not match, which is how the 404 keeps rendering. export default defineConfig({ - plugins: [tailwindcss(), tanstackStart(), react()], + plugins: [ + tailwindcss(), + tanstackStart({ prerender: { enabled: true } }), + react(), + ], server: { port: 5173 }, });