feat(library): offline search via Pagefind #87
No reviewers
Labels
No labels
area: arcade
area: art-studio
area: calendar
area: chapel
area: content
area: design
area: field-guide
area: infra
area: library
area: os
area: portal
area: sync
area: typing
blocked
breaking
bug
content: approved
content: changes-requested
content: drafting
content: needs-doctrinal-review
content: needs-review
dependencies
documentation
duplicate
enhancement
epic
github_actions
good first issue
help wanted
invalid
javascript
needs-triage
priority: high
priority: low
priority: medium
question
type: enhancement
type: feature
type: fix
type: perf
type: security
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Bosco/bosco!87
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/library-search"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The Library — offline search (v0.3.0 PR3)
Static, offline, in-browser search over the prerendered Library, powered by Pagefind. No server, no
runtime network — the build indexes the HTML and all querying happens client-side over that index.
The gate came first
Before any UI, the PR's real risk was proven empirically: Pagefind's binary is vendored, not
postinstall-fetched — it ships as ordinary platform packages (
@pagefind/<platform>, anoptionalDependenciesset with an emptyscriptsblock), sopnpm install --frozen-lockfileresolvesit from the lockfile with zero network, and the indexer runs fully offline. The lockfile records every
platform, so CI's Linux runner gets
@pagefind/linux-x64.What shipped
build(vite build && pnpm run index:search), so the guards and the offlinesmoke all see
build/pagefind/**.scripts/index-search.mjsdrives Pagefind's Node API, then:pagefind-entry.jsonreports ≥ 1 record (a zero-record index means thedata-pagefind-bodywrapper regressed → search would be silently empty), andpagefind-ui.*,-modular-ui.*,-component-ui.*, the highlighthelper): we ship our own UI, and one of those CSS files embeds bug-tracker URLs in a comment that
would (correctly) trip
guard:external. Pruning keeps the offline invariant intact and trims thebundle.
only the article body carries
data-pagefind-body, so home/category/error pages are ignored with nodata-pagefind-ignorechoreography.SearchPanel.svelte(onLibraryHome, so it appears both standalone andin-window). It loads the runtime with a runtime dynamic
import(/* @vite-ignore */ .../pagefind.js)—browser-only, absent under
vite dev, and degrades to "unavailable" if the load fails. Results are real/library/**links, so the desktop's delegated intercept opens them in-window while standalone / no-JSfollow the route.
pagefind.tsholds the cached loader + a pure, unit-testedtoHit()that re-appliesbaseto Pagefind's root-relative URLs.Verification
pnpm install --frozen-lockfileyields a working indexer offline (no installscript; binary from platform tarballs; runs and emits the bundle).
/librarylinks,<mark>highlight resolving tothe gold token (opaque), empty-state, zero console errors; in-window intercept preserves other windows.
0/0/0, 62 unit (+3
toHit), 16 e2e (+4: standalone search, in-window intercept, no-results, a11y).Architecture recorded in
docs/architecture/library.md. Closes the PR3 item on milestone v0.3.0.