# Fumadocs (Framework Mode, React Router): ローカル Markdown (Sätteri)
URL: /ja/docs/react-router/integrations/content/satteri-local-md
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/integrations/content/satteri-local-md.ja.mdx

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

## はじめに [#introduction]

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

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

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

### 相違点 [#differences]

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

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

## セットアップ [#setup]

```package-install
@fumadocs/satteri shiki
```

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

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

```ts title="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();
}
```

### スキーマ [#schema]

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

```ts title="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({
    // ...
  }),
});
```

### コンパイラオプション [#compiler-options]

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

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

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

## 使い方 [#usage]

`getSource()` は[コンテンツローダー](/docs/headless/source-api)を返します。ページは [`@fumadocs/local-md`](/docs/react-router/integrations/content/local-md#usage) と同じ方法でレンダリングできます。ただし、インポート元は `@fumadocs/satteri/local-md` にしてください。

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

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

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

### クライアントレンダリング [#client-rendering]

`serialize()` は、コンパイル済みページを JSON として安全に扱えるペイロードとして返します。

これをローダーから返し、クライアントでレンダリングします。

```tsx
const serialized = (await page.data.load()).serialize();
```

```tsx title="components/content.tsx"
'use client';
import {
  rendererFromSerialized,
  type MarkdownRendererSerializedOptions,
} from '@fumadocs/satteri/local-md/client';

export function Content({ serialized }: { serialized: MarkdownRendererSerializedOptions }) {
  return rendererFromSerialized(serialized).renderSync().body;
}
```

### インクルード [#include]

[`<include>`](/docs/mdx/include) と `::include` ディレクティブは、デフォルトで有効になっています。

```mdx title="content/docs/page.mdx"
<include>../shared/note.md</include>
```

### ホットリロード [#hot-reload]

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

開発中は、Vite プラグインが Vite のファイルウォッチャーを通じてソースを無効化します。設定ファイルにプラグインを追加し、ソースを接続してください。

```ts tab="vite.config.ts"
import { defineConfig } from 'vite';
import { localContentPlugin } from '@fumadocs/satteri/local-md/dev/vite';

export default defineConfig({
  plugins: [localContentPlugin()],
});
```

```ts tab="lib/source.ts"
import { watchWithVite } from '@fumadocs/satteri/local-md/dev/vite';

if (import.meta.env.DEV) {
  watchWithVite(docs);
}
```

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

### 再検証を無効にする [#disable-revalidation]

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

```ts title="lib/source.ts"
import { loader } from 'fumadocs-core/source';

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