跳至內容
Fumadocs

Typesense 搜尋

將 Typesense 搜尋整合至 Fumadocs

此整合由社群維護。

設定

安裝相依套件

npm install typesense typesense-fumadocs-adapter

啟動 Typesense 伺服器

您可以自行架設 Typesense 伺服器,或使用其雲端服務。請依照官方的入門指南設定伺服器,並將認證資訊儲存在 .env.local 中 (在 Vite 框架中請將 NEXT_PUBLIC_ 改為 VITE_,在 Astro 中則改為 PUBLIC_) :

NEXT_PUBLIC_TYPESENSE_URL="server URL"
NEXT_PUBLIC_TYPESENSE_SEARCH_KEY="search-only API key"
TYPESENSE_API_KEY="API key with write access"

同步資料集

透過預先算繪的 static.json 路由匯出搜尋索引,並在每次建置後以指令碼將其同步至 Typesense:

app/static.json/route.ts
import { source } from '@/lib/source';
import type { DocumentRecord } from 'typesense-fumadocs-adapter';

async function getDocuments() {
  const documents: DocumentRecord[] = [];
  for (const page of source.getPages()) {
    documents.push({
      _id: page.url,
      structured: page.data.structuredData,
      url: page.url,
      title: page.data.title,
      description: page.data.description,
      locale: page.locale,
    });
  }
  return documents;
}

export const revalidate = false;

export async function GET() {
  return Response.json(await getDocuments());
}
scripts/sync-content.ts
import * as fs from 'node:fs/promises';
import { type DocumentRecord, sync } from 'typesense-fumadocs-adapter';
import { Client } from 'typesense';

// Next.js writes it under `route-cache` when built with an adapter, like on Vercel
const [file] = await Array.fromAsync(fs.glob('.next/server/{app,route-cache/*/*/$}/static.json.body'));
const records = JSON.parse(await fs.readFile(file, 'utf-8')) as DocumentRecord[];

const client = new Client({
  nodes: [{ url: process.env.NEXT_PUBLIC_TYPESENSE_URL! }],
  apiKey: process.env.TYPESENSE_API_KEY!,
  connectionTimeoutSeconds: 60 * 15,
});

await sync(client, {
  typesenseCollectionName: 'docs',
  documents: records,
});

console.log(`search updated: ${records.length} records`);
package.json
{
  "scripts": {
    "build": "next build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
  }
}

build 指令碼會在每次建置時執行同步,因此請在您的部署平台上設定相同的變數。

搜尋 UI

若要實作搜尋 UI,您可以:

  • 使用 Fumadocs UI 搜尋對話方塊。

  • 使用 Typesense 搜尋用戶端 hook,自行打造搜尋 UI。

    import { Client } from 'typesense';
    import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client';
    
    const client = new Client({
      nodes: [{ url: 'YOUR_TYPESENSE_SERVER_URL' }],
      apiKey: 'YOUR_TYPESENSE_SEARCH_ONLY_API_KEY',
    });
    
    const { search, setSearch, query } = useTypesenseSearch({
      typesenseCollectionName: 'docs',
      client,
    });

選項

標籤篩選

若要設定標籤篩選,請在 static.json 路由中為各份文件加上 tag 值:

documents.push({
  // 其他欄位……
  tag: '<your value>',
});

接著更新您的搜尋用戶端:

  • Fumadocs UI:在搜尋 UI 中啟用標籤篩選。

  • 搜尋用戶端:您可以依下列方式加入標籤篩選:

    import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client';
    const { search, setSearch, query } = useTypesenseSearch({
      tag: '<your tag value>',
      // ...
    });

國際化 (i18n)

文件會包含所屬頁面的 locale,請將 locale 傳入搜尋用戶端:

import { useI18n } from 'fumadocs-ui/contexts/i18n';
import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client';

const { locale } = useI18n();
const { search, setSearch, query } = useTypesenseSearch({
  locale,
  // 其他欄位...
});

在底層,Typesense 會為每個語系分別建立集合,集合名稱會加上 _{locale} 後綴 (例如 docs_en、docs_fr) 。

How is this guide?

最後更新於