slimsearch
A powerful client-side search plugin featuring custom indexing and full-text search support.
Usage
npm i -D @vuepress/plugin-slimsearch@nextimport { slimsearchPlugin } from '@vuepress/plugin-slimsearch'
export default {
plugins: [
slimsearchPlugin({
// options
}),
],
}Search Index
Powered by slimsearch, this plugin provides ultra-fast search capabilities, even for large documentation sites.
By default, the plugin indexes only headings, article excerpts, and any custom fields you configure. If you wish to index the full content of your pages, set indexContent: true in the plugin options.
To exclude a specific page from the index, set search: false in its frontmatter. For programmatic filtering (e.g., excluding pages based on paths), use the filter option.
Custom Fields
Whether you are a theme developer or a user, it is common to attach extra metadata to pages via frontmatter or the extendsPage lifecycle hook. You can add this data to the search index using the customFields option.
The customFields option accepts an array of configuration objects. Each object consists of two parts:
getter: A function that receives thepageobject and returns the value to be indexed. It can return a string, an array of strings, ornull/undefinedif the field is missing.formatter: A string or object defining how the item appears in search results. The placeholder$contentis replaced by the value returned by thegetter. If your site supports multiple languages, you can provide an object mapping locale paths to format strings.
Example: Adding Author to Index
Suppose you define an author in your frontmatter:
---
author: Your name
---
Your Markdown content...You can add this author information to the search index like this:
import { slimsearchPlugin } from '@vuepress/plugin-slimsearch'
export default {
plugins: [
slimsearchPlugin({
customFields: [
{
name: 'author',
getter: (page) => page.frontmatter.author,
formatter: 'Author: $content',
},
],
}),
],
}Example: Adding Update Time
Suppose you are using the @vuepress/plugin-git plugin and host Chinese docs under /zh/ and English docs under /.
You can index the last updated time with locale-specific formatting:
import { slimsearchPlugin } from '@vuepress/plugin-slimsearch'
import { defineUserConfig } from 'vuepress'
export default defineUserConfig({
// Assuming the following locale config
locales: {
'/': {
lang: 'en-US',
},
'/zh/': {
lang: 'zh-CN',
},
},
plugins: [
slimsearchPlugin({
customFields: [
{
name: 'updateTime',
getter: (page) => page.data.git?.updateTime.toLocaleString(),
formatter: {
'/': 'Update time: $content',
'/zh/': '更新时间:$content',
},
},
],
}),
],
})Options
indexContent
- Type:
boolean - Default:
false
Whether to enable full content indexing.
Tips
By default, only page headings, excerpts, and custom fields are indexed. Set this to true only if you need to search the entire body text of your pages.
suggestion
- Type:
boolean - Default:
true
Whether to display search suggestions while typing.
customFields
Type:
CustomFieldOptions[]interface CustomFieldOptions { /** * Custom field getter */ getter: (page: Page) => string[] | string | null | undefined /** * Display content format * * @description `$content` will be replaced by the value returned by `getter` * * @default `$content` */ formatter?: Record<string, string> | string }
Configuration for indexing custom fields.
hotKeys
Type:
(KeyOptions | string)[]export interface KeyOptions { /** * Value of `event.key` to trigger the hot key * * 热键的 `event.key` 值 */ key: string /** * Whether to press `event.altKey` at the same time * * 是否同时按下 `event.altKey` * * @default false */ alt?: boolean /** * Whether to press `event.ctrlKey` at the same time * * 是否同时按下 `event.ctrlKey` * * @default false */ ctrl?: boolean /** * Whether to press `event.shiftKey` at the same time * * 是否同时按下 `event.shiftKey` * * @default false */ shift?: boolean /** * Whether to press `event.metaKey` at the same time * * 是否同时按下 `event.metaKey` * * @default false */ meta?: boolean }Default:
[{ key: "k", ctrl: true }, { key: "/", ctrl: true }]
Specify the event.key for hotkeys.
Pressing these keys will focus the search input. Set to an empty array [] to disable hotkeys.
queryHistoryCount
- Type:
number - Default:
5
The maximum number of search query history items to store. Set to 0 to disable.
resultHistoryCount
- Type:
number - Default:
5
The maximum number of matched result history items to store. Set to 0 to disable.
searchDelay
- Type:
number - Default:
150
The delay (in milliseconds) before starting a search after input.
Note
Client-side searching on sites with massive content can be resource-intensive. You may need to increase this value to ensure the user has finished typing before the search triggers.
filter
- Type:
(page: Page) => boolean - Default:
() => true
A function to filter which pages are included in the index.
sortStrategy
- Type:
"max" | "total" - Default:
"max"
The strategy used to sort search results.
When multiple results match, this determines the order. max places pages with the highest single-match score first. total places pages with the highest cumulative score first.
worker
- Type:
string - Default:
slimsearch.worker.js
The filename for the output Worker script.
hotReload
- Type:
boolean - Default: Same as the
--debugflag status
Whether to enable hot reloading of the search index in the development server.
Note
This is disabled by default because rebuilding the index on every file change can severely impact performance on large sites.
indexOptions
Type:
SlimSearchIndexOptionsinterface SlimSearchIndexOptions { /** * Function to tokenize the index field item. */ tokenize?: (text: string, fieldName?: string) => string[] /** * Function to process or normalize terms in the index field. */ processTerm?: (term: string) => string[] | string | false | null | undefined }
Options passed to slimsearch during index creation.
indexLocaleOptions
- Type:
Record<string, SlimSearchIndexOptions>
Options for index creation per locale. The object keys should correspond to the locale path.
locales
Type:
SlimSearchLocaleConfiginterface SlimSearchLocaleData { /** * Search box placeholder */ placeholder: string /** * Search text label */ search: string /** * Clear search text label */ clear: string /** * Remove current item label */ remove: string /** * Searching status text */ searching: string /** * Cancel text label */ cancel: string /** * Default title */ defaultTitle: string /** * Select hint */ select: string /** * Navigate hint */ navigate: string /** * Autocomplete hint */ autocomplete: string /** * Close hint */ exit: string /** * Loading hint */ loading: string /** * Search query history title */ queryHistory: string /** * Search result history title */ resultHistory: string /** * Empty history hint */ emptyHistory: string /** * Empty result hint */ emptyResult: string } interface SlimSearchLocaleConfig { [localePath: string]: SlimSearchLocaleData }
Multilingual configuration for the search UI.
Built-in Supported Languages
- Simplified Chinese (zh-CN)
- Traditional Chinese (zh-TW)
- English (United States) (en-US)
- German (de-DE)
- Russian (ru-RU)
- Ukrainian (uk-UA)
- Vietnamese (vi-VN)
- Portuguese (pt)
- Polish (pl-PL)
- French (fr-FR)
- Spanish (es-ES)
- Slovak (sk-SK)
- Japanese (ja-JP)
- Turkish (tr-TR)
- Korean (ko-KR)
- Finnish (fi-FI)
- Indonesian (id-ID)
- Dutch (nl-NL)
Frontmatter
search
- Type:
boolean - Default:
true
Whether to include this page in the search index.
Advanced
Customize Index Generation
You can customize the index generation process using indexOptions and indexLocaleOptions. This allows you to fine-tune indexing results globally or for specific locales.
We use the Intl.Segmenter API for tokenization (word-splitting) by default. While this works well for most languages, you might want to provide a custom tokenize function for specific languages to improve search accuracy.
Using with API
To access the search functionality programmatically, import the createSearchWorker function from @vuepress/plugin-slimsearch/client:
import { createSearchWorker } from '@vuepress/plugin-slimsearch/client'
import { defineClientConfig } from 'vuepress/client'
const { all, suggest, search, terminate } = createSearchWorker()
// Suggest terms based on input
suggest('key').then((suggestions) => {
// Handle search suggestions
})
// Search for content
search('keyword').then((results) => {
// Handle search results
})
// Get both suggestions and results
all('key').then(({ suggestions, results }) => {
// Handle suggestions and results
})
// Terminate the worker when no longer needed
terminate()Limitations in DevServer
The search service runs in a Web Worker. In development mode, we cannot bundle the worker file like in production.
To load search indexes in the dev server, we use a modern Service Worker with type: "module". If you want to test search functionality locally, please ensure your browser supports ES Module Workers (see CanIUse).
For performance reasons, adding, editing, or deleting Markdown content will not trigger a search index update in development mode by default. If you are refining search results, you can enable hot reloading by setting hotReload: true.
Comparing with Server-Search
Client-side search offers benefits like zero backend dependencies and ease of integration, but it also comes with trade-offs.
Disadvantages
- Build Time: Indexes are generated during the build, which increases deployment time and the size of the output bundle.
- Bandwidth: Users must download the search index before they can search. The more content you have, the larger the index file, which consumes more bandwidth.
- Latency: Users must wait for the index to be downloaded and parsed locally. This initial load can be slower than a direct API request to a server-side search engine.
- Device Performance: Since the search logic runs on the user's device, speed is dependent on their hardware capabilities.
If you are building a very large site, it is recommended to use a dedicated search service provider like Algolia, or host an open-source search crawler on your own server. This approach is more scalable as users only send search queries over the network rather than downloading the entire dataset.
Notably, DocSearch is a free service by Algolia for open-source projects. If you maintain open-source documentation or a technical blog, you can apply for it and use the @vuepress/plugin-docsearch plugin.
Client Config
defineSearchConfig
Customize search options. Accepts a plain object, a ref, or a getter function.
Since searching is performed inside a Web Worker, you cannot pass function-typed options directly to slimsearch.
However, to provide more accurate queries, suggestions, and results, we expose querySplitter, suggestionsFilter, and resultsFilter options in the client config. You can set these for specific languages or globally:
interface SearchLocaleOptions extends Omit<
SearchOptions,
'boostDocument' | 'fields' | 'filter' | 'processTerm' | 'tokenize'
> {
/** A function to split words */
querySplitter?: (query: string) => Promise<string[]>
/** A function to filter suggestions */
suggestionsFilter?: (
suggestions: string[],
query: string,
locale: string,
pageData: PageData,
) => string[]
/** A function to filter search results */
resultsFilter?: (
results: SearchResult[],
query: string,
locale: string,
pageData: PageData,
) => SearchResult[]
}
interface SearchOptions extends SearchLocaleOptions {
/** Setting different options per locale */
locales?: Record<string, SearchLocaleOptions>
}
export const defineSearchConfig: (
options: MaybeRefOrGetter<SearchOptions>,
) => voidimport { defineSearchConfig } from '@vuepress/plugin-slimsearch/client'
defineSearchConfig({
// global search options here
locales: {
'/zh/': {
// set different options for Chinese
},
},
})Components
- SearchBox
