Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/zola-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,53 @@ jobs:
BUILD_ONLY: true
BUILD_THEMES: false

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "20"

# Runs after `zola build`, before the artifact upload, so the index
# ships with the pages it describes and reflects this exact commit.
# The zola-deploy-action builds `website/public` as root inside Docker,
# so reclaim ownership before the Node step writes search-index.json.
- name: Build search index
run: |
cd website
sudo chown -R "$(id -u):$(id -g)" public
npm ci
npm run build:search-index
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Fail the deploy if the index is missing, malformed, or too small.
# Long pages are split into per-section records, so the real count is
# ~2,100+. MIN_RECORDS is a floor with headroom for content churn that is
# still high enough to catch a regression back to one-record-per-page
# (which would collapse the count to roughly 800).
- name: Verify search index
env:
MIN_RECORDS: "1500"
run: |
cd website
INDEX=public/search-index.json
if [ ! -s "$INDEX" ]; then
echo "::error::$INDEX is missing or empty"
exit 1
fi
COUNT=$(node -e "const a=require('./public/search-index.json'); if(!Array.isArray(a)){console.error('not an array');process.exit(1)} console.log(a.length)")
echo "search-index.json contains $COUNT records"
if [ "$COUNT" -lt "$MIN_RECORDS" ]; then
echo "::error::search index has $COUNT records, below the expected minimum of $MIN_RECORDS"
exit 1
fi
# Spot-check that render-time docs content (not just blog stubs) made
# it in: at least one /topics/ and one /commands/ page must be present.
node -e "
const a=require('./public/search-index.json');
const has=(p)=>a.some(r=>typeof r.url==='string'&&r.url.startsWith(p)&&(r.body||'').length>0);
const topics=has('/topics/'), commands=has('/commands/');
console.log('topics indexed:', topics, '| commands indexed:', commands);
if(!topics||!commands){console.error('::error::expected indexed /topics/ and /commands/ pages with content');process.exit(1)}
"

- name: Upload artifact
if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@v3
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DS_Store
public
package-lock.json
node_modules
build-bloom-command-json
build-command-docs
build-command-json
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,45 @@ Point your browser at `http://127.0.0.1:1111/commands/` and you should see the f
All files created in this process are ignored by git.
Commit your changes to your local copy of `valkey-io/valkey-doc` for description changes and `valkey-io/valkey` for command JSON changes (if you have any).

## Search

Site search is powered by [fuse.js](https://www.fusejs.io/) running entirely in the browser against a prebuilt index (`search-index.json`).

The index is not Zola's native search index. Most of this site's documentation (topics, the command reference, and the clients page) is injected at template-render time from the sibling repos described above, so it never appears in the Markdown page body that Zola's `build_search_index` reads. Instead, `build/build-search-index.mjs` walks the rendered HTML in `public/` after a build and extracts the visible page content, capturing everything the site actually renders.

Long pages are indexed as one record per top-level (`h2`) section rather than a single whole-page record, so deep content stays searchable and a result can link straight to the matching section via its heading anchor. Content before the first `h2`, and pages with no `h2`, produce a single page-level record. All records for one page share the same `title` (the page title); the section heading is stored separately and weighted well below the title, so splitting a page into sections does not let a thin section out-rank, or dilute, a page-name match. Because a long page contributes several records that share a base url, the client (`static/assets/js/search.js`) also caps how many sections from the same page appear in the results list.

### Testing search locally

Search does not work under `zola serve`. The dev server builds the site into memory and does not run the post-build indexer, so `search-index.json` is never generated or served and every query returns nothing. This is expected: `zola serve` is fine for editing content with live reload, but it cannot serve search.

To test search, build the site to disk (which also generates the index) and serve the `public/` directory with any static file server. The indexer needs [Node.js](https://nodejs.org/) (18 or newer); install dependencies once with `npm install`, then:

```shell
npm run build # zola build + generate search-index.json in public/
python3 -m http.server -d public 8080 # or any static server for public/
```

Open `http://localhost:8080/` and search will work. Any static server works; the only requirement is that it serves the `public/` directory produced by `npm run build`, including `search-index.json`.

The generated `public/search-index.json` is ignored by git; it is always produced fresh at build time. Because both `zola build` and `zola serve` wipe `public/`, re-run `npm run build` after any rebuild to refresh the index. To regenerate only the index against a `public/` that already exists on disk (for example after a plain `zola build`), run `npm run build:search-index`.

To search topics, the command reference, and the clients page locally, first follow [Building additional content](#building-additional-content) so those pages exist to be indexed. Otherwise only the blog, author, download, event, and static pages are searchable.

### Previewing complete results without the sibling repos

If you don't have the sibling repos checked out, you can build an index from a running site (production or a local `zola serve`) via its sitemap:

```shell
node build/build-search-index.mjs --crawl https://valkey.io
```

This is a local convenience for previewing complete results and is not used by the deploy pipeline.

### Automation

The deploy workflow (`.github/workflows/zola-deploy.yml`) regenerates the index on every deploy, after `zola build` and before the site is published, so it always reflects the commit being deployed.

## License

This project is licensed under the BSD-3-Clause License.
Loading
Loading