Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin-algolia): add plugin-algolia and optimize some DX on customizing Search #1909

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

SoonIter
Copy link
Member

@SoonIter SoonIter commented Mar 4, 2025

@rspress/plugin-algolia

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

Installation

npm add @rspress/plugin-algolia -D

Usage

First, add the following configuration to your config file:

// rspress.config.ts
import path from 'path';
import { defineConfig } from 'rspress';
import { pluginAlgolia } from '@rspress/plugin-algolia';

export default defineConfig({
  plugins: [pluginAlgolia()],
  search: false, // Disable the default search index generation
});

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/theme';

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.

export const ZH_LOCALES: Locales = {
  zh: {
    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: '点击反馈',
        },
      },
    },
  },
} as const;

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.dev'],
  sitemaps: ['https://rspress.dev/sitemap.xml'],
  discoveryPatterns: ['https://rspress.dev/**'],
  actions: [
    {
      indexName: 'doc_search_rspress_pages',
      pathsToMatch: ['https://rspress.dev/**'],
      recordExtractor: ({ $, helpers }) => {
        return helpers.docsearch({
          recordProps: {
            lvl0: {
              selectors: '',
              defaultValue: 'Documentation',
            },
            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_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',
    },
  },
});

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/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: [`language:${lang}`],
        },
      }}
    />
  );
};
export { Search };
export * from 'rspress/theme';

Copy link

netlify bot commented Mar 4, 2025

Deploy Preview for aquamarine-blini-95325f ready!

Name Link
🔨 Latest commit 21e3435
🔍 Latest deploy log https://app.netlify.com/sites/aquamarine-blini-95325f/deploys/67d00a85a5702600080dc425
😎 Deploy Preview https://deploy-preview-1909--aquamarine-blini-95325f.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 91 (🟢 up 4 from production)
Accessibility: 97 (no change from production)
Best Practices: 92 (no change from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

@SoonIter SoonIter changed the base branch from 1.x to main March 4, 2025 12:35
Copy link

netlify bot commented Mar 4, 2025

Deploy Preview for rspress-v2 ready!

Name Link
🔨 Latest commit 21e3435
🔍 Latest deploy log https://app.netlify.com/sites/rspress-v2/deploys/67d00a85cedd4c00088dcf7b
😎 Deploy Preview https://deploy-preview-1909--rspress-v2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@SoonIter SoonIter force-pushed the algolia branch 2 times, most recently from c414074 to 2032884 Compare March 6, 2025 06:46
@SoonIter SoonIter changed the title feat(plugin-algolia): add plugin-algolia feat(plugin-algolia): add plugin-algolia and optimize some DX on customizing Search Mar 6, 2025
@SoonIter
Copy link
Member Author

SoonIter commented Mar 7, 2025

ScreenShot

image


export default defineConfig({
plugins: [pluginAlgolia()],
search: false, // Disable the default search index generation
Copy link
Contributor

@Timeless0911 Timeless0911 Mar 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we disable it in plugin logic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants