ローカル HTML
ローカルの HTML ファイルを扱うコンテンツソースです。
はじめに
@fumadocs/local-html は、ローカルの HTML ファイル用のコンテンツソースです。バンドラーを使わない設計のため、完全にランタイムで動作します。
自分で執筆するのではなく、HTML として受け取るページを対象としています。たとえば、エクスポートしたスライドやレポート、他のツールの出力などです。各ファイルはそのままの形でレンダリングされるのではなく、ドキュメントのテーマに合わせて変換されます。
ローカル Markdown とは異なり、HTML は執筆に使うドキュメント形式ではなく、変換対象のデータとして扱われます。
制限事項
- スクリプトは除去されるため、元のページのインタラクティブな動作は再現されません。
- コンテンツ内で MDX コンポーネントは使用できませんが、レンダリング時に HTML タグをコンポーネントにマッピングできます。
- この処理は変換であり、サニタイズではありません。実行されるものは一切残りませんが、残ったマークアップはそのままレンダリングされ、そこで参照されているリソース (特に画像) は、ページを開いたすべてのユーザーの環境で読み込まれます。コンテンツディレクトリには、Markdown コンテンツなど、信頼できるファイルだけを置いてください。
セットアップ
パッケージをインストールします。
npm install @fumadocs/local-htmllocalHtml インスタンスを作成し、Fumadocs に接続します。
import { dynamicLoader } from 'fumadocs-core/source';
import { localHtml } from '@fumadocs/local-html';
const pages = localHtml({
dir: 'content/pages',
// オプション
});
const pagesLoader = dynamicLoader(pages.dynamicSource(), {
baseUrl: '/docs',
});
export async function getSource() {
return pagesLoader.get();
}pagesLoader.get() から返されるソースは、通常のコンテンツローダーのインスタンスです。
使い方
page.data.load() は、処理済みコンテンツのレンダラーを返します。
ページ内でレンダリングします。
import { getSource } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
export default async function Layout({ children }: LayoutProps<'/docs'>) {
const source = await getSource();
return <DocsLayout tree={source.getPageTree()}>{children}</DocsLayout>;
}render() にコンポーネントを渡すと、HTML タグをアンカー付きの見出しなどの独自コンポーネントに置き換えられます。
import { getMDXComponents } from '@/components/mdx';
const { body, toc } = await renderer.render(getMDXComponents());ページのメタデータ
各ページのタイトルと説明は、そのページの <head> から読み取られます。
<title>がページのタイトルになります。<meta name="description">が説明になります。
fumadocs: の meta タグを使用すると、表示されるコンテンツを変更せずにこれらを上書きできます (アイコンの設定も可能です) 。
<meta name="fumadocs:title" content="My Page" />
<meta name="fumadocs:description" content="A short description." />
<meta name="fumadocs:icon" content="SquareBookmark" />ドキュメント内のすべての <meta name>/content のペアは、page.data.metadata からも参照できます。
他のローカルソースと同様に、meta.json ファイルでページツリーをカスタマイズでき、その内容は metaSchema で検証されます。
コンテンツオプション
ページからはコンテンツ要素のみが抽出されます。唯一の <main> があればそれを、なければ唯一の <article> を使用し、どちらもない場合は <header> や <nav> などのページ装飾部分を取り除いた <body> にフォールバックします。テーマの本文用スタイル (prose) が適用されるよう、この要素の class 属性と style 属性は削除されます。また、目次と検索に利用できるよう、見出しには id が付与されます。
これらの動作はそれぞれ設定で変更できます。
import { localHtml } from '@fumadocs/local-html';
const pages = localHtml({
dir: 'content/pages',
// テーマに合わせて調整せず、元の class/style 属性を保持する
adaptStyles: false,
// 指定したタグもコンテンツから除外する
exclude: ['aside'],
// ページコンテンツを含む要素を選ぶカスタムロジック
selectContent: (root) => {
// hast 要素を返す(デフォルトの動作にする場合は undefined を返す)
},
});シンタックスハイライト
<pre><code> ブロックは Shiki によってハイライトされます。オプションは ローカル Markdown と同じものが使用されます。
const pages = localHtml({
dir: 'content/pages',
rehypeCodeOptions: {
themes: {
light: 'github-light',
dark: 'github-dark',
},
},
});言語は、ブロックの <code> 要素、またはそれを囲む <pre> 要素に付与された language-* クラスから判別されます。
<pre><code class="language-ts">const answer: number = 42;</code></pre>言語が指定されていないブロックは、プレーンテキストとして表示されます。シンタックスハイライトを無効にするには、rehypeCodeOptions: false を渡してください。
ホットリロード
@fumadocs/local-html はランタイムにファイルを読み込むため、デフォルトではファイルの変更を監視しません。
開発中は、同梱の開発サーバーをアプリと並行して実行してください。このサーバーは単一のプロセスでファイルを監視し、変更を WebSocket 経由でブロードキャストするため、Next.js が複数のワーカーで動作している場合でも機能します。
{
"scripts": {
"dev": "local-html dev -- next dev"
}
}ソースを開発サーバーに接続します。
import { watchWithDevServer } from '@fumadocs/local-html/dev/ws';
if (process.env.NODE_ENV === 'development') {
void watchWithDevServer(pages);
}このコマンドは URL を環境変数で公開するため、設定は不要です。サーバーを自分で起動する場合は URL を明示的に渡してください。ポートは -p で変更できます。
void watchWithDevServer(pages, { url: 'ws://127.0.0.1:8000/_fumadocs_local_md' });これでサーバー側のソースは無効化されますが、ブラウザ上のレンダリング済みページは Next.js によって保持されたままです。ページも更新されるように、ルートレイアウトで <DevClient /> をレンダリングしてください。
import { DevClient } from '@fumadocs/local-html/dev/react-client';
export function RootLayout({ children }) {
return (
<RootProvider>
<DevClient />
{children}
</RootProvider>
);
}独自のウォッチャーを使う場合は、ファイルの変更時に pages.invalidateFile(path) を呼び出してください。
再検証を無効にする
再検証が不要で、一度きりのスナップショットだけが必要な場合は、staticSource() を使用できます。
dynamicLoader() だけでなく、通常の loader() でも使用できます。
import { loader } from 'fumadocs-core/source';
import { localHtml } from '@fumadocs/local-html';
const pages = localHtml({
dir: 'content/pages',
});
export const source = loader(await pages.staticSource(), {
baseUrl: '/docs',
});How is this guide?
最終更新日
