-
Notifications
You must be signed in to change notification settings - Fork 0
WASM API
Complete API for modern-cmdk-search-wasm — the optional Rust/WebAssembly trigram search engine.
pnpm add modern-cmdk-search-wasmThe WASM binary is bundled and loaded automatically. No additional build configuration needed.
Creates a WASM-powered search engine that runs on the main thread. Drop-in replacement for the default TypeScript engine.
import { createWasmSearchEngine } from 'modern-cmdk-search-wasm';
import { createCommandMachine } from 'modern-cmdk';
const wasmEngine = await createWasmSearchEngine();
using machine = createCommandMachine({
search: wasmEngine,
});- Sub-1ms fuzzy search on 100K items
- Trigram index for high-quality fuzzy matching
- ~150KB WASM binary (gzip: ~60KB)
Creates a WASM search engine that runs in a Web Worker, keeping the main thread free for rendering.
import { createWorkerWasmSearchEngine } from 'modern-cmdk-search-wasm';
const workerEngine = await createWorkerWasmSearchEngine();
using machine = createCommandMachine({
search: workerEngine,
});When cross-origin isolation headers are set, results are transferred via SharedArrayBuffer for zero-copy performance:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Without these headers, results are transferred via postMessage structured clone (still fast for typical result sizes).
Both WASM engines implement the standard SearchEngine interface:
interface SearchEngine {
index(items: readonly CommandItem[]): void;
search(query: string, items: readonly CommandItem[]): IteratorObject<SearchResult>;
remove(ids: ReadonlySet<ItemId>): void;
clear(): void;
}Main Thread Web Worker WASM Module
| | |
|-- new Worker() ------------>| |
| |-- import wasm ------->|
| |<-- module loaded -----|
|<-- { type: ready } ---------| |
| | |
|-- { type: index, items } -->| |
| |-- index_items() ---->|
| |<-- index built -------|
|<-- { type: indexed } -------| |
| | |
|-- { type: search, | |
| query, scoresBuffer } -->| |
| |-- search() --------->|
| |<-- raw results -------|
| |-- write to SAB |
|<-- { type: results-sab, | |
| ids, matches } ----------| |
|-- read Float32Array | |
| (zero-copy) | |
| | |
|-- { type: dispose } ------->| |
| |-- instance.free() -->|
| |-- self.close() |
The Rust crate builds a trigram index from item values and keywords:
- Each item's
valueandkeywordsare split into overlapping 3-character substrings - A reverse index maps each trigram to a set of item IDs
- On search, the query is split into trigrams and matched against the index
- Results are scored by trigram overlap ratio with position bonuses
This provides:
- O(1) lookup per trigram (hash map)
- Sub-linear search — only items sharing trigrams with the query are scored
- High recall — even with typos, shared trigrams surface relevant results
| Scenario | Recommendation |
|---|---|
| < 500 items | Default TypeScript engine is sufficient |
| 500 - 5K items | WASM main thread for snappier feel |
| 5K - 100K items | WASM Worker for zero main-thread blocking |
| > 100K items | WASM Worker + virtualization |
| Engine | Size (raw) | Size (gzip) |
|---|---|---|
| TypeScript (default) | 0 KB (included in core) | 0 KB |
| WASM main thread | ~150 KB | ~60 KB |
| WASM Worker | ~155 KB | ~62 KB |
The WASM engine is fully tree-shakeable. If not imported, it adds zero bytes to your bundle.
try {
const engine = await createWasmSearchEngine();
} catch (error) {
// WASM not supported — fall back to TypeScript engine
console.warn('WASM search unavailable, using default engine');
const { createSearchEngine } = await import('modern-cmdk');
const engine = createSearchEngine();
}Both createWasmSearchEngine() and createWorkerWasmSearchEngine() return Promises that reject if WASM instantiation fails (e.g., Content Security Policy blocks WebAssembly.instantiate).