Skip to content

@ox-content/vite-plugin#

View Markdown

Environment API 対応の、Ox Content 向けベース Vite プラグインです。

インストール#

vp install @ox-content/vite-plugin

@ox-content/vite-plugin はすでに @ox-content/napi に依存するので、Vite プラグインを使うときは別途 vp install @ox-content/napi は不要です。

基本的な使い方#

// vite.config.ts
import { defineConfig } from "vite";
import { oxContent } from "@ox-content/vite-plugin";

export default defineConfig({
  plugins: [
    oxContent({
      srcDir: "docs",
    }),
  ],
});

VitePress からの移行#

すでに VitePress サイトがあるときは、編集可能な ox-content オプションオブジェクトを生成します。

vpx oxct migrate vitepress .vitepress/config.ts \
  --src-dir docs \
  --out-dir dist \
  --out ox-content.config.ts

CLI は @ox-content/vite-plugin が入れる oxct バイナリから実行します。

vpx oxct migrate vitepress .vitepress/config.ts --out ox-content.config.ts

生成される ox-content.config.ts は、これらの設定を ox-content へ写します。

  • title / themeConfig.siteTitlessg.siteName
  • basebase
  • themeConfig.sidebarssg.navigation
  • themeConfig.socialLinks / themeConfig.footer / themeConfig.logossg.theme
  • themeConfig.search.placeholdersearch.placeholder

ランディングページでは、VitePress 風の layout: home frontmatter は ox-content の layout: entry と同じ扱いになります。

オプション#

非標準機能のどれがオプトインかを含む、まとめた既定表は 組み込み機能 を見てください。

srcDir#

  • 型: string
  • 既定: 'docs'

Markdown ファイルのソースディレクトリです。

extensions#

  • 型: string[]
  • 既定: ['.md', '.markdown', '.mdx']

Vite プラグイン、SSG、開発サーバ、検索インデックス、OG ビューアが処理する Markdown 風ファイル拡張子です。

outDir#

  • 型: string
  • 既定: 'dist'

ビルド成果物の出力ディレクトリです。

ssg#

  • 型: SsgOptions | boolean
  • 既定: { enabled: true }

SSG(静的サイト生成)オプションです。既定では、ox-content はビルド中に各 Markdown ファイルの静的 HTML を生成します。

oxContent({
  ssg: {
    enabled: true,
    extension: ".html",
    clean: false,
  },
});

SsgOptions#

オプション 既定 説明
enabled boolean true SSG モードのオン / オフ
extension string '.html' 出力ファイル拡張子
clean boolean false ビルド前に出力ディレクトリを消す
bare boolean false 素の HTML 出力(ナビなし、スタイルなし)

Bare モード(ベンチマーク向け)#

oxContent({
  ssg: {
    bare: true, // ナビ / スタイルなしの最小 HTML
  },
});

SSG を切る#

oxContent({
  ssg: false, // SSG を切り、モジュール変換器としてだけ使う
});

Vite 経由で Markdown を import しない独自ホストでも、公開 OxContentOptions から同じパイプラインを実行し、構造化された TransformResult を受け取れます。 プラグインの transform フックをキャストしたり、生成モジュールの export const html = ... をパースしたりする必要はありません。

import { renderMarkdown } from "@ox-content/vite-plugin";

const result = await renderMarkdown("# Hi", "/virtual/article.md", {
  ssg: false,
  highlight: false,
});

result.html;
result.frontmatter;
result.toc;

.md / .mdx の判定は Vite プラグインと同じ (resolveMdxForFilePath) で、 組み込みオプションの既定値も oxContent() と一致します。複数ドキュメントで オプション解決を一度だけにしたいときは createMarkdownProcessor(options) を 使い、processor.render(source, filePath) を呼んでください。

ssg: falserenderMarkdown()transformAllPlugins() が返すのは マークアップだけです。その HTML を描画するホストで公式の機能スタイルシートを import してください。crate の CSS をアプリにコピーしないでください。 コンポーネント CSS を見てください。

@import "@ox-content/vite-plugin/styles/core.css";
@import "@ox-content/vite-plugin/styles/markdown-tables.css";
@import "@ox-content/vite-plugin/styles/magic-links.css";
@import "@ox-content/vite-plugin/styles/social.css";
@import "@ox-content/vite-plugin/styles/twitter-full.css";
@import "@ox-content/vite-plugin/styles/reader-chrome.css";

