You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vitepress/docs/ru/reference/default-theme-search.md

13 KiB

outline
deep

Поиск

VitePress поддерживает нечёткий полнотекстовый поиск с использованием внутрибраузерного индекса благодаря MiniSearch. Чтобы включить эту функцию, просто установите значение 'local' для опции themeConfig.search.provider в файле .vitepress/config.ts:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local'
    }
  }
})

Пример результата:

скриншот модального окна поиска

В качестве альтернативы можно использовать Algolia DocSearch или некоторые плагины сообщества, например https://www.npmjs.com/package/vitepress-plugin-search или https://www.npmjs.com/package/vitepress-plugin-pagefind.

i18n

Пример конфигурации для использования многоязычного поиска:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local',
      options: {
        locales: {
          ru: { // используйте ключ `root`, если хотите перевести локаль по умолчанию
            translations: {
              button: {
                buttonText: 'Поиск',
                buttonAriaLabel: 'Поиск'
              },
              modal: {
                displayDetails: 'Отобразить подробный список',
                resetButtonTitle: 'Сбросить поиск',
                backButtonTitle: 'Закрыть поиск',
                noResultsText: 'Нет результатов по запросу',
                footer: {
                  selectText: 'выбрать',
                  selectKeyAriaLabel: 'выбрать',
                  navigateText: 'перейти',
                  navigateUpKeyAriaLabel: 'стрелка вверх',
                  navigateDownKeyAriaLabel: 'стрелка вниз',
                  closeText: 'закрыть',
                  closeKeyAriaLabel: 'esc'
                }
              }
            }
          }
        }
      }
    }
  }
})

Параметры MiniSearch

Вы можете настроить MiniSearch следующим образом:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local',
      options: {
        miniSearch: {
          /**
           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}
           */
          options: {
            /* ... */
          },
          /**
           * @type {import('minisearch').SearchOptions}
           * @default
           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }
           */
          searchOptions: {
            /* ... */
          }
        }
      }
    }
  }
})

Подробнее в документации MiniSearch.

Пользовательский рендерер содержимого

Вы можете настроить функцию, используемую для отображения содержимого в формате Markdown перед его индексацией:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local',
      options: {
        /**
         * @param {string} src
         * @param {import('vitepress').MarkdownEnv} env
         * @param {import('markdown-it')} md
         */
        _render(src, env, md) {
          // возвращаем html
        }
      }
    }
  }
})

Эта функция будет очищена от данных сайта на стороне клиента, поэтому вы можете использовать в ней API Node.js.

Вы можете исключить страницы из поиска, добавив search: false в блок метаданных страницы. Альтернативный вариант:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local',
      options: {
        _render(src, env, md) {
          const html = md.render(src, env)
          if (env.frontmatter?.search === false) return ''
          if (env.relativePath.startsWith('some/path')) return ''
          return html
        }
      }
    }
  }
})

::: warning ПРИМЕЧАНИЕ В случае, если предоставляется пользовательская функция _render, вам нужно самостоятельно обработать заголовок search: false. Кроме того, объект env не будет полностью заполнен до вызова md.render, поэтому любые проверки необязательных свойств env, таких как frontmatter, должны быть выполнены после этого. :::

Пример: Преобразование содержимого - добавление якорей

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'local',
      options: {
        _render(src, env, md) {
          const html = md.render(src, env)
          if (env.frontmatter?.title)
            return md.render(`# ${env.frontmatter.title}`) + html
          return html
        }
      }
    }
  }
})

VitePress поддерживает поиск в вашей документации с помощью Algolia DocSearch. Обратитесь к руководству по началу работы. В файле .vitepress/config.ts вам нужно будет указать, по крайней мере, следующее, чтобы всё работало:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'algolia',
      options: {
        appId: '...',
        apiKey: '...',
        indexName: '...'
      }
    }
  }
})

i18n

Пример конфигурации для использования многоязычного поиска:

import { defineConfig } from 'vitepress'

