This site deploys to Cloudflare Pages with zero npm dependencies at build time.
Cloudflare Pages runs npm run pages:build which executes:
node --experimental-strip-types scripts/build.ts --mode=pagesThis works because:
- Node 22 is available on Cloudflare (with experimental TypeScript support)
- Vite assets are pre-committed in
dist/(built locally before push) - Articles are markdown files in
blog/articles/(committed to git) - No npm install needed (
SKIP_DEPENDENCY_INSTALL=truein Cloudflare settings)
| Mode | Command | What It Does |
|---|---|---|
dev |
bun run dev |
Generate content + Vite dev server |
prod |
bun run build |
Generate + Vite build + Finalize |
pages |
npm run pages:build |
Generate + Finalize (no Vite) |
-
Generate (
scripts/generate.ts)- Reads
blog/articles/*.md(markdown with YAML frontmatter) - Writes
public/content/manifest.json(article list) - Writes
.build/article/*/index.html(SSG article pages) - Writes
.build/context/*/index.html(SSG context pages)
- Reads
-
Vite Build (prod mode only)
- Bundles React app to
dist/ - Copies public assets
- Bundles React app to
-
Finalize (
scripts/finalize.ts)- Copies manifest + bookmarks to
dist/ - Processes SSG HTML (injects prod asset tags)
- Embeds manifest into
index.html(no fetch needed)
- Copies manifest + bookmarks to
Build command: npm run pages:build
Build output: dist
Root directory: /
Node version: 22
Environment variables:
SKIP_DEPENDENCY_INSTALL = true
CI = true
You're probably running prod mode on Cloudflare. Use pages mode instead.
The pages:build script should use --mode=pages.
Check that:
blog/articles/*.mdfiles are committed- Articles have
status: publishedin frontmatter (drafts are hidden whenCI=true) generate.tsran successfully (check build logs for article count)- The article slug matches (trailing slashes are stripped)
Check that:
context/*.mdfiles exist- Build logs show context count > 0
The dist/ directory with Vite-built assets needs to exist. Run bun run build locally before pushing.
Cloudflare caches aggressively. Check:
index.htmlhas 30s max-age (should update quickly)- Asset URLs have hashes (immutable cache is fine)
- Try a hard refresh or clear Cloudflare cache
# Full production build + preview
bun run preview:build
# Just preview existing build
bun run previewThe preview server mimics Cloudflare's behavior with proper caching headers.