既存の prose theme に、keyboard accessible なレスポンシブ Markdown table だけを足したい場合は、package root と styles/core.css ではなく styles/markdown-tables.css@ox-content/vite-plugin/markdown-tables を使ってください。

独自ホストは oxContentCustomHost() で Vite lifecycle を Ox Content に任せられます。 dev/build で host module を SSR load し、route dispatch、response cache、 dependency invalidation、manifest 対応の document asset tag、self-hosted asset、 redirect、Markdown 併記、協調 writer を持ちます。 独自ホスト lifecycleDocument assets を見てください。

framework integration がすでに Vite plugin を持っている場合も、buildSsg() なしで 低レベルのリソース指紋、Markdown 併記、フィード、sitemap、git lastmod helper を 再利用できます。SSG 出力プリミティブ を見てください。

Environment API の runtime 解決#

oxContent() は Vite の Environment API で Markdown environment を設定します。 Vite が Deno または Bun 上で動いているときは、対応する deno / bun resolve condition を追加し、build target は runtime neutral にします。既存の environment condition は残すので、アプリ側の conditional exports と併用できます。

import { createMarkdownEnvironment } from "@ox-content/vite-plugin";

export default defineConfig({
  environments: {
    markdown: createMarkdownEnvironment(resolvedOxContentOptions),
  },
});

Fetch router と middleware#

Vite dev server なしで Markdown ページを描画したいホストでは、 @ox-content/vite-plugin/router を使えます。router は標準 Fetch の Request / Response API ベースなので、同じ handler を Deno、Bun、 Workers 風ホスト、Node adapter で使えます。

// deno.ts
import { createOxContentFetchHandler } from "@ox-content/vite-plugin/router";

Deno.serve(
  createOxContentFetchHandler(
    {
      srcDir: "content",
      ssg: { routePrefix: "blog" },
    },
    Deno.cwd(),
  ),
);
// bun.ts
import { createOxContentFetchHandler } from "@ox-content/vite-plugin/router";

const fetch = createOxContentFetchHandler(
  {
    srcDir: "content",
    base: "/docs/",
    ssg: { routePrefix: "blog" },
  },
  import.meta.dir,
);

Bun.serve({ fetch });

framework adapter や独自 server では、組み込み renderer の前後に middleware を合成できます。

import { createOxContentMiddleware } from "@ox-content/vite-plugin/router";

const oxContentPages = createOxContentMiddleware({ srcDir: "content" }, projectRoot, {
  middleware: [
    async (context, next) => {
      if (context.match.routePathname.startsWith("/drafts/")) {
        return new Response("Not Found", { status: 404 });
      }
      const response = await next();
      if (!response) return undefined;
      const headers = new Headers(response.headers);
      headers.set("x-ox-route", context.match.routePathname);
      return new Response(response.body, { headers, status: response.status });
    },
  ],
});

gfm#

  • 型: boolean
  • 既定: true

GitHub Flavored Markdown 拡張を有効にします。

codeAnnotations#

  • 型: boolean | CodeAnnotationsOptions
  • 既定: false

フェンス付きコードブロック向けの、オプトインのコード注釈を有効にします。

既定では Ox Content は設定可能な属性構文を使います。VitePress 互換のフェンスメタデータとインライン記法にオプトインすることも、両方同時にオンにすることもできます。

oxContent({
  highlight: true,
  codeAnnotations: {
    notation: "both",
  },
});

既定 metaKey の属性構文:

```ts annotate="highlight:1,6;warning:2;error:3"
export function loadUser(input: string) {
  if (!input) console.warn("missing payload");
  throw new Error("missing id");
}

const user = loadUser(payload);
console.log(user);
```

VitePress 互換構文:

```ts:line-numbers=10 {1,4} [config.ts]
const user = loadUser(payload);
console.warn("Deprecated")
throw new Error("boom")
```

描画例:

export function loadUser(input: string) {
  if (!input) console.warn("missing payload");
  throw new Error("missing id");
}

const user = loadUser(payload);
console.log(user);

属性名も変えられます。

oxContent({
  codeAnnotations: {
    metaKey: "markers",
  },
});

描画例は Code Annotations の例 を見てください。

toc#

  • 型: boolean
  • 既定: true

目次を生成します。

embeds#

  • 型: BuiltinEmbedOptions | false
  • 既定: { github: true, openGraph: true, pm: false, spotify: false, appleMusic: false, speakerDeck: false, audio: false, video: false, stackBlitz: false, twitter: false, reddit: false, bluesky: false, webContainer: false }

