本機 HTML
適用於本機 HTML 檔案的內容來源。
簡介
@fumadocs/local-html 是用於本機 HTML 檔案的內容來源。它在設計上就不需要打包,因此能完全在執行階段運作。
它專為以 HTML 形式取得、而非由您自行撰寫的頁面而設計,例如匯出的簡報、報告,以及其他工具產生的輸出。每個檔案都會依照您的文件主題進行調整,而不是照原樣算繪。
與本機 Markdown 不同,HTML 在這裡被視為需要調整的資料,而非用來撰寫內容的文件格式。
限制
- 指令碼會被移除,原始頁面的互動行為不會保留。
- 內容中無法使用 MDX 元件,但您可以在算繪階段將 HTML 標籤對應到元件。
- 處理過程只是轉換,而非淨化 (sanitization) 。所有可執行的內容都會被移除,但其餘標記會原封不動地算繪,而其中引用的資源 (尤其是圖片) 會在每位使用者開啟頁面時被載入。請確保內容目錄中只放您信任的檔案,例如您自己的 Markdown 內容。
設定
請安裝此套件:
npm install @fumadocs/local-html建立 localHtml 實例,並將它串接到 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 type { Route } from './+types/docs';
import { useMemo } from 'react';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
import { useFumadocsLoader } from 'fumadocs-core/source/client';
import { rendererFromSerialized } from '@fumadocs/local-html/client';
import { getSource } from '@/lib/source';
export async function loader({ params }: Route.LoaderArgs) {
const source = await getSource();
const page = source.getPage(params['*'].split('/').filter((v) => v.length > 0));
if (!page) throw new Response('Not found', { status: 404 });
const renderer = await page.data.load();
return {
title: page.data.title,
description: page.data.description,
// 語法樹,於用戶端算繪
render: renderer.serialize(),
pageTree: await source.serializePageTree(source.getPageTree()),
};
}
export default function Page({ loaderData }: Route.ComponentProps) {
const { title, description, render, pageTree } = useFumadocsLoader(loaderData);
const renderer = useMemo(() => rendererFromSerialized(render), [render]);
const { body, toc } = renderer.renderSync();
return (
<DocsLayout tree={pageTree}>
<DocsPage toc={toc}>
<DocsTitle>{title}</DocsTitle>
<DocsDescription>{description}</DocsDescription>
<DocsBody>{body}</DocsBody>
</DocsPage>
</DocsLayout>
);
}將元件傳入 renderSync(),即可將 HTML 標籤對應到您自訂的元件,例如帶有錨點的標題:
import { getMDXComponents } from '@/components/mdx';
const { body, toc } = renderer.renderSync(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>,若都沒有則退回使用 <body>,並移除 <header> 與 <nav> 等頁面外框元素。該元素的 class 與 style 屬性會被移除,改由您主題的 prose 樣式接手;其中的標題則會加上 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',
},
},
});語言會從程式碼區塊的 language-* class 讀取,該 class 可位於 <code> 或其外層的 <pre> 上:
<pre><code class="language-ts">const answer: number = 42;</code></pre>未指定語言的區塊會以純文字呈現。若要停用語法突顯,請傳入 rehypeCodeOptions: false。
熱重載
@fumadocs/local-html 會在執行階段讀取檔案,因此預設不會監看這些檔案。
開發期間,Vite 外掛會透過 Vite 的檔案監看器讓來源失效,不需要額外的行程或連接埠。請將外掛加入您的設定,並連接來源:
import { defineConfig } from 'vite';
import { localContentPlugin } from '@fumadocs/local-html/dev/vite';
export default defineConfig({
plugins: [localContentPlugin()],
});若想改用您自己的監看器,請在檔案變更時呼叫 pages.invalidateFile(path)。
停用重新驗證
若您只需要一次性的快照,不需要重新驗證,可以使用 staticSource()。
它可搭配一般的 loader() 使用,不必侷限於 dynamicLoader():
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?
最後更新於
