npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vita-site/plugin-search

v1.0.0

Published

search plugin for VitaSite

Downloads

341

Readme

@vita-site/plugin-search

VitaSite 全文搜索插件,为 Markdown 站点提供中英文混合搜索能力。

特性

  • 中英文混合分词 — 中文单字 + 双字组合(bigram),英文按空格分词并小写化
  • 倒排索引 — 构建时生成倒排索引,客户端按需加载,搜索高效
  • 标题加权 — 标题匹配权重为内容匹配的 5 倍
  • 虚拟模块交付 — 通过 Vite 虚拟模块提供搜索索引,天然支持子目录部署(base 配置)
  • 懒加载 — 搜索索引在首次搜索时按需加载并缓存
  • 搜索取消 — 基于代数计数器的取消机制,连续搜索自动使前一次失效
  • 内容高亮 — 提供搜索结果高亮工具函数
  • 多语言支持 — 可按语言过滤搜索结果

安装

pnpm add @vita-site/plugin-search

使用

注册插件

在 VitaSite 配置中注册搜索插件:

import searchPlugin from '@vita-site/plugin-search/server'

export default {
  plugins: [searchPlugin()]
}

插件会在构建期间自动完成:

  1. 收集所有 Markdown 文档,按标题分段并分词
  2. 生成倒排索引,通过虚拟模块 virtual:vita-site-search/index 交付

客户端搜索

import { search, cancelSearch, highlight } from '@vita-site/plugin-search'

// 执行搜索
const response = await search('搜索关键词', {
  lang: 'zh',           // 可选,按语言过滤
  maxResults: 10,       // 可选,最大结果数,默认 10
  maxContentLength: 200 // 可选,内容截取长度,默认 200
})

if (response.status === 'success') {
  for (const result of response.matched) {
    console.log(result.title, result.path, result.heading)
    console.log(highlight('搜索关键词', result.content))
  }
}

// 取消搜索(例如用户关闭搜索弹窗时)
cancelSearch()

内容高亮

import { highlight } from '@vita-site/plugin-search'

highlight('搜索', '这是一个搜索功能的示例')
// → '这是一个<mark>搜索</mark>功能的示例'

highlight('search', 'search result', 'em')
// → '<em>search</em> result'

API

服务端

searchPlugin(options?)

创建搜索插件实例,注册为 VitaSite 插件。

import { type SearchPluginOptions } from '@vita-site/plugin-search/server'

declare function searchPlugin(options?: SearchPluginOptions): VitaSitePlugin

| 参数 | 类型 | 说明 | |-----------|-----------------------|-------------------| | options | SearchPluginOptions | 插件配置(预留扩展,当前无必填项) |

客户端

search(query, options?)

执行异步搜索,支持取消机制。首次调用时懒加载搜索索引。

declare function search(query: string, options?: SearchOptions): Promise<SearchResponse>

SearchOptions

| 参数 | 类型 | 默认值 | 说明 | |--------------------|----------|-------|---------| | lang | string | — | 按语言过滤结果 | | maxResults | number | 10 | 最大返回结果数 | | maxContentLength | number | 200 | 内容截取长度 |

SearchResponse

| 字段 | 类型 | 说明 | |-----------|---------------------------|-------------------------------| | status | 'success' \| 'canceled' | 搜索状态,canceled 表示被新搜索或手动取消取代 | | matched | SearchResult[] | 匹配结果列表 |

searchWithIndex(query, searchIndex, options?)

使用指定索引执行同步搜索(供测试使用),不支持取消机制。

declare function searchWithIndex(
  query: string,
  searchIndex: SearchIndex,
  options?: SearchOptions
): SearchResult[]

cancelSearch()

取消当前正在进行的搜索,递增代数计数器使正在进行的搜索立即失效。

declare function cancelSearch(): void

loadIndex()

懒加载搜索索引,首次调用时通过虚拟模块加载并缓存。

declare function loadIndex(): Promise<SearchIndex>

highlight(query, content, tag?)

高亮匹配内容,将查询文本用指定标签包裹。

declare function highlight(query: string, content: string, tag?: string): string

| 参数 | 类型 | 默认值 | 说明 | |-----------|----------|----------|-------| | query | string | — | 查询文本 | | content | string | — | 待高亮内容 | | tag | string | 'mark' | 高亮标签名 |

共享

tokenize(text)

中英文混合分词器,供索引构建和查询分词共同使用。

declare function tokenize(text: string): string[]
tokenize('搜索功能')   // ['搜', '索', '搜索', '功', '能', '功能']
tokenize('Hello World') // ['hello', 'world']

类型

SearchResult

interface SearchResult {
  score: number               // 匹配得分
  lang: string                // 语言标识
  path: string                // 路由路径
  hash: string                // 锚点 hash(用于页面内跳转)
  title: string               // 页面标题
  heading: string             // 段落标题
  content: string             // 匹配的文本片段
  matchType: 'page' | 'content' // page 匹配主标题,content 匹配段落内容
}

SearchIndex

interface SearchIndex {
  docs: SearchDoc[]                              // 文档列表
  index: Record<string, [number, number][]>      // 倒排索引:token → [docIndex, sectionIndex][]
}

架构

src/
├── server/          # 服务端:插件注册、索引构建、内容分段
│   ├── index.ts     # 插件入口,生命周期编排
│   ├── builder.ts   # 倒排索引构建器
│   └── splitter.ts  # Markdown 按标题分段器
├── client/          # 客户端:搜索执行、内容高亮
│   ├── index.ts     # 客户端导出
│   ├── search.ts    # 搜索逻辑(含取消机制)
│   ├── highlight.ts # 高亮工具
│   └── virtual.d.ts # 虚拟模块类型声明
├── common/          # 共享:分词器
│   └── tokenizer.ts # 中英文混合分词
├── types.ts         # 共享类型定义
└── index.ts         # 包入口

数据流

Markdown 文件
    ↓ afterParse
splitByHeadings() → 按标题分段
    ↓
buildSearchIndex() → 分词 + 构建倒排索引
    ↓
虚拟模块交付(Vite virtual module)
    ↓
客户端 loadIndex() → 懒加载索引
    ↓
search() → 分词查询 + 倒排索引匹配 + 评分排序
    ↓
SearchResult[]

评分策略

  • 标题匹配加权 5 倍sectionIndex === -1
  • 内容匹配权重 1 倍
  • 多个查询 token 命中同一文档/段落时得分累加
  • 最终按得分降序排列,截取 maxResults

索引体积优化

构建时使用 SearchDocBuild(含 titleTokens / contentTokens)生成倒排索引,输出时剥离 token 数据转为 SearchDoc,减少约 50% 索引体积。客户端搜索仅需倒排索引 + 文档元信息,无需预分词结果。

License

MIT