docs(adr): ADR-0005: Server-Side Search Index
@aRustyDev đang làm issue này rồi.
Từ ngày 5/1/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
ADR-0005: Server-Side Search Index
Status
Accepted
Context
MDBook's default HTML renderer includes client-side search powered by elasticlunr.js. The search index is loaded as JSON and executed in the browser.
For an HTMX-based architecture, we need to decide where search execution happens.
Decision Drivers
- HTMX Philosophy - Server returns HTML, not JSON
- Performance - Large books have large indexes
- Authorization - Search results should respect access control
- Simplicity - Minimize client-side JavaScript
Options Considered
Option A: Client-Side Search (like mdbook-html)
Ship elasticlunr.js and JSON index to browser.
<input type="search" onkeyup="search(this.value)">
<script>
const index = elasticlunr.Index.load(searchIndex);
function search(query) {
const results = index.search(query);
document.getElementById('results').innerHTML = renderResults(results);
}
</script>
Pros:
- No server required
- Instant results (after index load)
- Works offline
Cons:
- Large index download (100KB+ for big books)
- Slow initial load
- JavaScript required
- No auth filtering (all content in index)
- Against HTMX philosophy
Option B: Server-Side Search with JSON Response
Server searches, returns JSON, client renders.
<input hx-get="/search" hx-trigger="input changed delay:300ms">
Server returns:
{"results": [{"title": "Chapter 1", "url": "/docs/ch1"}]}
Pros:
- Index stays on server
- Can filter by auth
Cons:
- Requires client-side rendering
- Not hypermedia (JSON, not HTML)
- More JavaScript
Option C: Server-Side Search with HTML Response (Recommended)
Server searches, returns HTML fragment.
<input
type="search"
name="q"
hx-get="/docs/search"
hx-trigger="input changed delay:300ms"
hx-target="#search-results"
hx-swap="innerHTML">
<div id="search-results"></div>
Server returns:
<ul class="search-results">
<li><a href="/docs/ch1">Chapter 1</a><p>...matching text...</p></li>
<li><a href="/docs/ch2">Chapter 2</a><p>...matching text...</p></li>
</ul>
Pros:
- True hypermedia (HTML response)
- No client-side rendering logic
- Authorization-aware (filter results)
- Index never sent to client
- Works with minimal JS (just HTMX)
Cons:
- Requires server
- Network latency per search
Decision
Generate server-side search index; output HTML search results template.
Index Format
Default: search-index.json
{
"config": {
"heading_split_level": 3
},
"documents": [
{
"path": "/docs/chapter-1",
"title": "Getting Started",
"body": "Full text content...",
"headings": [
{"level": 2, "text": "Installation", "anchor": "#installation"},
{"level": 2, "text": "Configuration", "anchor": "#configuration"}
],
"auth": {
"access": "public"
}
}
]
}
Optional: search-index.sqlite for large books (using FTS5).
Search Partial Template
<!-- templates/partials/search-results.html -->
{% if results %}
<ul class="search-results">
{% for result in results %}
<li>
<a href="{{ result.path }}" hx-boost="true">
<strong>{{ result.title }}</strong>
</a>
<p class="excerpt">{{ result.excerpt | safe }}</p>
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-results">No results found for "{{ query }}"</p>
{% endif %}
Server Implementation
// Cloudflare Worker example
import Fuse from 'fuse.js';
import searchIndex from './search-index.json';
const fuse = new Fuse(searchIndex.documents, {
keys: ['title', 'body', 'headings.text'],
includeMatches: true,
threshold: 0.3,
});
app.get('/docs/search', async (c) => {
const query = c.req.query('q');
const user = await getUser(c.req);
let results = fuse.search(query);
// Filter by auth
results = results.filter(r =>
r.item.auth.access === 'public' ||
user?.roles.includes(r.item.auth.roles)
);
return c.html(await render('partials/search-results.html', {
query,
results: results.slice(0, 10)
}));
});
Consequences
Positive
- True hypermedia pattern
- Authorization-aware search
- No large index download
- Minimal client JavaScript
- Consistent with HTMX philosophy
Negative
- Requires server for search
- Network latency per query
- Server must implement search logic
Mitigation
- Debounce search input (300ms)
- Loading indicator during search
- Provide reference implementations (Workers, Deno, Node)
- Optional SQLite FTS5 for large books
Configuration
[output.htmx.search]
enabled = true
index-format = "json" # "json" | "sqlite"
heading-split-level = 3 # Index headings up to H3
include-body = true # Include full text
max-excerpt-length = 200 # Snippet length
Related ADRs
- ADR-0009: Audience Scopes - Generates scope-filtered search indexes (e.g.,
search-index.developers.json) - ADR-0021: Search Index Format Evolution - Versioning and migration strategy for the search index format
References
- Ngôn ngữ chính
- Rust
- Star
- 0
- Fork
- 1
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của aRustyDev/mdbook-htmx
-
feat(ci): Implement cross-repo-validate compliance for docs syncCó thể làm lại được @aRustyDev đã nhận 285 ngày trước và không có pull request nào đang mở. Đang mởci enhancement
aRustyDev/mdbook-htmx#58 · 1 bình luận · 1 người được giao ·
-
docs(htmx): Explain how HTMX worksCó thể làm lại được @aRustyDev đã nhận 287 ngày trước và không có pull request nào đang mở. Đang mở
aRustyDev/mdbook-htmx#48 · 3 bình luận · 1 người được giao ·
-
docs(mdbook-htmx): Parent Issue for documentationCó thể làm lại được @aRustyDev đã nhận 287 ngày trước và không có pull request nào đang mở. Đang mởdocumentation
aRustyDev/mdbook-htmx#47 · 1 người được giao ·
-
docs(examples): Secure Self-Hosted Meilisearch via CloudflareCó thể làm lại được @aRustyDev đã nhận 287 ngày trước và không có pull request nào đang mở. Đang mởdocumentation
aRustyDev/mdbook-htmx#46 · 1 người được giao ·
-
docs(examples): Kubernetes with MeilisearchCó thể làm lại được @aRustyDev đã nhận 287 ngày trước và không có pull request nào đang mở. Đang mởdocumentation
aRustyDev/mdbook-htmx#45 · 1 người được giao ·
Tất cả issue của aRustyDev/mdbook-htmx
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
home-assistant/installer#308 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
swc-project/swc-next#1053 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
What happened to `check.py`?Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
linebender/resvg#1179 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
enhancement triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
zizmorcore/zizmor#2468 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Maintainer thường phản hồi trong vòng 2 ngày