2026-03-08 16:16:04 +08:00

94 lines
3.0 KiB
TypeScript

import type { Plugin } from 'vuepress/core'
import type { SearchPluginOptions } from '../shared/index.js'
import { addViteOptimizeDepsInclude, getFullLocaleConfig } from '@vuepress/helper'
import chokidar from 'chokidar'
import { getDirname, path } from 'vuepress/utils'
import { SEARCH_LOCALES } from './locales/index.js'
import { onSearchIndexRemoved, onSearchIndexUpdated, prepareSearchIndex, prepareSearchIndexPlaceholder } from './prepareSearchIndex.js'
const __dirname = getDirname(import.meta.url)
/**
* Create a VuePress search plugin instance.
*
* 创建 VuePress 搜索插件实例。
*
* @param options - Plugin configuration options / 插件配置选项
* @param options.locales - Locale-specific search configurations / 特定语言的搜索配置
* @param options.isSearchable - Function to determine if a page should be indexed / 判断页面是否应被索引的函数
* @param options.searchOptions - MiniSearch options / MiniSearch 配置选项
* @returns VuePress plugin object / VuePress 插件对象
* @example
* // Basic usage
* export default {
* plugins: [
* searchPlugin()
* ]
* }
*
* // With custom options
* export default {
* plugins: [
* searchPlugin({
* locales: {
* '/zh/': { placeholder: '搜索文档' }
* },
* isSearchable: (page) => page.path !== '/secret/'
* })
* ]
* }
*/
export function searchPlugin({
locales = {},
isSearchable,
...searchOptions
}: SearchPluginOptions = {}): Plugin {
return app => ({
name: '@vuepress-plume/plugin-search',
clientConfigFile: path.resolve(__dirname, '../client/config.js'),
define: {
__SEARCH_LOCALES__: getFullLocaleConfig({
app,
name: '@vuepress-plume/plugin-search',
default: SEARCH_LOCALES,
config: locales,
}),
__SEARCH_OPTIONS__: searchOptions,
},
extendsBundlerOptions(bundlerOptions) {
addViteOptimizeDepsInclude(bundlerOptions, app, ['mark.js/src/vanilla.js', '@vueuse/integrations/useFocusTrap', 'minisearch'])
},
onPrepared: async (app) => {
if (app.env.isBuild) {
await prepareSearchIndex({ app, isSearchable, searchOptions })
}
else {
await prepareSearchIndexPlaceholder(app)
prepareSearchIndex({ app, isSearchable, searchOptions })
}
},
onWatched: (app, watchers) => {
const searchIndexWatcher = chokidar.watch('pages', {
cwd: app.dir.temp(),
ignoreInitial: true,
ignored: (filepath, stats) => Boolean(stats?.isFile()) && !filepath.endsWith('.js'),
})
searchIndexWatcher.on('add', (filepath) => {
onSearchIndexUpdated(filepath, { app, isSearchable, searchOptions })
})
searchIndexWatcher.on('change', (filepath) => {
onSearchIndexUpdated(filepath, { app, isSearchable, searchOptions })
})
searchIndexWatcher.on('unlink', (filepath) => {
onSearchIndexRemoved(filepath, { app, isSearchable, searchOptions })
})
watchers.push(searchIndexWatcher)
},
})
}