feat(structure): compact archive + tag pages + hero/featured, and fix site search
Deploy / build (push) Failing after 13m52s

Found a real bug while verifying the nav search: /pagefind/pagefind.js is an ES
module that defines no window.Pagefind, but Search.astro loaded it with a classic
<script src> and read window.Pagefind — so every query answered "Search is
unavailable." (confirmed live before the fix). Now a dynamic import; the specifier
must be a variable or Rollup resolves it at build time and the build fails.

Measured before/after in a real browser:

- archive /posts/ + /zh/posts/: 18,220px -> 3,788px (71 rows at 44px, grouped by
  year) with a client-side filter (title/tags/description text, category chips,
  14 tag chips, zero requests). Tested: "nginx" -> 6 rows, chip devops -> 28.
- tag pages for tags with >= 3 posts. Measured 235 distinct tags (an earlier brief
  claimed 74), 156 used exactly once — pages only where a topic exists: 40 tags ->
  80 pages, build 165 -> 245 pages. Pills link only when a page exists.
- homepage + ZH homepage: hero (288px) with the real scale claim, three CTAs, a
  fixed Featured 4 (scale -> automation -> observability -> a delivered result),
  Latest 10 -> 6. ZH hero had linked "关于我" to the English /about/.
- long code blocks collapse above 420px with an Expand button + gradient, copy
  button still copies the whole block (verified on the 1010px block).
- search is visible ("⌕ Search /" pill, "/" plus the existing Ctrl/Cmd+K) and the
  zero-result screen offers topic chips instead of a dead end.

Docs: project-state B3 entry, ops-runbook Pagefind gotcha.
This commit is contained in:
hoelee committed 2026-10-16 21:18:25 +08:00
1 parent 8619e48271
commit f4008d9e8b
15 files changed
+669 -60

No files matched your search

+8
View File
@@ -32,6 +32,14 @@ Markdown (src/content/posts) → Astro build (dist/) → Gitea Actions → act_r
## Build pitfalls (from prior Astro work — check these first)
- **Pagefind is an ES module and exposes no window global.** `dist/pagefind/pagefind.js`
ends with `export { search, debouncedSearch, … }`. Load it with a dynamic `import()`, never
a classic `<script src>` + `window.Pagefind` — that combination silently made every search
answer "Search is unavailable." for as long as the overlay existed. The specifier must be a
**variable** (`const url = '/pagefind/pagefind.js'; await import(/* @vite-ignore */ url)`)
because Rollup resolves a literal dynamic-import path at build time and fails on a file that
does not exist until after the search index is generated.
- **No JSX helper components in frontmatter** — inline JSX directly in `.map()` calls, or the build fails with `Expected ">" but found "class"`.
- **Import depth** — `src/pages/*.astro` use `../layouts/…`; subdirs use `../../`. Wrong level = `Could not resolve`.
- **Footer must render AFTER `<main>`** — a shared header+footer component renders footer above content otherwise.
+8
View File
@@ -28,6 +28,14 @@ Living list of what's done and what's next for blog.hoelee.com. Work through the
- ✅ Knowledge guides in `docs/` + README index + `hoelee-blog` skill
- ✅ Both repos public (Gitea + GitHub) with title/description/homepage/topics + `v1.0.0` release
- ✅ **Live re-audit of the Sept research recorded (§2 Phase E + §4), 2026-09-29** — 53 posts × 2 languages, 127 sitemap URLs, 133/133 internal links 200
- ✅ **B3 structure batch, 2026-10-16 (third batch from the external design review)** — all numbers measured in a real browser (CDP), not by eye:
- **Found and fixed a real bug: site search never worked.** `/pagefind/pagefind.js` is an **ES module** (`export { search, debouncedSearch, … }`) that defines **no `window.Pagefind`**, but `Search.astro` loaded it with a classic `<script src>` and read `window.Pagefind` → `undefined` → every query in the overlay was answered **"Search is unavailable."** Live-verified before the fix. Loader is now a dynamic `import()`; the specifier must be a **variable** (`const url = '…'; import(/* @vite-ignore */ url)`) because Rollup resolves a literal path at build time and fails on a file that only exists in `dist/`. After: query "docker" → 12 hits, first = the Docker OOM post; ZH "容器" also returns hits.
- **Archive `/posts/` + `/zh/posts/`: 18,220px → 3,788px** (71 rows at 44px, grouped by year) with a client-side filter — title/tag/description text search + category chips + 14 tag chips, zero network requests (tested: "nginx" → 6 rows, chip `devops` → 28 rows, reset → 71).
- **Tag pages**: 235 distinct tags measured (the earlier brief said 74 — wrong), **156 of them used exactly once**; pages are generated only for tags with **≥ 3 posts** (40 tags → **80 pages**, build 165 → 245 pages). Tag pills on posts and listings link only when a page exists; one-off tags stay plain text. `/tags/docker/` → 25 posts.
- **Homepage + ZH homepage**: hero (288px desktop) with the real scale claim (162 containers / 3 hosts), 3 CTAs (case studies ↓ / hiring profile / SME work), **Featured 4** fixed slugs (scale → automation → observability → a delivered business result) and Latest trimmed 10 → 6.
- **Long code blocks collapse** at >420px with an "Expand (N lines) ↓" button and a gradient mask; the copy button still copies the full block (verified on `how-i-host-this-blog`: 1010px block).
- **Search is now visible** (nav pill "⌕ Search /" plus `/` as a shortcut next to the existing Ctrl/Cmd+K) and the zero-result screen offers topic chips + the archive instead of a dead end (verified with a query that matches nothing).
- ZH nav bug fixed in passing: the ZH hero linked "关于我" to the **English** `/about/`.
- ✅ **B2 broken-windows batch, 2026-10-16 (second batch from the external design review)** — every item verified before/after with `curl`:
- **`/posts/zh/` answered 403** (a directory with no index) → nginx now `301`s it to the new Chinese archive.
- **`/zh/posts/` did not exist** (404) → new `src/pages/zh/posts/index.astro` (build went 163 → 165 pages).