跳至內容
Fumadocs

載入器 API

將內容來源轉換為統一的介面

它的用途是什麼?

loader() 提供一個介面,讓 Fumadocs 能與各種內容來源整合。

重要須知

  • loader() 是伺服器端 API,既不是建置時期的魔法,也不是可在瀏覽器中使用的 API。
  • 它採用記憶體內儲存,檔案由您的內容來源傳入。

使用方式

您可以搭配 Fumadocs MDX 等內容來源使用,詳情請參閱 source。

import { loader } from 'fumadocs-core/source';
import { docs } from 'collections/server';

export const source = loader({
  source: docs.toFumadocsSource(),
  baseUrl: '/docs',
});

URL

您可以覆寫基礎 URL,或指定一個函式來產生每個頁面的 URL。

import { loader } from 'fumadocs-core/source';

loader({
  baseUrl: '/docs',
  // 或者您也可以使用函式自訂
  url(slugs, locale) {
    if (locale) return '/' + [locale, 'docs', ...slugs].join('/');
    return '/' + ['docs', ...slugs].join('/');
  },
});

Slugs

定義自訂函式,用來根據頁面檔案產生 slug。

import { loader } from 'fumadocs-core/source';

loader({
  slugs(file, next) {
    console.log(file.path, file.data);
    // 您可以透過 `next()` 在預設 slug 的基礎上擴充
    if (file.path.startsWith('blog/')) return ['blog', ...next()];
    // 或回傳 `undefined` 以改用預設值
    return ['my', 'slug'];
  },
});

圖示

載入頁面與 meta 檔案中指定的 icon 屬性。

import { loader } from 'fumadocs-core/source';
import { icons } from 'lucide-react';
import { createElement } from 'react';

loader({
  icon(icon) {
    if (!icon) {
      // 您可以設定預設圖示
      return;
    }

    if (icon in icons) return createElement(icons[icon as keyof typeof icons]);
  },
});

I18n

請將 i18n 設定傳入載入器。

lib/source.ts
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';

export const source = loader({
  i18n, 
});

啟用 i18n 後,載入器會為每個語系產生一個頁面樹。

若某個頁面缺少翻譯,則會改用 fallbackLanguage 作為備用語系。

輸出

它會輸出一個內容載入器實例。

取得頁面

依據 slugs 取得頁面。

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

source.getPage(['slug', 'of', 'page']);

// 使用 i18n 時
source.getPage(['slug', 'of', 'page'], 'locale');

自訂 Props

您可以將 props 傳入頁面內容,例如讀者所選的版本。內容會透過 props 讀取這些值,用法與路徑參數相同:

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

const page = source.getPage(['slug', 'of', 'page'], {
  props: { version: 'v2' },
  // 使用 i18n 時
  language: 'locale',
});

頁面資料 (包括內容與目錄) 是根據這些 props 產生的。MDX 元件也屬於 props;若希望處理後的 Markdown 能算繪出您的元件,請將它們傳入:

import { getMDXComponents } from '@/components/mdx';

const page = source.getPage(['slug', 'of', 'page'], {
  props: { components: getMDXComponents() },
});
const markdown = await page.data.getText('processed');

小提醒

搜尋與 LLM 路由是透過 getPages() 讀取頁面,而這些頁面只帶有路徑參數。若要讓搜尋或 LLM 看到某個變體,該變體就必須是路徑參數。

取得頁面

取得指定語系下可用的頁面清單。

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

// 取得所有語系的頁面
source.getPages();

// 取得特定語系的頁面
source.getPages('locale');

頁面樹

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

// 未使用 i18n
source.getPageTree();

// 使用 i18n
source.getPageTree('locale');

從節點取得

頁面樹的節點會保留指向其原始檔案路徑的參照。 您可以透過樹狀節點找到對應的原始頁面或 meta 檔案。

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

source.getNodePage(pageNode);
source.getNodeMeta(folderNode);

參數

產生每個頁面的路徑參數,以便預先算繪頁面。 產生的參數名稱為 slug: string[] 與 lang: string (僅限 i18n) 。

app/docs/[[...slug]]/page.tsx
import { source } from '@/lib/source';

export function generateStaticParams() {
  return source.generateParams();
}

React Router 與 TanStack Start 是依 URL 進行預先算繪,因此請改為列出 source.getPages() 各頁面的 url。

語言項目

取得所有可用的語言及其對應頁面。

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

// 語言 -> 頁面
const entries = source.getLanguages();

用戶端 API

載入器 API 最適合在 RSC 環境中使用,因為 RSC 允許跨越伺服器與用戶端的邊界傳遞 JSX 節點。

在非 RSC 環境中,載入器 API 則提供一個輕量的序列化層。

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

// 在此傳遞 loader 資料
async function loader() {
  const pageTree = source.getPageTree();

  return {
    pageTree: await source.serializePageTree(pageTree),
  };
}

Dynamic 載入器

dynamicLoader() 可為內容來源提供額外的重新驗證功能,請搭配 Dynamic 來源使用。

import { dynamicLoader } from 'fumadocs-core/source';
import { createMySource } from './my-source';

const source = dynamicLoader(createMySource(), {
  baseUrl: '/docs',
});

export async function getSource() {
  return source.get();
}

呼叫 await source.get() 時,會回傳一個一般的內容載入器物件:

const docs = await getSource();

const page = docs.getPage(['...']);

重新驗證

載入器會快取 Dynamic 來源。

如果您的來源會隨時間變動,請呼叫 invalidate() 清除快取,或呼叫 revalidate() 更新快取:

source.invalidate();

await source.revalidate();

若採用多來源的設定,您可以針對特定來源進行失效 (invalidate) 或重新驗證 (revalidate) :

source.invalidate('docs');

await source.revalidate('docs');

How is this guide?

最後更新於