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: support for searching code blocks #1797

Merged
merged 2 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions e2e/fixtures/search-code-blocks/doc/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Hello world

```js
console.log('hello from code block');
```
16 changes: 16 additions & 0 deletions e2e/fixtures/search-code-blocks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@rspress-fixture/rspress-search-code-blocks",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "rspress build",
"dev": "rspress dev",
"preview": "rspress preview"
},
"dependencies": {
"rspress": "workspace:*"
},
"devDependencies": {
"@types/node": "^18.11.17"
}
}
9 changes: 9 additions & 0 deletions e2e/fixtures/search-code-blocks/rspress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as path from 'node:path';
import { defineConfig } from 'rspress/config';

export default defineConfig({
root: path.join(__dirname, 'doc'),
search: {
codeBlocks: true,
},
});
1 change: 1 addition & 0 deletions e2e/fixtures/search-code-blocks/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
31 changes: 31 additions & 0 deletions e2e/tests/search-code-blocks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import path from 'node:path';
import { expect, test } from '@playwright/test';
import { getPort, killProcess, runDevCommand } from '../utils/runCommands';
import { searchInPage } from '../utils/search';

const fixtureDir = path.resolve(__dirname, '../fixtures');

test.describe('search code blocks test', async () => {
let appPort;
let app;

test.beforeAll(async () => {
const appDir = path.join(fixtureDir, 'search-code-blocks');
appPort = await getPort();
app = await runDevCommand(appDir, appPort);
});

test.afterAll(async () => {
if (app) {
await killProcess(app);
}
});

test('search index should include content of code blocks', async ({
page,
}) => {
await page.goto(`http://localhost:${appPort}`);
const suggestItems = await searchInPage(page, 'hello from code block');
expect(suggestItems.length).toBe(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function extractPageData(
root: string,
routeService: RouteService,
highlighterLangs: Set<string>,
searchCodeBlocks: boolean,
): Promise<PageIndexInfo[]> {
const pageData = await Promise.all(
routeService
Expand Down Expand Up @@ -108,7 +109,7 @@ export async function extractPageData(
{
// Skip code blocks
selector: 'pre > code',
format: 'skip',
format: searchCodeBlocks ? 'block' : 'skip',
},
...['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].map(tag => ({
selector: tag,
Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/node/runtimeModule/siteData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,24 @@ export async function siteDataVMPlugin(context: FactoryContext) {

const highlightLanguages: Set<string> = new Set();
const replaceRules = userConfig?.replaceRules || [];

const searchConfig = userConfig?.search || {};

// If the dev server restart when config file, we will reuse the siteData instead of extracting the siteData from source files again.
const domain =
userConfig?.search && userConfig?.search?.mode === 'remote'
? (userConfig?.search.domain ?? '')
: '';
searchConfig?.mode === 'remote' ? (searchConfig.domain ?? '') : '';

const searchCodeBlocks =
'codeBlocks' in searchConfig ? searchConfig.codeBlocks : false;

const pages = await extractPageData(
replaceRules,
alias,
domain,
userDocRoot,
routeService,
highlightLanguages,
searchCodeBlocks,
);
// modify page index by plugins
await pluginDriver.modifySearchIndexData(pages);
Expand Down
33 changes: 32 additions & 1 deletion packages/document/docs/en/api/config/config-basic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,21 @@ export default defineConfig({

## search

- Type: `{ searchHooks: string; versioned: boolean; }`
- Type:

```ts
type SearchOptions = {
searchHooks?: string;
versioned?: boolean;
codeBlocks?: boolean;
};
```

### searchHooks

- Type: `string`
- Default: `undefined`

You can add search runtime hooks logic through the `searchHooks` parameter, for example:

```ts title="rspress.config.ts"
Expand All @@ -282,6 +293,9 @@ For specific hook logic, you can read [Customize Search Functions](/guide/advanc

### versioned

- Type: `boolean`
- Default: `false`

If you are using `multiVersion`, the `versioned` parameter allows you to create a separate search index for each version of your documentation.
When enabled, the search will only query the index corresponding to the currently selected version.

Expand All @@ -295,6 +309,23 @@ export default defineConfig({
});
```

### codeBlocks

- Type: `boolean`
- Default: `false`

If enabled, the search index will include code block content, which allows users to search code blocks.

```ts title="rspress.config.ts"
import { defineConfig } from 'rspress/config';

export default defineConfig({
search: {
codeBlocks: true,
},
});
```

## globalUIComponents

- Type: `(string | [string, object])[]`
Expand Down
33 changes: 32 additions & 1 deletion packages/document/docs/zh/api/config/config-basic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,21 @@ export default defineConfig({

## search

- Type: `{ searchHooks: string; versioned: boolean; }`
- Type:

```ts
type SearchOptions = {
searchHooks?: string;
versioned?: boolean;
codeBlocks?: boolean;
};
```

### searchHooks

- Type: `string`
- Default: `undefined`

你可以通过 `searchHooks` 参数来增加搜索运行时钩子逻辑,比如:

```ts title="rspress.config.ts"
Expand All @@ -282,6 +293,9 @@ export default defineConfig({

### versioned

- Type: `boolean`
- Default: `false`

如果你配置了 `multiVersion`,可以使用 `versioned` 参数为文档的每个版本创建单独的搜索索引。开启该选项后,搜索将仅会查询当前所选版本对应的索引。

```ts title="rspress.config.ts"
Expand All @@ -294,6 +308,23 @@ export default defineConfig({
});
```

### codeBlocks

- Type: `boolean`
- Default: `false`

开启后,搜索的索引将包含代码块的内容,从而允许用户搜索代码块。

```ts title="rspress.config.ts"
import { defineConfig } from 'rspress/config';

export default defineConfig({
search: {
codeBlocks: true,
},
});
```

## globalUIComponents

- Type: `(string | object)[]`
Expand Down
3 changes: 3 additions & 0 deletions packages/document/rspress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export default defineConfig({
}),
],
},
search: {
codeBlocks: true,
},
route: {
cleanUrls: true,
exclude: ['**/fragments/**'],
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@ export type LocalSearchOptions = SearchHooks & {
* Whether to generate separate search index for each version
*/
versioned?: boolean;
/**
* If enabled, the search index will include code block content, which allows users to search code blocks.
* @default false
*/
codeBlocks?: boolean;
};

export type RemoteSearchIndexInfo =
Expand Down
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.