コンテンツへスキップ
Fumadocs

ローカル Markdown (Sätteri)

ローカルの Markdown コンテンツを Sätteri でコンパイルするコンテンツソースです。

はじめに

@fumadocs/satteri/local-md は、ローカルの Markdown/MDX ファイル向けのコンテンツソースです。unified/remark パイプラインではなく、Sätteri でコンパイルを行います。

@fumadocs/local-md と同じ API を備え、同じくバンドル不要なため、型生成やバンドラーのステップを挟まずにランタイムで動作します。

Sätteri コンパイラとそのプラグインモデル、Fumadocs の Sätteri プリセットを使いたい場合に利用してください。

相違点

  • コンパイル結果は常に JavaScript になるため、仮想 JavaScript エンジンのオプションはありません。レンダリングにはネイティブエンジンを使用します。
  • プラグインは remark/rehype プラグインではなく Sätteri プラグインで、satteriOptions で設定します。

信頼できない Markdown/MDX ファイルを dir に置かないでください。JavaScript として実行されたり、サーバー側のファイルを参照したりするおそれがあります。

セットアップ

npm install @fumadocs/satteri shiki

shiki をインストールしているのは、バンドラーで外部化する必要があるためです。

localMd インスタンスを作成し、Fumadocs に接続します。

lib/source.ts
import { dynamicLoader } from 'fumadocs-core/source';
import { localMd } from '@fumadocs/satteri/local-md';

const docs = localMd({
  dir: 'content/docs',
});

const docsLoader = dynamicLoader(docs.dynamicSource(), {
  baseUrl: '/docs',
});

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

スキーマ

バリデーション用のスキーマをカスタマイズするには、frontmatterSchema と metaSchema を渡します。

lib/source.ts
import { localMd } from '@fumadocs/satteri/local-md';
import { pageSchema, metaSchema } from 'fumadocs-core/source/schema';

const docs = localMd({
  dir: 'content/docs',
  frontmatterSchema: pageSchema.extend({
    // ...
  }),
  metaSchema: metaSchema.extend({
    // ...
  }),
});

コンパイラオプション

satteriOptions は Fumadocs Sätteri プリセットを経由して渡されるため、プラグインとそのオプションは Fumadocs MDX と同じ方法で設定できます。

lib/source.ts
const docs = localMd({
  dir: 'content/docs',
  satteriOptions: {
    rehypeCodeOptions: {
      themes: { light: 'github-light', dark: 'github-dark' },
    },
    mdastPlugins: [myPlugin()],
  },
});

オプションを遅延して構築するには、関数を渡します。

使い方

getSource() はコンテンツローダーを返します。ページは @fumadocs/local-md と同じ方法でレンダリングできます。ただし、インポート元は @fumadocs/satteri/local-md にしてください。

各ページには load() があり、ページをコンパイルしてレンダラーを返します。

const page = source.getPage(slugs);
const { body, toc } = await (await page.data.load()).render();

レンダラーには structuredData と exports もあり、ドキュメントやそのプラグインがエクスポートした値を参照できます。

インクルード

<include> と ::include ディレクティブは、デフォルトで有効になっています。

content/docs/page.mdx
<include>../shared/note.md</include>

ホットリロード

ソースは実行時にファイルを読み込むため、デフォルトではファイルの監視は行われません。

開発中は、アプリと並行して @fumadocs/local-md の開発サーバーを実行します。

package.json
{
  "scripts": {
    "dev": "local-md dev -- next dev"
  }
}

ソースを開発サーバーに接続します。

lib/source.ts
import { watchWithDevServer } from '@fumadocs/satteri/local-md/dev/ws';

if (process.env.NODE_ENV === 'development') {
  void watchWithDevServer(docs);
}

これによりサーバー側のソースは無効化されますが、ブラウザ上のレンダリング済みページは Next.js によって保持されたままです。ページも更新されるように、ルートレイアウトで <DevClient /> をレンダリングしてください。

app/layout.tsx
import { DevClient } from '@fumadocs/satteri/local-md/dev/react-client';

export function RootLayout({ children }) {
  return (
    <RootProvider>
      <DevClient />
      {children}
    </RootProvider>
  );
}

インクルードされたファイルも監視対象です。独自のウォッチャーを組み込む場合は、docs.dir と docs.onDependency() に渡されたファイルを監視し、ファイルが変更されたときに docs.invalidateFile(path) を呼び出してください。

再検証を無効にする

一度きりのスナップショットだけが必要な場合は、staticSource() を使用してください。そうすれば、通常の loader() で動作します。

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

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

How is this guide?

最終更新日