組み込みの静的埋め込みは変換時に描画され、クライアント側 JavaScript は使いません。非標準の埋め込みはオプトインです。既定表と描画例の全体は 埋め込み を見てください。

<GitHub repo="ubugeeei-prod/ox-content" />

<GitHub permalink="https://github.com/ubugeeei-prod/ox-content/blob/278098b/README.md#L1-L12" />

<GitHub repo="ubugeeei-prod/ox-content" path="README.md" ref="main" loc="1-12" />

<OgCard url="https://github.com/ubugeeei-prod/ox-content" />

permalinkurlhref は GitHub の blob URL を受け付けます。#L1-L12 フラグメントはソース行範囲として使います。完全なパーマリンクを貼りたくないときは repopathrefloc も使えます。ソース埋め込みは GitHub contents API を取り、Open Graph プレビューではなくコードを直接描画します。

すべての埋め込みを切るか、各取得器を設定します。

oxContent({
  embeds: {
    github: {
      token: process.env.GITHUB_TOKEN,
      maxSourceBytes: 200000,
      maxSourceLines: 120,
    },
    openGraph: {
      timeout: 5000,
    },
    pm: true,
    reddit: true,
  },
});
oxContent({
  embeds: false,
});

組み込み埋め込みのスタイル#

組み込み埋め込みのマークアップは安定した CSS クラスを使うので、生成 HTML はクライアント側 JavaScript なしでテーマできます。

リポジトリカードのクラス:

  • .ox-github-card
  • .ox-github-header
  • .ox-github-icon
  • .ox-github-repo
  • .ox-github-description
  • .ox-github-stats
  • .ox-github-stat
  • .ox-github-language

ソースコードカードのクラス:

  • .ox-github-code
  • .ox-github-code-header
  • .ox-github-code-title
  • .ox-github-code-loc
  • .ox-github-code-block
  • .ox-github-code-line
  • .ox-github-code-line-number
  • .ox-github-code-line-content

Open Graph カードのクラス:

  • .ox-ogp-card
  • .ox-ogp-simple
  • .ox-ogp-content
  • .ox-ogp-title
  • .ox-ogp-description
  • .ox-ogp-image
  • .ox-ogp-meta
  • .ox-ogp-domain
  • .ox-ogp-favicon
.ox-github-card,
.ox-github-code,
.ox-ogp-card {
  border-color: var(--my-border-color);
}

.ox-github-code-line-number,
.ox-ogp-domain {
  color: var(--my-muted-color);
}

docs#

  • 型: DocsOptions | false
  • 既定: { enabled: true }

ソースドキュメント生成オプションです。切るときは false です。

生成 API ページはいま、要約統計、シグネチャバッジ、1 行のシンボル概要、展開できる詳細、ラベル付き例を含みます。集計件数を持つ機械可読の docs.json ペイロードも Markdown の横に出るので、独自ビューアはソースを再パースせずより豊かな体験を作れます。

oxContent({
  docs: {
    enabled: true,
    src: ["./src"],
    out: "docs/api",
    include: ["**/*.ts"],
    exclude: ["**/*.test.*"],
    format: "markdown",
    toc: true,
    groupBy: "file",
  },
});

DocsOptions#

オプション 既定 説明
enabled boolean true docs 生成のオン / オフ
src string[] ['./src'] 走査するソースディレクトリ
out string 'docs/api' 出力ディレクトリ
include string[] JS/TS ソース glob 含めるファイル
exclude string[] ['**/*.test.*', '**/*.spec.*'] 除くファイル
format 'markdown' | 'json' | 'html' 'markdown' 出力形式
private boolean false @private メンバーを含める
toc boolean true 目次を生成する
groupBy 'file' | 'category' 'file' ファイルまたはカテゴリでグループ

docs 生成を切る#

oxContent({
  docs: false, // 組み込み docs 生成をオプトアウト
});
  • 型: SearchOptions | boolean
  • 既定: { enabled: true }

全文検索オプションです。Ox Content は BM25 スコア付きの、Rust 駆動の組み込み検索エンジンを載せます。

oxContent({
  search: {
    enabled: true,
    limit: 10,
    prefix: true,
    placeholder: "Search documentation...",
    hotkey: "/",
  },
});

SearchOptions#

オプション 既定 説明
enabled boolean true 検索機能のオン / オフ
limit number 10 検索結果の上限
prefix boolean true オートコンプリート向けプレフィックス一致
placeholder string 'Search documentation...' 検索入力のプレースホルダ
hotkey string '/' 検索を開くキーボードショートカット

