homepage

Personal site built with Astro 7. Currently a read-only showcase of the public images on a Harbor registry; built to grow into a blog/portfolio with more backends (e.g. Gitea).

How it works

  • Static where possible, live where it matters. The home and 404 pages are prerendered. The registry pages (/registry/…) render on request through the Node adapter, reading Harbor via a live content collection (src/live.config.ts, loader in src/loaders/harbor.ts). No credentials or API calls reach the browser.
  • Cached. Rendered registry pages are kept in Astro's in-memory route cache for 60 s and served stale for up to 10 min while a fresh copy renders in the background (REGISTRY_CACHE in src/consts.ts). The listing also reuses a repository's artifacts for up to 5 min while its update_time is unchanged.
  • No rebuilds for new images. Pushing to Harbor shows up within about a minute. Rebuild only after code changes.
  • Harbor unreachable? The listing shows a notice and detail pages return 503; neither is cached.
  • Repository descriptions are rendered as Markdown with raw HTML escaped and unsafe link schemes removed.

Develop

cp .env.example .env   # set HARBOR_URL
pnpm install
pnpm dev               # http://localhost:4321
pnpm check             # type-check
pnpm build             # -> dist/
pnpm start             # run the production server (reads .env)

Without HARBOR_URL the registry is simply empty.

Deploy (Docker Compose)

cp .env.example .env        # set HARBOR_URL etc.
docker compose up -d --build

Harbor settings are passed to the container at runtime, so changing them needs a restart (docker compose up -d), not a rebuild. Served on ${PORT:-8080}.

Container (plain Docker)

docker build -t homepage \
  --build-arg SITE_URL=https://example.com \
  --build-arg HARBOR_URL=https://registry.example.com \
  .
docker run -p 8080:8080 homepage
# HARBOR_URL is baked in as a default env var; override it with -e HARBOR_URL=... if needed.
# optional robot account for non-public projects:
#   -e HARBOR_USERNAME='robot$showcase' -e HARBOR_PASSWORD=...

A small Node server (server.mjs) runs Astro's standalone handler, adds security headers, and serves hashed /_astro/ assets with long-lived caching. The server build is self-contained, so the image ships no node_modules.

S
Description
Simple astro homepage
Readme
376 KiB
Languages
TypeScript 51.2%
Astro 37.6%
JavaScript 5.7%
CSS 3.3%
Dockerfile 2.2%