close
  • English
  • @rspress/plugin-algolia new

    Based on docsearch, this plugin replaces Rspress's built-in search with algolia.

    Installation

    npm
    yarn
    pnpm
    bun
    deno
    npm add @rspress/plugin-algolia -D

    Usage

    First, add the following configuration to rspress.config.ts:

    // rspress.config.ts
    import path from 'path';
    import { defineConfig } from '@rspress/core';
    import { pluginAlgolia } from '@rspress/plugin-algolia';
    
    export default defineConfig({
      plugins: [pluginAlgolia()],
    });

    Then override the Search component with an algolia-supported search box via Custom Theme.

    // theme/index.tsx
    import { Search as PluginAlgoliaSearch } from '@rspress/plugin-algolia/runtime';
    
    const Search = () => {
      return (
        <PluginAlgoliaSearch
          docSearchProps={{
            appId: 'R2IYF7ETH7', // Replace with your own Algolia appId
            apiKey: '599cec31baffa4868cae4e79f180729b', // Replace with your own Algolia apiKey
            indexName: 'docsearch', // Replace with your own Algolia indexName
          }}
        />
      );
    };
    export { Search };
    export * from '@rspress/core/theme-original';

    Configuration

    The plugin accepts an options object with the following type:

    interface Options {
      verificationContent?: string;
    }

    verificationContent

    • Type: string | undefined
    • Default: undefined

    Used for meta tag verification when creating algolia crawler. Format: <meta name="algolia-site-verification" content="YOUR_VERIFICATION_CONTENT" />. Refer to Create a new crawler - algolia

    SearchProps

    The SearchProps type from @rspress/plugin-algolia/runtime is as follows:

    import type { DocSearchProps } from '@docsearch/react';
    
    type Locales = Record<
      string,
      { translations: DocSearchProps['translations']; placeholder: string }
    >;
    type SearchProps = {
      /**
       * @link https://docsearch.algolia.com/docs/api
       */
      docSearchProps?: DocSearchProps;
      locales?: Locales;
    };

    docSearchProps

    • Type: import('@docsearch/react').DocSearchProps
    • Default: undefined

    docSearchProps will be directly passed to the <DocSearch /> component in @docsearch/react. For specific types, please refer to docsearch documentation.

    locales

    • Type:
    type Locales = Record<
      string,
      { translations: DocSearchProps['translations']; placeholder: string }
    >;
    • Default: {}

    For customizing translated text in different languages, Rspress provides the following translated text, which can be imported through import.

    import type { DocSearchProps } from '@docsearch/react';
    
    export type Locales = Record<
      string,
      { translations: DocSearchProps['translations']; placeholder: string }
    >;
    
    // cspell:disable
    export const ZH_LOCALES: Locales = {
      zh: {
        placeholder: '搜索文档',
        translations: {
          button: {
            buttonText: '搜索',
            buttonAriaLabel: '搜索',
          },
          modal: {
            searchBox: {
              clearButtonTitle: '清除查询条件',
              clearButtonAriaLabel: '清除查询条件',
              closeButtonText: '取消',
              closeButtonAriaLabel: '取消',
            },
            startScreen: {
              recentSearchesTitle: '搜索历史',
              noRecentSearchesText: '没有搜索历史',
              saveRecentSearchButtonTitle: '保存至搜索历史',
              removeRecentSearchButtonTitle: '从搜索历史中移除',
              favoriteSearchesTitle: '收藏',
              removeFavoriteSearchButtonTitle: '从收藏中移除',
            },
            errorScreen: {
              titleText: '无法获取结果',
              helpText: '你可能需要检查你的网络连接',
            },
            footer: {
              selectText: '选择',
              navigateText: '切换',
              closeText: '关闭',
              poweredByText: '搜索提供者',
            },
            noResultsScreen: {
              noResultsText: '无法找到相关结果',
              suggestedQueryText: '你可以尝试查询',
              reportMissingResultsText: '你认为该查询应该有结果?',
              reportMissingResultsLinkText: '点击反馈',
            },
          },
        },
      },
    } as const;
    
    export const RU_LOCALES: Locales = {
      ru: {
        placeholder: 'Поиск в документации',
        translations: {
          button: {
            buttonText: 'Поиск',
            buttonAriaLabel: 'Поиск',
          },
          modal: {
            searchBox: {
              clearButtonTitle: 'Очистить поиск',
              clearButtonAriaLabel: 'Очистить поиск',
              closeButtonText: 'Закрыть',
              closeButtonAriaLabel: 'Закрыть',
            },
            startScreen: {
              recentSearchesTitle: 'История поиска',
              noRecentSearchesText: 'Нет истории поиска',
              saveRecentSearchButtonTitle: 'Сохранить в истории поиска',
              removeRecentSearchButtonTitle: 'Удалить из истории поиска',
              favoriteSearchesTitle: 'Избранное',
              removeFavoriteSearchButtonTitle: 'Удалить из избранного',
            },
            errorScreen: {
              titleText: 'Невозможно получить результаты',
              helpText: 'Проверьте подключение к Интернету',
            },
            footer: {
              selectText: 'выбрать',
              navigateText: 'перейти',
              closeText: 'закрыть',
              poweredByText: 'поиск от',
            },
            noResultsScreen: {
              noResultsText: 'Ничего не найдено',
              suggestedQueryText: 'Попробуйте изменить запрос',
              reportMissingResultsText: 'Считаете, что результаты должны быть?',
              reportMissingResultsLinkText: 'Сообщите об этом',
            },
          },
        },
      },
    } as const;
    // cspell:enable
    

    Rspress provides Chinese translation by default, and you can customize translated text in different languages ​​through locales.

    • Example:
    import { Search as PluginAlgoliaSearch, ZH_LOCALES } from '@rspress/plugin-algolia/runtime';
    
    <PluginAlgoliaSearch locales={ZH_LOCALES} />
    // or
    <PluginAlgoliaSearch
      locales={{
        en: {
          placeholder: 'Search Documentation',
          translations: {
            button: {
              buttonText: 'Search',
              buttonAriaLabel: 'Search',
            }
          }
        },
        ...ZH_LOCALES,
      }}
    />

    Algolia crawler config

    Here is an example config based on what this site uses:

    new Crawler({
      appId: 'YOUR_APP_ID',
      apiKey: 'YOUR_API_KEY',
      rateLimit: 8,
      maxDepth: 10,
      startUrls: ['https://rspress.rs'],
      sitemaps: ['https://rspress.rs/sitemap.xml'],
      discoveryPatterns: ['https://rspress.rs/**'],
      actions: [
        {
          indexName: 'doc_search_rspress_v2_pages',
          pathsToMatch: ['https://rspress.rs/**'],
          recordExtractor: ({ $, helpers }) => {
            // Remove badge elements to prevent their text from being indexed
            $('.rp-badge').remove();
            // Remove non-doc elements (e.g. version switcher) from h1 to keep title text clean
            $('.rspress-doc h1 .rp-not-doc').remove();
    
            const $activeNavItem = $('.rp-nav-menu__item.rp-nav-menu__item--active')
              .first()
              .clone();
    
            const lvl0 = $activeNavItem.text().trim() || 'Documentation';
    
            return helpers.docsearch({
              recordProps: {
                lvl0: {
                  selectors: '',
                  defaultValue: lvl0,
                },
                lvl1: '.rspress-doc h1',
                lvl2: '.rspress-doc h2',
                lvl3: '.rspress-doc h3',
                lvl4: '.rspress-doc h4',
                lvl5: '.rspress-doc h5',
                lvl6: '.rspress-doc pre > code', // if you want to search code blocks, add this line
                content: '.rspress-doc p, .rspress-doc li',
              },
              indexHeadings: true,
              aggregateContent: true,
              recordVersion: 'v3',
            });
          },
        },
      ],
      initialIndexSettings: {
        doc_search_rspress_v2_pages: {
          attributesForFaceting: ['type', 'lang'],
          attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
          attributesToHighlight: ['hierarchy', 'content'],
          attributesToSnippet: ['content:10'],
          camelCaseAttributes: ['hierarchy', 'content'],
          searchableAttributes: [
            'unordered(hierarchy.lvl0)',
            'unordered(hierarchy.lvl1)',
            'unordered(hierarchy.lvl2)',
            'unordered(hierarchy.lvl3)',
            'unordered(hierarchy.lvl4)',
            'unordered(hierarchy.lvl5)',
            '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',
          ],
          minWordSizefor1Typo: 3,
          minWordSizefor2Typos: 7,
          allowTyposOnNumericTokens: false,
          minProximity: 1,
          ignorePlurals: true,
          advancedSyntax: true,
          attributeCriteriaComputedByMinProximity: true,
          removeWordsIfNoResults: 'allOptional',
        },
      },
      schedule: 'on tuesday',
      indexPrefix: 'rspress-v2-crawler-',
    });

    Distinguish search results based on i18n

    You can achieve internationalized search results by combining Runtime API with docSearchProps.

    Here's an example using docSearchProps.searchParameters:

    // theme/index.tsx
    import { useLang } from '@rspress/core/runtime';
    import { Search as PluginAlgoliaSearch } from '@rspress/plugin-algolia/runtime';
    
    const Search = () => {
      const lang = useLang();
      return (
        <PluginAlgoliaSearch
          docSearchProps={{
            appId: 'R2IYF7ETH7',
            apiKey: '599cec31baffa4868cae4e79f180729b',
            indexName: 'docsearch',
            searchParameters: {
              facetFilters: [`lang:${lang}`],
            },
          }}
        />
      );
    };
    export { Search };
    export * from '@rspress/core/theme-original';