跳至內容
Fumadocs

createGraphQL()

GraphQL 伺服器實例。

GraphQL 伺服器

Fumadocs GraphQL 的主要設定。

請勿在瀏覽器環境中引用此設定。

input

要讀取的 GraphQL schema,可以是:

  • 由 SDL 檔案路徑/URL 組成的陣列。
  • schema ID -> 輸入的對應物件 (record) 。

物件形式的輸入可接受 SDL 檔案路徑/URL、SDL 文字、introspection 結果、GraphQLSchema 實例,以及回傳上述任一項的函式。

只有在此列出的 schema 才能載入,若傳入其他 ID 給 getSchema(),將會拋出錯誤。

import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
});

您可以傳入由多個 SDL 檔案組成的陣列,將它們合併為單一 schema,也支援型別擴充 (例如 extend type Query) 。

import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: {
    api: ['./base.graphql', './orders.graphql'],
  },
});

examples

取自 GraphQL 文件的範例 operation,可以是檔案路徑、URL 或 GraphQL 文字。

import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
  examples: ['./examples.graphql'],
});

陣列會套用到所有 schema。每個具名 operation 都會成為範例,顯示在它所選取的根欄位頁面上,並取代自動產生的範例:

examples.graphql
# 客戶的公開個人資料。
query CustomerProfile($id: ID! = "cus_42") {
  customer(id: $id) {
    id
    name
  }
}
範例來源
titleoperation 名稱,例如 CustomerProfile 會轉為 Customer Profile
descriptionoperation 的 """ 描述,或其正上方的 # 註解,支援 Markdown
variables變數的預設值 (不寫入查詢中) ,或為必要變數自動產生的值
response根據選取集自動產生

每個 operation 的名稱都必須唯一,且必須符合 schema,否則建置會失敗。

根欄位的引數必須是同名的變數,例如 customer(id: $id),互動測試區才能編輯這些引數。

disableCache

停用已載入之 schema 與範例的快取。適合在開發期間使用,因為這些內容經常變動。

import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
  disableCache: true,
});

只載入一次 schema

頁面會透過 props 接收完整的 schema,因此每次載入頁面、切換頁面及預先擷取時,都會重新傳送一次。若 schema 較大,建議不要將其傳入:

lib/graphql.ts
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  // ID 最終會出現在 URL 中,請確保只使用 URL 安全字元
  input: { store: './store.graphql' },
  includeSchema: false, 
});

TanStack Start 的路由載入器會同時在伺服器與瀏覽器上執行,因此您的文件路由不需要 loadSchema 也能載入 schema。只有在瀏覽器尚未取得 schema 時,才需要呼叫 server function:

src/routes/docs/$.tsx
import { createServerFn } from '@tanstack/react-start';
import { graphql } from '@/lib/graphql';

// 瀏覽器已載入的 schema
const schemas = new Map<string, string>();

const getSchema = createServerFn({ method: 'GET' })
  .validator((id: string) => id)
  .handler(async ({ data: id }) => (await graphql.getSchema(id)).sdl);

export const Route = createFileRoute('/docs/$')({
  component: Page,
  loader: async ({ params }) => {
    const data = await serverLoader({ data: params._splat?.split('/') ?? [] });
    if (data.type === 'graphql') {
      const { schema: id, payload } = data.props;
      payload.sdl = schemas.get(id) ?? (await getSchema({ data: id }));
    }
    return data;
  },
});

function Page() {
  const page = useFumadocsLoader(Route.useLoaderData());
  // 第一個頁面的 schema 也要記錄
  if (page.type === 'graphql' && typeof window !== 'undefined')
    schemas.set(page.props.schema, page.props.payload.sdl!);
  // ...
}
  • 瀏覽器會保留每個 schema,直到重新載入頁面為止。若啟用 disableCache,請保持 includeSchema 開啟。

產生頁面

staticSource() 和 dynamicSource() 會為您的 loader() 產生頁面,兩者的選項完全相同。

lib/source.ts
export const source = loader(
  {
    docs: docs.toFumadocsSource(),
    graphql: await graphql.staticSource({
      baseDir: 'graphql',
    }),
  },
  // ...
);

per

自訂每個頁面涵蓋的內容,預設為 item。

模式內容檔案路徑
item每個 operation,以及搭配 includeTypes 時的每個具名型別{name}.mdx
file單一 schema 的所有 operation,以及搭配 includeTypes 時其所有具名型別{file_name}.mdx
custom請參閱下方說明不適用

設為 custom 時,您可以傳入函式來完全自訂產生流程:

import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  per: 'custom',
  toPages(builder) {
    builder.create({
      type: 'operation',
      path: 'my-orders.mdx',
      info: { title: 'My Orders' },
      item: { kind: 'query', name: 'orders' },
    });
  },
});

groupBy

當 per: 'item' 時,可自訂產生的頁面要如何分組至資料夾,預設為 kind。

模式資料夾
kind依種類分組,例如 queries/、mutations/
none不建立資料夾

您也可以傳入一個函式,用來回傳項目的群組名稱:

import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  groupBy: (entry) => (entry.type === 'operation' ? 'operations' : 'types'),
});

includeOperations & includeTypes

篩選要產生文件的 operation (query/mutation/subscription 欄位) 與具名型別。

  • includeOperations:在 per: 'item' 時為每個 operation 各產生一個頁面,預設為 true。
  • includeTypes:具名型別。在 per: 'item' 時各自擁有獨立頁面,在 per: 'file' 時則放在該檔案的頁面中,預設為 false。無論採用哪種方式,operation 頁面都會顯示其使用的型別。

型別頁面會顯示該型別的使用位置,並提供連結至其他型別及各個 operation。

import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  // 略過訂閱操作
  includeOperations: (kind, field) => kind !== 'subscription',
  // 為型別產生文件,但排除內部型別
  includeTypes: (type) => !type.name.startsWith('Internal'),
});

name & slugify

自訂所產生頁面的檔案名稱。

GraphQL 名稱本身就可以安全地用於 URL,因此預設會保留原始名稱 (包含大小寫) 。

import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  per: 'item',
  name: (entry) => entry.item.name.toLowerCase(),
});

slugify 會將群組名稱 (預設也包含項目名稱) 轉換為適用於 URL 的路徑片段。

meta

產生 meta.json 檔案以自訂頁面樹,預設為停用。

folderStyle頁面樹
folder每個群組各為一個資料夾 (預設)
separator每個群組各以一個分隔符區隔,頁面列於其下
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  meta: { folderStyle: 'separator' },
});

供 LLM 使用的 Markdown

page.data.getText() 會以 Markdown 格式回傳頁面中的項目:包括 operation 及其簽章、引數、範例和所用型別的 SDL,以及具名型別及其 SDL 和使用位置。例如在 docsLlms 中:

import { llms } from 'fumadocs-core/source';
import { source } from '@/lib/source';

export const docsLlms = llms(source, {
  renderPage: async (page) => {
    if (page.type === 'graphql') {
      return `# ${page.data.title}\n\n${await page.data.getText('processed')}`;
    }

    // 以下為您原有的處理流程……
  },
});

載入器外掛

loaderPlugin() 會為頁面樹中的 GraphQL 頁面加上以下標示:

  • 為每個 operation 頁面加上 query/mutation/subscription 徽章。
  • 為已棄用的 operation 加上刪除線。
lib/source.ts
export const source = loader(
  // ...
  {
    baseUrl: '/docs',
    plugins: [graphql.loaderPlugin()],
  },
);

How is this guide?

最後更新於