Personal website built with Astro, deployed to Cloudflare Workers.
- Keep answers short and concise.
- No fluff or cheerful filler.
- Technical prose only, be kind but direct.
- No emojis in commits, issues, PR comments, or code.
- Prefer clear recommendations over long option lists.
- Read files before making broad changes.
- Match existing style unless the task is intentionally changing the stack or conventions.
- Use specific TypeScript types; avoid
anyunless there is no practical alternative. - Check installed package types/docs instead of guessing external APIs.
- Do not remove intentional functionality without calling it out.
- Do not commit unless explicitly asked.
- Framework: Astro
- Styling: Authored CSS with custom properties and intrinsic design tokens
- Content: Markdown pages rendered by Astro
- Syntax Highlighting: Astro's Shiki integration with
@shikijs/transformers - Deployment: Cloudflare Workers via Wrangler
- Package Manager: pnpm
src/
├── components/ # Astro components
├── layouts/ # Shared page layouts
├── lib/astro/ # Astro-specific content and site helpers
├── pages/ # Astro routes, including dynamic post/project routes
├── posts/ # Markdown blog posts
└── projects/ # Markdown project pages
static/ # Static assets: images, favicon
docs/plans/ # Implementation plans for future workSITE_URL- Site origin used for canonical URLs and social cards.- Falls back to
http://localhost:4321in development.
ENVIRONMENT-productionorstaging.SITE_URL- Site URL for the deployed environment.
Runtime values are defined in wrangler.jsonc under env.production and env.staging.
pnpm dev # Start Astro dev server
pnpm build # Build for production
pnpm preview # Preview production build
pnpm deploy # Build and deploy to production
pnpm deploy:staging # Build and deploy to staging
pnpm lint # Run Prettier check + ESLint
pnpm check # Run astro check
pnpm format # Format with PrettierAfter code changes, run:
pnpm lint
pnpm check
pnpm buildDocumentation-only changes do not require the full build unless they affect rendered content or examples.
SITE_URL=https://johnhooks.io pnpm deploy
SITE_URL=https://website-staging.johnhooks.workers.dev pnpm deploy:stagingGitHub Actions workflows in .github/workflows/:
deploy-production.yml- Manual production deploy.deploy-staging.yml- Manual staging deploy.wrangler-deploy.yml- Shared deploy workflow.
Required GitHub secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
- Production: https://johnhooks.io and https://www.johnhooks.io
- Staging: https://website-staging.johnhooks.workers.dev
- Workers.dev: https://website.johnhooks.workers.dev
Most pages are prerendered at build time with:
export const prerender = true;Dynamic routes:
/robots.txt- Returns different content based onENVIRONMENT.
- Posts live in
src/content/posts/*.{md,mdx}. - Projects live in
src/content/projects/*.{md,mdx}. - Quotes live in
src/content/quotes/*.{md,mdx}. - Published post and project entries require
isPublished: truein frontmatter. - Homepage ordering is by
publishedOn, newest first. - Some older Markdown files use a custom
<doc-info>callout element styled insrc/app.css.
- See
docs/plans/sitemap.mdfor sitemap implementation notes.