I had a really… interesting search on this site, with the Jekyll rewrite. It worked, I guess, but I never found it enjoyable to use, and it actually was a lot heavier than it should have been. It was based on Jekyll generating a search.json file, and the browser used
simple-jekyll-search to search it.
The real limitation was in the index itself. Each page contributed a title, URL, and only the first 160 characters of stripped content. That meant search could find titles and opening text, but anything deeper in a post was likely invisible. For a site with hundreds of older posts, that is not really search. It is more like a title lookup with a tiny content preview, and with the way I write, it actually wasn’t that efficient: I front-load content, but the real meat comes later, so a stripped-down index actually works against me, not for me.
There’s better out there, and I know of a lot of things better right out of the gate, so the only real question is how far afield I wanted to go. With some casual search, I found something right outside of Jekyll that gave me a much better search experience.
What Changed
The site now uses Pagefind for search.
Pagefind runs after Jekyll builds the site. Jekyll still produces the static HTML in _site, and then Pagefind scans that generated HTML and writes a static search bundle into _site/pagefind.
The publish flow now does this:
npm ci
JEKYLL_ENV=production bundle exec jekyll build
npm run search:index
The search:index script runs:
pagefind --site _site
The old simple-jekyll-search script include was removed from the default layout, and the sidebar search box now uses a small custom JavaScript file that loads Pagefind on demand. The navigation model stays the same, but the impact for clients and the server go way down, apart from the total index size, which went up - but we no longer download the full index, so it’s a win bandwidth-wise, as well as giving a far more complete search.
What Gets Indexed
Only the main page content is indexed.
The default layout now marks the central <main> element with data-pagefind-body. That tells Pagefind to ignore repeated page cruft such as
navigation, footer text, search UI, and quotes. The comments block is also marked with data-pagefind-ignore="all" so Disqus fallback text does not become part of the searchable page body.
Posts with dates expose a date metadata value to Pagefind. The search results use that metadata so the sidebar can show:
- title
- date
- excerpt
The excerpt is generated from the real matching content rather than the first few characters of the post.
One follow-up fix was needed after the first pass. Pagefind’s automatic title detection was finding the first <h1> on the page, which is the site header. That meant result links pointed to the right pages, but the visible title for each result was Enigmastation.com instead of the post title, which is technically correct, but … not actually correct in the sense that humans would want.
The layout now passes the page title explicitly through Pagefind metadata:
data-page-title="Fixing Search with Pagefind"
data-pagefind-meta="title[data-page-title]"
For dated posts, the same metadata attribute also captures the post date from a data-page-date attribute. This makes the search result display independent of whatever Pagefind might infer from the surrounding page chrome.
Why This Approach
This keeps Jekyll. Jekyll is working, fast, sufficient, and I have a workflow that suits me.
This preserves working permalink behavior, old WordPress upload paths, Markdown posts, some AsciiDoc posts, custom Liquid tags, category pages, archives, and a feed. A full platform migration would have to recreate or replace all of that before delivering any improvement.
Pagefind solves the immediate problem without requiring a database, an indexing server, or a new content model. It indexes the rendered HTML, which means it sees the final output after Markdown, AsciiDoc, Liquid, and wikilinks have been processed.
There is no runtime search server. The server only serves static files from /pagefind, and the browser fetches Pagefind’s search index chunks as needed; the overall index size is larger, but again, the actual impact goes down.
I am satisfied. So far.