Nuxt Content v2 で4ツール分のマニュアルサイトをスケールさせた設計
2026-05-17
はじめに
当サイト akizorasoft.com では、自作の Web ツールのマニュアルを Nuxt Content v2 で配信しています。最初は PICOM のマニュアル1つだけでしたが、差分比較ツール・詠み人・yomogi の3ツール分のマニュアルを一気に追加しました。
この記事では、その過程で「1ツール専用だったマニュアル基盤をどうスケールさせたか」を、composable 抽象化と動的ルート構成の観点からまとめます。
最初の PICOM 専用マニュアルでは、useManualNavigation composable の中で picom セクションがハードコードされていました。これを sectionsByTool のレコードに昇格させ、動的ルート(/manual/[tool]/[slug])の Vue ページも PICOM パターンを複製することで、4ツール分のマニュアルサイトに拡張できました。
環境
| 項目 | 技術 |
|---|---|
| フレームワーク | Nuxt 4(SSG) |
| CMS | Nuxt Content v2 |
| ホスティング | Azure Static Web Apps |
| ツール数 | 1 → 4(PICOM / diff / yominchu / yomogi) |
初期状態:PICOM 専用のハードコード
マニュアル基盤の中核は app/composables/useManualNavigation.ts です。最初はこんな形で、PICOM のセクション定義がそのままベタ書きされていました。
const picomSections: ManualNavSection[] = [
{ title: '基本', items: [ /* ... */ ] },
{ title: '作曲', items: [ /* ... */ ] },
{ title: '応用', items: [ /* ... */ ] },
{ title: 'リファレンス', items: [ /* ... */ ] },
]
export const useManualNavigation = (toolSlug: string) => {
const sections = computed(() => {
if (toolSlug === 'picom') {
return picomSections
}
return []
})
// ...
}
1ツールしか存在しないうちは、この実装で十分でした。実際 PICOM の構成はこれで問題なく動いていました。
問題は「2つ目のツール」を追加しようとした瞬間に露呈します。
ステップ1:sectionsByTool レコードへの昇格
最小の変更は、if 分岐を辞書参照に置き換えることです。
const sectionsByTool: Record<string, ManualNavSection[]> = {
picom: picomSections,
diff: diffSections,
yominchu: yominchuSections,
yomogi: yomogiSections,
}
export const useManualNavigation = (toolSlug: string) => {
const sections = computed(() => sectionsByTool[toolSlug] ?? [])
// ...
}
これだけで、新しいツールを追加するときは次の2ステップだけで済むようになります。
- 新しいツール用のセクション定義を書く(例:
diffSections) sectionsByToolにdiff: diffSectionsの1行を足す
関数の本体は一切触らなくて良く、テストや既存動作への回帰リスクもほぼゼロ です。
「分岐」を「辞書」に変えるだけのリファクタリングなのに、後から見返すと効果が大きい典型例でした。
ステップ2:動的ルートの複製
次は Vue ページ側です。app/pages/manual/picom/ には index.vue(マニュアルトップ)と [slug].vue(各章の動的ページ)の2つがあり、両方が useManualNavigation('picom') を呼び出しています。
これを 4ツール分用意する必要があります。やり方は2通り考えました。
案 A:単一の /manual/[tool]/[slug].vue に統合
パラメータ [tool] と [slug] の両方を動的にし、1組の Vue ページで全ツールを賄う案です。コード量は最小になります。
案 B:ツールごとに manual/{tool}/[slug].vue を複製
物理的にツール別のディレクトリを掘る案。コードの重複は増えますが、ツールごとに違う breadcrumb や OG 画像を素直に書ける 利点があります。
結局、案 B を採用しました。理由は次の通りです。
- 各ツールの breadcrumb リンクはツール名も URL も異なる。動的にするとリテラルが増えて読みにくくなる
- OG 画像のパスをツールごとに分けたい場合に、動的分岐が面倒
- PICOM はすでに案 B の形で動いていたため、既存コードを壊さず 拡張できる
- 重複コードは 60 行程度で、複雑な分岐コードよりも読みやすい
- 将来的にマニュアルのデザインを製品に合わせるということも行いたい
複製後のディレクトリ構造はこうなりました。
app/pages/manual/
├── picom/
│ ├── index.vue
│ └── [slug].vue
├── diff/
│ ├── index.vue
│ └── [slug].vue
├── yominchu/
│ ├── index.vue
│ └── [slug].vue
└── yomogi/
├── index.vue
└── [slug].vue
コピペ臭はありますが、中身の差は useManualNavigation('picom') の引数と breadcrumb リンクだけ です。読むほうが楽で、保守時の事故も少ないです。
正直、AIエージェントを利用できる現環境下で、コピペを全力で避ける必要性は薄くなったと感じています。コピペ内容も小規模ですし。
ステップ3:Nuxt Content 側のディレクトリ
content/tool_manuals/ 配下にもツールごとにディレクトリを掘ります。
content/tool_manuals/
├── picom/
│ ├── index.md
│ ├── getting-started.md
│ └── ... (11ファイル)
├── diff/
├── yominchu/
└── yomogi/
各 .md ファイルの frontmatter には sitemap.loc と sitemap.lastmod を入れておき、@nuxtjs/sitemap が sitemap.xml に自動で流し込む仕組みです。新しいマニュアルを追加する作業は、ほぼ Markdown を置くだけ に収まります。
---
title: はじめかた - Yomogi マニュアル
description: Yomogi の初回アクセスから...
date: 2026-04-14
sitemap:
loc: "/manual/yomogi/getting-started"
lastmod: "2026-04-14"
priority: 0.8
---
実際の拡張コスト
PICOM マニュアルが既にあった状態から、diff / yominchu / yomogi の3ツール分のマニュアル基盤を整えるのに要したコード作業の内訳はこうです。
useManualNavigation.tsへの 3 ツール分の sections 追加- 動的ルート Vue ページ 6 ファイルの複製・微修正
- マニュアル Markdown 9 ファイルの執筆・確認
大半はコード作業ではなく文章執筆で、これは想定通りです。Nuxt Content v2 の強みは「コンテンツ追加コストを文章執筆そのものに絞れる」点にあります。 さらに、文章執筆は AI エージェントを活用して下書きを生成できます。つまり、実質的にマニュアルの運用コストは内容の確認に集中できるということです。
まとめ
- 「1つ目」を作るときは
if toolSlug === 'picom'のハードコードで十分。早すぎる抽象化は不要 - 「2つ目」を追加する瞬間に、辞書化 + ディレクトリ複製 のリファクタが効く
- Vue ページは DRY より breadcrumb や OG の素直さ を優先して複製を選ぶ判断もあり
- Nuxt Content v2 + frontmatter sitemap の組み合わせで、マニュアル追加は純粋な執筆コストに収束する
「スケールさせる」という言葉はつい大袈裟に捉えがちですが、実際には小さな工夫をしただけに過ぎません。個人開発のマニュアルサイト設計の参考になれば幸いです。
