Hugo Client Search

Client side search for Hugo, using Web Assembly

This project provides a modular search facility intended to integrate easily into Hugo static websites. It leverages a full-text index built by the site builder, runs entirely client side, and exploits Web Assembly (written in Go) to replace JavaScript where reasonable.

Goals

  1. Must-haves
    • Easy to integrate into standard Hugo site, few/no additional constraints on clients and browsers.
    • Involve some Go and Web Assembly (as a learning goal)
    • Functionally, leverage existing standard search index, optimize client performance through combination of server side post-processing and client side caching and performant lookups.
  2. Might-haves
    • (sliding scale) Google style search syntax, not just blind or fuzzy keyword matching.
    • Good documentation so others can easily deploy it.
    • (sliding scale) Learn more about typora and markdown for web writing.
  3. Non-goals

Design

Generally, leverage Hugo server render-to-json for the server-side index. Optionally do some trimming so the server-side index is more concise.

On the client, a script added to the search page scans user search input for matches in the index (which it downloads and caches if needed). Matches are rendered with links that user can click on. There are several good packages for managing the user input and rendering (Luna, ghosthunter...), learn from them (and maybe integrate with them). Key goal of this project is to minimize client side javascript, use Web Assembly where that makes sense.

Components

(To get hugo to render mermaid, initialize it to process div.language-mermaid instead of .mermaid, see https://discourse.gohugo.io/t/use-mermaid-with-code-fences/17211)

sequenceDiagram
participant hs as hugoServer
participant io as indexOptimizer
participant ci Cached Index
participant wasm as WASM
participant pt as pageTemplate
hs-->>hs: Rebuild, emit index.json
hs-->>io: Minimize index.json
pt-->>wasm: Input in search box
wasm ->> io: Retrieve modified index.json
io ->> ci: Changed index.json
wasm -->> ci: Search
wasm -->> pt: List of matches
pt -->> pt: Render matches

Index optimization is optional, implemented by a separate command. Client side should be able to handle both formats. Name of index file is constrained to one of a few defaults (index.json and ... )

CachedIndex module hardcodes the index fetch: should use if-modified-since and good compression [[which is?]]. CachedIndex persists on client side using [[means]].

PageTemplate invokes a partial template with 2 sections:

  • Search Box and invocation of WebAssembly
  • Results section that renders the results

User can tailor the partial to change look and feel. My implementation uses bootstrap for responsive rendering.