Files
patrickandClaude Sonnet 5 4a19335a1e feat: rework starter kit for self-hosted deploy (Vite/React + Fastify/Drizzle/Postgres)
Replace Next.js/Supabase/Vercel stack with a self-hostable setup: Vite+React
frontend, Fastify+Drizzle+PostgreSQL backend with own JWT auth, deploy via
git pull + rsync + systemd (checkout/service separated, updates pulled from
Gitea). Adds a reference auth route (register/login/me) as the canonical
pattern for new routes. Updates all skills/rules/agents/docs to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMdBJfD9TT6XUU2NqGG1PN
2026-09-08 11:42:47 +02:00

2.0 KiB

Performance Monitoring

Lighthouse Check (after every deployment)

  1. Open Chrome DevTools (F12)
  2. Go to Lighthouse tab
  3. Select: Performance, Accessibility, Best Practices, SEO
  4. Generate Report for both Mobile and Desktop
  5. Target: Score > 90 in all categories

Common Performance Issues

Unoptimized Images

// Bad - unoptimized, no lazy loading
<img src="/large-image.jpg" />

// Good - explicit dimensions + native lazy loading
<img src="/large-image.jpg" width={800} height={600} loading="lazy" alt="Description" />

Pre-resize/compress source images (e.g. with sharp in a build step, or an image CDN) — Vite does not do this automatically like Next.js Image did.

Large JavaScript Bundle

Use dynamic imports for heavy components that aren't needed on initial load:

import { lazy, Suspense } from "react";

const HeavyChart = lazy(() => import("./HeavyChart"));

<Suspense fallback={<p>Loading chart...</p>}>
  <HeavyChart />
</Suspense>

Vite code-splits dynamic imports automatically — check npm run build's output chunk sizes.

Missing Loading States

Always show feedback during data fetching:

// Use shadcn Skeleton component
import { Skeleton } from "@/components/ui/skeleton"

if (isLoading) return <Skeleton className="h-12 w-full" />

No Caching Strategy

Cache slow backend queries in-process (see database-optimization.md) rather than re-querying Postgres on every request for rarely-changing data.

Quick Wins Checklist

  • Images have explicit width/height and loading="lazy" where below the fold
  • Heavy components use React.lazy + Suspense
  • Loading states show skeleton/spinner
  • Fonts loaded via @font-face/Google Fonts <link>, with font-display: swap
  • Production build (npm run build) checked for unexpectedly large chunks

Automated Monitoring

  • Self-hosted Plausible or Umami for privacy-friendly traffic analytics
  • web-vitals npm package to report Core Web Vitals from real users to your own backend/logging