export default defineConfig({
  themeConfig: {
    search: {
      provider: 'algolia',
      options: {
        appId: '...',
        apiKey: '...',
        indexName: '...',
        locales: {
          ru: {
            placeholder: 'Поиск в документации',
            translations: {
              button: {
                buttonText: 'Поиск',
                buttonAriaLabel: 'Поиск'
              },
              modal: {
                searchBox: {
                  resetButtonTitle: 'Сбросить поиск',
                  resetButtonAriaLabel: 'Сбросить поиск',
                  cancelButtonText: 'Отменить поиск',
                  cancelButtonAriaLabel: 'Отменить поиск'
                },
                startScreen: {
                  recentSearchesTitle: 'История поиска',
                  noRecentSearchesText: 'Нет истории поиска',
                  saveRecentSearchButtonTitle: 'Сохранить в истории поиска',
                  removeRecentSearchButtonTitle: 'Удалить из истории поиска',
                  favoriteSearchesTitle: 'Избранное',
                  removeFavoriteSearchButtonTitle: 'Удалить из избранного'
                },
                errorScreen: {
                  titleText: 'Невозможно получить результаты',
                  helpText:
                    'Вам может потребоваться проверить подключение к Интернету'
                },
                footer: {
                  selectText: 'выбрать',
                  navigateText: 'перейти',
                  closeText: 'закрыть',
                  searchByText: 'поставщик поиска'
                },
                noResultsScreen: {
                  noResultsText: 'Нет результатов для',
                  suggestedQueryText: 'Вы можете попытаться узнать',
                  reportMissingResultsText:
                    'Считаете, что поиск даёт ложные результаты?',
                  reportMissingResultsLinkText:
                    'Нажмите на кнопку «Обратная связь»'
                }
              }
            }
          }
        }
      }
    }
  }
})

Эти параметры можно переопределить. Чтобы узнать о них больше, обратитесь к официальной документации Algolia.

Конфигурация поискового робота

Вот пример конфигурации, основанной на той, что используется на этом сайте:

new Crawler({
  appId: '...',
  apiKey: '...',
  rateLimit: 8,
  startUrls: ['https://vitepress.dev/'],
  renderJavaScript: false,
  sitemaps: [],
  exclusionPatterns: [],
  ignoreCanonicalTo: false,
  discoveryPatterns: ['https://vitepress.dev/**'],
  schedule: 'at 05:10 on Saturday',
  actions: [
    {
      indexName: 'vitepress',
      pathsToMatch: ['https://vitepress.dev/**'],
      recordExtractor: ({ $, helpers }) => {
        return helpers.docsearch({
          recordProps: {
            lvl1: '.content h1',
            content: '.content p, .content li',
            lvl0: {
              selectors: 'section.has-active div h2',
              defaultValue: 'Documentation'
            },
            lvl2: '.content h2',
            lvl3: '.content h3',
            lvl4: '.content h4',
            lvl5: '.content h5'
          },
          indexHeadings: true
        })
      }
    }
  ],
  initialIndexSettings: {
    vitepress: {
      attributesForFaceting: ['type', 'lang'],
      attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
      attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],
      attributesToSnippet: ['content:10'],
      camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],
      searchableAttributes: [
        'unordered(hierarchy_radio_camel.lvl0)',
        'unordered(hierarchy_radio.lvl0)',
        'unordered(hierarchy_radio_camel.lvl1)',
        'unordered(hierarchy_radio.lvl1)',
        'unordered(hierarchy_radio_camel.lvl2)',
        'unordered(hierarchy_radio.lvl2)',
        'unordered(hierarchy_radio_camel.lvl3)',
        'unordered(hierarchy_radio.lvl3)',
        'unordered(hierarchy_radio_camel.lvl4)',
        'unordered(hierarchy_radio.lvl4)',
        'unordered(hierarchy_radio_camel.lvl5)',
        'unordered(hierarchy_radio.lvl5)',
        'unordered(hierarchy_radio_camel.lvl6)',
        'unordered(hierarchy_radio.lvl6)',
        'unordered(hierarchy_camel.lvl0)',
        'unordered(hierarchy.lvl0)',
        'unordered(hierarchy_camel.lvl1)',
        'unordered(hierarchy.lvl1)',
        'unordered(hierarchy_camel.lvl2)',
        'unordered(hierarchy.lvl2)',
        'unordered(hierarchy_camel.lvl3)',
        'unordered(hierarchy.lvl3)',
        'unordered(hierarchy_camel.lvl4)',
        'unordered(hierarchy.lvl4)',
        'unordered(hierarchy_camel.lvl5)',
        'unordered(hierarchy.lvl5)',
        'unordered(hierarchy_camel.lvl6)',
        'unordered(hierarchy.lvl6)',
        'content'
      ],
      distinct: true,
      attributeForDistinct: 'url',
      customRanking: [
        'desc(weight.pageRank)',
        'desc(weight.level)',
        'asc(weight.position)'
      ],
      ranking: [
        'words',
        'filters',
        'typo',
        'attribute',
        'proximity',
        'exact',
        'custom'
      ],
      highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
      highlightPostTag: '</span>',
      minWordSizefor1Typo: 3,
      minWordSizefor2Typos: 7,
      allowTyposOnNumericTokens: false,
      minProximity: 1,
      ignorePlurals: true,
      advancedSyntax: true,
      attributeCriteriaComputedByMinProximity: true,
      removeWordsIfNoResults: 'allOptional'
    }
  }
})