lilith-platform.live/docs/prerender-guide.md

79 lines
3.5 KiB
Markdown
Raw Normal View History

# pSEO Static Prerender Guide
## How it works
The `pseoPrerendererPlugin` Vite plugin runs as part of `vite build` (in `closeBundle`). After the SPA bundle is assembled, the plugin:
1. Fetches `GET /www/sitemap.xml` from the quinn.api to discover all pSEO routes
2. Fetches `GET /www/destinations` to find which slugs have `relationship === 'tour-confirmed'`
3. For each remaining route, fetches the specific page data and writes `dist/_/<route>/index.html` with the correct `<title>`, `<meta>`, `<link rel="canonical">`, and `<script type="application/ld+json">` tags injected into the HTML template
4. Emits `dist/prerender-manifest.json` listing all routes written, skipped, and excluded
Nginx serves the prerendered `index.html` for known routes via `try_files $uri/index.html $uri /index.html`. React hydrates on the client and takes over from there.
## Routes covered
| Pattern | Source |
|---------|--------|
| `/_/escorts/in-{slug}` | destinations table, all non-tour-confirmed rows |
| `/_/trans-escorts/in-{slug}` | same destinations |
| `/_/escorts/{region}` | regions table |
| `/_/trans-escorts/{region}` | same regions |
| `/_/what-is/{slug}` | hobby_terms table |
## Excluded routes
**Tour-confirmed destinations** are excluded at build time. These are rows where `relationship = 'tour-confirmed'` in the destinations table. Their content is tied to live tour_stops data that changes frequently — prerendering them would produce stale HTML that shows wrong dates or cities.
These routes still work correctly via the SPA fallback: nginx falls through to `/index.html`, React hydrates, and the client fetches live data.
To see which slugs were excluded in the last build:
```bash
cat deployments/@domains/quinn.www/root/dist/prerender-manifest.json | jq '.tourConfirmedExcluded'
```
## Environment variables
| Variable | Default | Purpose |
|----------|---------|---------|
| `QUINN_API_URL` | `http://localhost:3030` | Base URL of quinn.api — must be reachable at build time |
Set this in the build environment when deploying (e.g. in `deploy.sh` before `bun run build`):
```bash
export QUINN_API_URL=http://localhost:3030 # on VPS, api runs on :3030
cd deployments/@domains/quinn.www/root && bun run build
```
## Rebuilding
The prerender runs automatically on every `bun run build`. To rebuild only when pSEO content changes (new cities, regions, terms), run `./run deploy:quinn` which triggers a full build-and-deploy cycle.
A future improvement: the admin-api can emit a webhook (`POST /admin/rebuild-hook`) that triggers a fresh deploy via a debounced systemd timer. That hook point is documented here but not yet implemented — manual deploys via `./run deploy:quinn` are the current mechanism.
## Verification
After a build, confirm JSON-LD is present in the raw HTML:
```bash
# Local (after build)
grep -l 'application/ld+json' deployments/@domains/quinn.www/root/dist/_/escorts/in-*/index.html | head -5
# Check one file
grep 'application/ld+json' deployments/@domains/quinn.www/root/dist/_/escorts/in-san-francisco/index.html
# On prod (curl without JS execution)
curl -s https://transquinnftw.com/_/escorts/in-san-francisco | grep 'application/ld+json'
```
## Plugin source
`deployments/@domains/quinn.www/root/plugins/vite-plugin-pseo-prerender.ts`
## Nginx config
The `/_/` location block in `deployments/@domains/quinn.www/nginx/prod.conf` uses:
```nginx
try_files $uri/index.html $uri /index.html;
```
This serves `dist/_/escorts/in-{slug}/index.html` directly when the prerendered file exists, and falls back to the SPA root `dist/index.html` for any route that was skipped.