動き方#

  1. ビルド時: プラグインはすべての Markdown を走査し、Rust ベースの検索エンジンでインデックスを作る
  2. インデックス保存: インデックスは出力ディレクトリの search-index.json に書く
  3. クライアント側検索: 検索インデックスは必要になったときに読み、検索はすべてクライアント側

機能#

  • BM25 スコア: 業界標準の関連度順位アルゴリズム
  • 複数フィールド検索: タイトル、見出し、本文、コードを異なる重みで索引
  • 日本語 / CJK 対応: CJK 文字の適切なトークン化
  • プレフィックス一致: オートコンプリート向けタイプアヘッド
  • スコープ付きクエリ: @api transform のようにプレフィックスして区画で結果を制限
  • 依存ゼロ: 外部検索サービスは不要

検索を切る#

oxContent({
  search: false, // 組み込み検索を切る
});

独自検索 UI と使う#

仮想モジュール経由で検索インデックスにプログラムから触れます。

import { search, searchOptions } from "virtual:ox-content/search";

// Search the index
const results = await search("query text", { limit: 5 });

// Scope search to the API reference
const apiResults = await search("@api transform", { limit: 5 });

// Results include:
// - id: document ID
// - title: document title
// - url: document URL
// - score: relevance score
// - snippet: text snippet with context

collections#

  • 型: CollectionsOptions | boolean
  • 既定: { content: { source: "**/*" } }

コレクションは Markdown frontmatter とルートメタデータを virtual:ox-content/collections 経由で出します。その仮想モジュールを import したときだけビルドします。既定ペイロードはメタデータのみです。Ox Content はディレクトリ歩行、ソースパターンフィルタ、frontmatter パース、ルートパス生成、タイトル取り出しにネイティブ Rust マニフェストビルダを使うので、大きな Markdown 木はファイルごとの JavaScript / NAPI 往復を避け、すべての Markdown を HTML に描画しません。

// vite.config.ts
import { defineConfig } from "vite";
import { defineCollection, oxContent } from "@ox-content/vite-plugin";

export default defineConfig({
  plugins: [
    oxContent({
      srcDir: "content",
      collections: {
        blog: defineCollection({
          source: "blog/**/*.md",
        }),
        docs: defineCollection({
          source: "docs/**/*.md",
          include: ["body"],
        }),
      },
    }),
  ],
});
import { queryCollection } from "virtual:ox-content/collections";

const posts = await queryCollection("blog")
  .where("draft", "=", false)
  .order("date", "DESC")
  .select("title", "path", "description")
  .all();

const page = await queryCollection("docs").path("/docs/getting-started").first();

大きなサイトでは include は意図して明示です。

フィールド コスト
body 除いた生 Markdown を仮想モジュールに埋め込む。
html ネイティブ Markdown 変換を走らせ、HTML を埋め込む。
toc ネイティブ Markdown 変換を走らせ、TOC を埋め込む。

シンタックスハイライトや Mermaid 描画のような、ページ単位の完全な JavaScript 後処理では、Markdown モジュールを直接 import してください。コレクションの html はクエリペイロード向けに最適化しています。

コレクション全体を切るときは collections: false です。

Environment API#

プラグインは、SSG に寄せた描画のため、Vite の Environment API で markdown 環境を作ります。

HMR 対応#

開発中、Markdown はホットリロードされます。プラグインは独自 HMR イベントを送ります。

// Client-side
if (import.meta.hot) {
  import.meta.hot.on("ox-content:update", (data) => {
    console.log("Markdown updated:", data.file);
  });
}

仮想モジュール#

プラグインは次の仮想モジュールを提供します。

  • virtual:ox-content/config — 解決済みプラグイン設定
  • virtual:ox-content/runtime — ランタイムユーティリティ
  • virtual:ox-content/search — 検索機能
  • virtual:ox-content/collections — コレクションクエリヘルパー
import config from "virtual:ox-content/config";
import { useMarkdown, withBase, withoutBase } from "virtual:ox-content/runtime";
import { search, searchOptions } from "virtual:ox-content/search";
import { queryCollection } from "virtual:ox-content/collections";

const assetUrl = withBase("/og.png");
const routePath = withoutBase("/docs/guide");

// Use the search function
const results = await search("query", { limit: 10 });

const page = await queryCollection("content").path("/guide").first();

Last updated: