[{"data":1,"prerenderedAt":1596},["ShallowReactive",2],{"content-query-nHjjTI5IwZ":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"rowTypeId":15,"sitemap":16,"body":17,"_type":1590,"_id":1591,"_source":1592,"_file":1593,"_stem":1594,"_extension":1595},"/articles/tech/development/nuxt-content-manual-site","development",false,"","Nuxt Content v2 で4ツール分のマニュアルサイトをスケールさせた設計","Nuxt Content v2 で構築したマニュアルサイトを、1ツール専用から4ツール対応にスケールさせたときの composable 抽象化と動的ルート構成の記録です。","2026-05-17",[12,13,14],"Nuxt","Nuxt Content","マニュアル",1,{"loc":4,"lastmod":10,"priority":15},{"type":18,"children":19,"toc":1574},"root",[20,28,45,58,92,97,177,183,196,674,679,684,697,710,978,983,1018,1030,1035,1041,1078,1083,1098,1119,1133,1145,1157,1193,1198,1206,1225,1231,1242,1250,1301,1460,1465,1470,1494,1513,1518,1563,1568],{"type":21,"tag":22,"props":23,"children":25},"element","h2",{"id":24},"はじめに",[26],{"type":27,"value":24},"text",{"type":21,"tag":29,"props":30,"children":31},"p",{},[32,34,43],{"type":27,"value":33},"当サイト ",{"type":21,"tag":35,"props":36,"children":40},"a",{"href":37,"rel":38},"https://www.akizorasoft.com",[39],"nofollow",[41],{"type":27,"value":42},"akizorasoft.com",{"type":27,"value":44}," では、自作の Web ツールのマニュアルを Nuxt Content v2 で配信しています。最初は PICOM のマニュアル1つだけでしたが、差分比較ツール・詠み人・yomogi の3ツール分のマニュアルを一気に追加しました。",{"type":21,"tag":29,"props":46,"children":47},{},[48,50,56],{"type":27,"value":49},"この記事では、その過程で「",{"type":21,"tag":51,"props":52,"children":53},"strong",{},[54],{"type":27,"value":55},"1ツール専用だったマニュアル基盤をどうスケールさせたか",{"type":27,"value":57},"」を、composable 抽象化と動的ルート構成の観点からまとめます。",{"type":21,"tag":59,"props":60,"children":61},"summary-box",{},[62],{"type":21,"tag":29,"props":63,"children":64},{},[65,67,74,76,82,84,90],{"type":27,"value":66},"最初の PICOM 専用マニュアルでは、",{"type":21,"tag":68,"props":69,"children":71},"code",{"className":70},[],[72],{"type":27,"value":73},"useManualNavigation",{"type":27,"value":75}," composable の中で picom セクションがハードコードされていました。これを ",{"type":21,"tag":68,"props":77,"children":79},{"className":78},[],[80],{"type":27,"value":81},"sectionsByTool",{"type":27,"value":83}," のレコードに昇格させ、動的ルート（",{"type":21,"tag":68,"props":85,"children":87},{"className":86},[],[88],{"type":27,"value":89},"/manual/[tool]/[slug]",{"type":27,"value":91},"）の Vue ページも PICOM パターンを複製することで、4ツール分のマニュアルサイトに拡張できました。",{"type":21,"tag":22,"props":93,"children":95},{"id":94},"環境",[96],{"type":27,"value":94},{"type":21,"tag":98,"props":99,"children":100},"table",{},[101,120],{"type":21,"tag":102,"props":103,"children":104},"thead",{},[105],{"type":21,"tag":106,"props":107,"children":108},"tr",{},[109,115],{"type":21,"tag":110,"props":111,"children":112},"th",{},[113],{"type":27,"value":114},"項目",{"type":21,"tag":110,"props":116,"children":117},{},[118],{"type":27,"value":119},"技術",{"type":21,"tag":121,"props":122,"children":123},"tbody",{},[124,138,151,164],{"type":21,"tag":106,"props":125,"children":126},{},[127,133],{"type":21,"tag":128,"props":129,"children":130},"td",{},[131],{"type":27,"value":132},"フレームワーク",{"type":21,"tag":128,"props":134,"children":135},{},[136],{"type":27,"value":137},"Nuxt 4（SSG）",{"type":21,"tag":106,"props":139,"children":140},{},[141,146],{"type":21,"tag":128,"props":142,"children":143},{},[144],{"type":27,"value":145},"CMS",{"type":21,"tag":128,"props":147,"children":148},{},[149],{"type":27,"value":150},"Nuxt Content v2",{"type":21,"tag":106,"props":152,"children":153},{},[154,159],{"type":21,"tag":128,"props":155,"children":156},{},[157],{"type":27,"value":158},"ホスティング",{"type":21,"tag":128,"props":160,"children":161},{},[162],{"type":27,"value":163},"Azure Static Web Apps",{"type":21,"tag":106,"props":165,"children":166},{},[167,172],{"type":21,"tag":128,"props":168,"children":169},{},[170],{"type":27,"value":171},"ツール数",{"type":21,"tag":128,"props":173,"children":174},{},[175],{"type":27,"value":176},"1 → 4（PICOM / diff / yominchu / yomogi）",{"type":21,"tag":22,"props":178,"children":180},{"id":179},"初期状態picom-専用のハードコード",[181],{"type":27,"value":182},"初期状態：PICOM 専用のハードコード",{"type":21,"tag":29,"props":184,"children":185},{},[186,188,194],{"type":27,"value":187},"マニュアル基盤の中核は ",{"type":21,"tag":68,"props":189,"children":191},{"className":190},[],[192],{"type":27,"value":193},"app/composables/useManualNavigation.ts",{"type":27,"value":195}," です。最初はこんな形で、PICOM のセクション定義がそのままベタ書きされていました。",{"type":21,"tag":197,"props":198,"children":202},"pre",{"code":199,"language":200,"meta":7,"className":201,"style":7},"const picomSections: ManualNavSection[] = [\n  { title: '基本', items: [ /* ... */ ] },\n  { title: '作曲', items: [ /* ... */ ] },\n  { title: '応用', items: [ /* ... */ ] },\n  { title: 'リファレンス', items: [ /* ... */ ] },\n]\n\nexport const useManualNavigation = (toolSlug: string) => {\n  const sections = computed(() => {\n    if (toolSlug === 'picom') {\n      return picomSections\n    }\n    return []\n  })\n  // ...\n}\n","typescript","language-typescript shiki shiki-themes vitesse-dark",[203],{"type":21,"tag":68,"props":204,"children":205},{"__ignoreMap":7},[206,245,306,355,404,453,462,472,531,567,610,624,633,647,656,665],{"type":21,"tag":207,"props":208,"children":210},"span",{"class":209,"line":15},"line",[211,217,223,229,235,240],{"type":21,"tag":207,"props":212,"children":214},{"style":213},"--shiki-default:#CB7676",[215],{"type":27,"value":216},"const ",{"type":21,"tag":207,"props":218,"children":220},{"style":219},"--shiki-default:#BD976A",[221],{"type":27,"value":222},"picomSections",{"type":21,"tag":207,"props":224,"children":226},{"style":225},"--shiki-default:#666666",[227],{"type":27,"value":228},": ",{"type":21,"tag":207,"props":230,"children":232},{"style":231},"--shiki-default:#5DA994",[233],{"type":27,"value":234},"ManualNavSection",{"type":21,"tag":207,"props":236,"children":237},{"style":225},[238],{"type":27,"value":239},"[] =",{"type":21,"tag":207,"props":241,"children":242},{"style":225},[243],{"type":27,"value":244}," [\n",{"type":21,"tag":207,"props":246,"children":248},{"class":209,"line":247},2,[249,254,260,264,270,276,280,285,290,295,301],{"type":21,"tag":207,"props":250,"children":251},{"style":225},[252],{"type":27,"value":253},"  { ",{"type":21,"tag":207,"props":255,"children":257},{"style":256},"--shiki-default:#B8A965",[258],{"type":27,"value":259},"title",{"type":21,"tag":207,"props":261,"children":262},{"style":225},[263],{"type":27,"value":228},{"type":21,"tag":207,"props":265,"children":267},{"style":266},"--shiki-default:#C98A7D77",[268],{"type":27,"value":269},"'",{"type":21,"tag":207,"props":271,"children":273},{"style":272},"--shiki-default:#C98A7D",[274],{"type":27,"value":275},"基本",{"type":21,"tag":207,"props":277,"children":278},{"style":266},[279],{"type":27,"value":269},{"type":21,"tag":207,"props":281,"children":282},{"style":225},[283],{"type":27,"value":284},", ",{"type":21,"tag":207,"props":286,"children":287},{"style":256},[288],{"type":27,"value":289},"items",{"type":21,"tag":207,"props":291,"children":292},{"style":225},[293],{"type":27,"value":294},": [ ",{"type":21,"tag":207,"props":296,"children":298},{"style":297},"--shiki-default:#758575DD",[299],{"type":27,"value":300},"/* ... */",{"type":21,"tag":207,"props":302,"children":303},{"style":225},[304],{"type":27,"value":305}," ] },\n",{"type":21,"tag":207,"props":307,"children":309},{"class":209,"line":308},3,[310,314,318,322,326,331,335,339,343,347,351],{"type":21,"tag":207,"props":311,"children":312},{"style":225},[313],{"type":27,"value":253},{"type":21,"tag":207,"props":315,"children":316},{"style":256},[317],{"type":27,"value":259},{"type":21,"tag":207,"props":319,"children":320},{"style":225},[321],{"type":27,"value":228},{"type":21,"tag":207,"props":323,"children":324},{"style":266},[325],{"type":27,"value":269},{"type":21,"tag":207,"props":327,"children":328},{"style":272},[329],{"type":27,"value":330},"作曲",{"type":21,"tag":207,"props":332,"children":333},{"style":266},[334],{"type":27,"value":269},{"type":21,"tag":207,"props":336,"children":337},{"style":225},[338],{"type":27,"value":284},{"type":21,"tag":207,"props":340,"children":341},{"style":256},[342],{"type":27,"value":289},{"type":21,"tag":207,"props":344,"children":345},{"style":225},[346],{"type":27,"value":294},{"type":21,"tag":207,"props":348,"children":349},{"style":297},[350],{"type":27,"value":300},{"type":21,"tag":207,"props":352,"children":353},{"style":225},[354],{"type":27,"value":305},{"type":21,"tag":207,"props":356,"children":358},{"class":209,"line":357},4,[359,363,367,371,375,380,384,388,392,396,400],{"type":21,"tag":207,"props":360,"children":361},{"style":225},[362],{"type":27,"value":253},{"type":21,"tag":207,"props":364,"children":365},{"style":256},[366],{"type":27,"value":259},{"type":21,"tag":207,"props":368,"children":369},{"style":225},[370],{"type":27,"value":228},{"type":21,"tag":207,"props":372,"children":373},{"style":266},[374],{"type":27,"value":269},{"type":21,"tag":207,"props":376,"children":377},{"style":272},[378],{"type":27,"value":379},"応用",{"type":21,"tag":207,"props":381,"children":382},{"style":266},[383],{"type":27,"value":269},{"type":21,"tag":207,"props":385,"children":386},{"style":225},[387],{"type":27,"value":284},{"type":21,"tag":207,"props":389,"children":390},{"style":256},[391],{"type":27,"value":289},{"type":21,"tag":207,"props":393,"children":394},{"style":225},[395],{"type":27,"value":294},{"type":21,"tag":207,"props":397,"children":398},{"style":297},[399],{"type":27,"value":300},{"type":21,"tag":207,"props":401,"children":402},{"style":225},[403],{"type":27,"value":305},{"type":21,"tag":207,"props":405,"children":407},{"class":209,"line":406},5,[408,412,416,420,424,429,433,437,441,445,449],{"type":21,"tag":207,"props":409,"children":410},{"style":225},[411],{"type":27,"value":253},{"type":21,"tag":207,"props":413,"children":414},{"style":256},[415],{"type":27,"value":259},{"type":21,"tag":207,"props":417,"children":418},{"style":225},[419],{"type":27,"value":228},{"type":21,"tag":207,"props":421,"children":422},{"style":266},[423],{"type":27,"value":269},{"type":21,"tag":207,"props":425,"children":426},{"style":272},[427],{"type":27,"value":428},"リファレンス",{"type":21,"tag":207,"props":430,"children":431},{"style":266},[432],{"type":27,"value":269},{"type":21,"tag":207,"props":434,"children":435},{"style":225},[436],{"type":27,"value":284},{"type":21,"tag":207,"props":438,"children":439},{"style":256},[440],{"type":27,"value":289},{"type":21,"tag":207,"props":442,"children":443},{"style":225},[444],{"type":27,"value":294},{"type":21,"tag":207,"props":446,"children":447},{"style":297},[448],{"type":27,"value":300},{"type":21,"tag":207,"props":450,"children":451},{"style":225},[452],{"type":27,"value":305},{"type":21,"tag":207,"props":454,"children":456},{"class":209,"line":455},6,[457],{"type":21,"tag":207,"props":458,"children":459},{"style":225},[460],{"type":27,"value":461},"]\n",{"type":21,"tag":207,"props":463,"children":465},{"class":209,"line":464},7,[466],{"type":21,"tag":207,"props":467,"children":469},{"emptyLinePlaceholder":468},true,[470],{"type":27,"value":471},"\n",{"type":21,"tag":207,"props":473,"children":475},{"class":209,"line":474},8,[476,482,487,492,497,502,507,511,516,521,526],{"type":21,"tag":207,"props":477,"children":479},{"style":478},"--shiki-default:#4D9375",[480],{"type":27,"value":481},"export",{"type":21,"tag":207,"props":483,"children":484},{"style":213},[485],{"type":27,"value":486}," const ",{"type":21,"tag":207,"props":488,"children":490},{"style":489},"--shiki-default:#80A665",[491],{"type":27,"value":73},{"type":21,"tag":207,"props":493,"children":494},{"style":225},[495],{"type":27,"value":496}," =",{"type":21,"tag":207,"props":498,"children":499},{"style":225},[500],{"type":27,"value":501}," (",{"type":21,"tag":207,"props":503,"children":504},{"style":219},[505],{"type":27,"value":506},"toolSlug",{"type":21,"tag":207,"props":508,"children":509},{"style":225},[510],{"type":27,"value":228},{"type":21,"tag":207,"props":512,"children":513},{"style":231},[514],{"type":27,"value":515},"string",{"type":21,"tag":207,"props":517,"children":518},{"style":225},[519],{"type":27,"value":520},")",{"type":21,"tag":207,"props":522,"children":523},{"style":225},[524],{"type":27,"value":525}," =>",{"type":21,"tag":207,"props":527,"children":528},{"style":225},[529],{"type":27,"value":530}," {\n",{"type":21,"tag":207,"props":532,"children":534},{"class":209,"line":533},9,[535,540,545,549,554,559,563],{"type":21,"tag":207,"props":536,"children":537},{"style":213},[538],{"type":27,"value":539},"  const ",{"type":21,"tag":207,"props":541,"children":542},{"style":219},[543],{"type":27,"value":544},"sections",{"type":21,"tag":207,"props":546,"children":547},{"style":225},[548],{"type":27,"value":496},{"type":21,"tag":207,"props":550,"children":551},{"style":489},[552],{"type":27,"value":553}," computed",{"type":21,"tag":207,"props":555,"children":556},{"style":225},[557],{"type":27,"value":558},"(()",{"type":21,"tag":207,"props":560,"children":561},{"style":225},[562],{"type":27,"value":525},{"type":21,"tag":207,"props":564,"children":565},{"style":225},[566],{"type":27,"value":530},{"type":21,"tag":207,"props":568,"children":570},{"class":209,"line":569},10,[571,576,580,584,589,593,598,602,606],{"type":21,"tag":207,"props":572,"children":573},{"style":478},[574],{"type":27,"value":575},"    if",{"type":21,"tag":207,"props":577,"children":578},{"style":225},[579],{"type":27,"value":501},{"type":21,"tag":207,"props":581,"children":582},{"style":219},[583],{"type":27,"value":506},{"type":21,"tag":207,"props":585,"children":586},{"style":213},[587],{"type":27,"value":588}," === ",{"type":21,"tag":207,"props":590,"children":591},{"style":266},[592],{"type":27,"value":269},{"type":21,"tag":207,"props":594,"children":595},{"style":272},[596],{"type":27,"value":597},"picom",{"type":21,"tag":207,"props":599,"children":600},{"style":266},[601],{"type":27,"value":269},{"type":21,"tag":207,"props":603,"children":604},{"style":225},[605],{"type":27,"value":520},{"type":21,"tag":207,"props":607,"children":608},{"style":225},[609],{"type":27,"value":530},{"type":21,"tag":207,"props":611,"children":613},{"class":209,"line":612},11,[614,619],{"type":21,"tag":207,"props":615,"children":616},{"style":478},[617],{"type":27,"value":618},"      return",{"type":21,"tag":207,"props":620,"children":621},{"style":219},[622],{"type":27,"value":623}," picomSections\n",{"type":21,"tag":207,"props":625,"children":627},{"class":209,"line":626},12,[628],{"type":21,"tag":207,"props":629,"children":630},{"style":225},[631],{"type":27,"value":632},"    }\n",{"type":21,"tag":207,"props":634,"children":636},{"class":209,"line":635},13,[637,642],{"type":21,"tag":207,"props":638,"children":639},{"style":478},[640],{"type":27,"value":641},"    return",{"type":21,"tag":207,"props":643,"children":644},{"style":225},[645],{"type":27,"value":646}," []\n",{"type":21,"tag":207,"props":648,"children":650},{"class":209,"line":649},14,[651],{"type":21,"tag":207,"props":652,"children":653},{"style":225},[654],{"type":27,"value":655},"  })\n",{"type":21,"tag":207,"props":657,"children":659},{"class":209,"line":658},15,[660],{"type":21,"tag":207,"props":661,"children":662},{"style":297},[663],{"type":27,"value":664},"  // ...\n",{"type":21,"tag":207,"props":666,"children":668},{"class":209,"line":667},16,[669],{"type":21,"tag":207,"props":670,"children":671},{"style":225},[672],{"type":27,"value":673},"}\n",{"type":21,"tag":29,"props":675,"children":676},{},[677],{"type":27,"value":678},"1ツールしか存在しないうちは、この実装で十分でした。実際 PICOM の構成はこれで問題なく動いていました。",{"type":21,"tag":29,"props":680,"children":681},{},[682],{"type":27,"value":683},"問題は「2つ目のツール」を追加しようとした瞬間に露呈します。",{"type":21,"tag":22,"props":685,"children":687},{"id":686},"ステップ1sectionsbytool-レコードへの昇格",[688,690,695],{"type":27,"value":689},"ステップ1：",{"type":21,"tag":68,"props":691,"children":693},{"className":692},[],[694],{"type":27,"value":81},{"type":27,"value":696}," レコードへの昇格",{"type":21,"tag":29,"props":698,"children":699},{},[700,702,708],{"type":27,"value":701},"最小の変更は、",{"type":21,"tag":68,"props":703,"children":705},{"className":704},[],[706],{"type":27,"value":707},"if",{"type":27,"value":709}," 分岐を辞書参照に置き換えることです。",{"type":21,"tag":197,"props":711,"children":713},{"code":712,"language":200,"meta":7,"className":201,"style":7},"const sectionsByTool: Record\u003Cstring, ManualNavSection[]> = {\n  picom: picomSections,\n  diff: diffSections,\n  yominchu: yominchuSections,\n  yomogi: yomogiSections,\n}\n\nexport const useManualNavigation = (toolSlug: string) => {\n  const sections = computed(() => sectionsByTool[toolSlug] ?? [])\n  // ...\n}\n",[714],{"type":21,"tag":68,"props":715,"children":716},{"__ignoreMap":7},[717,763,784,805,826,847,854,861,908,964,971],{"type":21,"tag":207,"props":718,"children":719},{"class":209,"line":15},[720,724,728,732,737,742,746,750,754,759],{"type":21,"tag":207,"props":721,"children":722},{"style":213},[723],{"type":27,"value":216},{"type":21,"tag":207,"props":725,"children":726},{"style":219},[727],{"type":27,"value":81},{"type":21,"tag":207,"props":729,"children":730},{"style":225},[731],{"type":27,"value":228},{"type":21,"tag":207,"props":733,"children":734},{"style":231},[735],{"type":27,"value":736},"Record",{"type":21,"tag":207,"props":738,"children":739},{"style":225},[740],{"type":27,"value":741},"\u003C",{"type":21,"tag":207,"props":743,"children":744},{"style":231},[745],{"type":27,"value":515},{"type":21,"tag":207,"props":747,"children":748},{"style":225},[749],{"type":27,"value":284},{"type":21,"tag":207,"props":751,"children":752},{"style":231},[753],{"type":27,"value":234},{"type":21,"tag":207,"props":755,"children":756},{"style":225},[757],{"type":27,"value":758},"[]> =",{"type":21,"tag":207,"props":760,"children":761},{"style":225},[762],{"type":27,"value":530},{"type":21,"tag":207,"props":764,"children":765},{"class":209,"line":247},[766,771,775,779],{"type":21,"tag":207,"props":767,"children":768},{"style":256},[769],{"type":27,"value":770},"  picom",{"type":21,"tag":207,"props":772,"children":773},{"style":225},[774],{"type":27,"value":228},{"type":21,"tag":207,"props":776,"children":777},{"style":219},[778],{"type":27,"value":222},{"type":21,"tag":207,"props":780,"children":781},{"style":225},[782],{"type":27,"value":783},",\n",{"type":21,"tag":207,"props":785,"children":786},{"class":209,"line":308},[787,792,796,801],{"type":21,"tag":207,"props":788,"children":789},{"style":256},[790],{"type":27,"value":791},"  diff",{"type":21,"tag":207,"props":793,"children":794},{"style":225},[795],{"type":27,"value":228},{"type":21,"tag":207,"props":797,"children":798},{"style":219},[799],{"type":27,"value":800},"diffSections",{"type":21,"tag":207,"props":802,"children":803},{"style":225},[804],{"type":27,"value":783},{"type":21,"tag":207,"props":806,"children":807},{"class":209,"line":357},[808,813,817,822],{"type":21,"tag":207,"props":809,"children":810},{"style":256},[811],{"type":27,"value":812},"  yominchu",{"type":21,"tag":207,"props":814,"children":815},{"style":225},[816],{"type":27,"value":228},{"type":21,"tag":207,"props":818,"children":819},{"style":219},[820],{"type":27,"value":821},"yominchuSections",{"type":21,"tag":207,"props":823,"children":824},{"style":225},[825],{"type":27,"value":783},{"type":21,"tag":207,"props":827,"children":828},{"class":209,"line":406},[829,834,838,843],{"type":21,"tag":207,"props":830,"children":831},{"style":256},[832],{"type":27,"value":833},"  yomogi",{"type":21,"tag":207,"props":835,"children":836},{"style":225},[837],{"type":27,"value":228},{"type":21,"tag":207,"props":839,"children":840},{"style":219},[841],{"type":27,"value":842},"yomogiSections",{"type":21,"tag":207,"props":844,"children":845},{"style":225},[846],{"type":27,"value":783},{"type":21,"tag":207,"props":848,"children":849},{"class":209,"line":455},[850],{"type":21,"tag":207,"props":851,"children":852},{"style":225},[853],{"type":27,"value":673},{"type":21,"tag":207,"props":855,"children":856},{"class":209,"line":464},[857],{"type":21,"tag":207,"props":858,"children":859},{"emptyLinePlaceholder":468},[860],{"type":27,"value":471},{"type":21,"tag":207,"props":862,"children":863},{"class":209,"line":474},[864,868,872,876,880,884,888,892,896,900,904],{"type":21,"tag":207,"props":865,"children":866},{"style":478},[867],{"type":27,"value":481},{"type":21,"tag":207,"props":869,"children":870},{"style":213},[871],{"type":27,"value":486},{"type":21,"tag":207,"props":873,"children":874},{"style":489},[875],{"type":27,"value":73},{"type":21,"tag":207,"props":877,"children":878},{"style":225},[879],{"type":27,"value":496},{"type":21,"tag":207,"props":881,"children":882},{"style":225},[883],{"type":27,"value":501},{"type":21,"tag":207,"props":885,"children":886},{"style":219},[887],{"type":27,"value":506},{"type":21,"tag":207,"props":889,"children":890},{"style":225},[891],{"type":27,"value":228},{"type":21,"tag":207,"props":893,"children":894},{"style":231},[895],{"type":27,"value":515},{"type":21,"tag":207,"props":897,"children":898},{"style":225},[899],{"type":27,"value":520},{"type":21,"tag":207,"props":901,"children":902},{"style":225},[903],{"type":27,"value":525},{"type":21,"tag":207,"props":905,"children":906},{"style":225},[907],{"type":27,"value":530},{"type":21,"tag":207,"props":909,"children":910},{"class":209,"line":533},[911,915,919,923,927,931,935,940,945,949,954,959],{"type":21,"tag":207,"props":912,"children":913},{"style":213},[914],{"type":27,"value":539},{"type":21,"tag":207,"props":916,"children":917},{"style":219},[918],{"type":27,"value":544},{"type":21,"tag":207,"props":920,"children":921},{"style":225},[922],{"type":27,"value":496},{"type":21,"tag":207,"props":924,"children":925},{"style":489},[926],{"type":27,"value":553},{"type":21,"tag":207,"props":928,"children":929},{"style":225},[930],{"type":27,"value":558},{"type":21,"tag":207,"props":932,"children":933},{"style":225},[934],{"type":27,"value":525},{"type":21,"tag":207,"props":936,"children":937},{"style":219},[938],{"type":27,"value":939}," sectionsByTool",{"type":21,"tag":207,"props":941,"children":942},{"style":225},[943],{"type":27,"value":944},"[",{"type":21,"tag":207,"props":946,"children":947},{"style":219},[948],{"type":27,"value":506},{"type":21,"tag":207,"props":950,"children":951},{"style":225},[952],{"type":27,"value":953},"]",{"type":21,"tag":207,"props":955,"children":956},{"style":213},[957],{"type":27,"value":958}," ?? ",{"type":21,"tag":207,"props":960,"children":961},{"style":225},[962],{"type":27,"value":963},"[])\n",{"type":21,"tag":207,"props":965,"children":966},{"class":209,"line":569},[967],{"type":21,"tag":207,"props":968,"children":969},{"style":297},[970],{"type":27,"value":664},{"type":21,"tag":207,"props":972,"children":973},{"class":209,"line":612},[974],{"type":21,"tag":207,"props":975,"children":976},{"style":225},[977],{"type":27,"value":673},{"type":21,"tag":29,"props":979,"children":980},{},[981],{"type":27,"value":982},"これだけで、新しいツールを追加するときは次の2ステップだけで済むようになります。",{"type":21,"tag":984,"props":985,"children":986},"ol",{},[987,1000],{"type":21,"tag":988,"props":989,"children":990},"li",{},[991,993,998],{"type":27,"value":992},"新しいツール用のセクション定義を書く（例: ",{"type":21,"tag":68,"props":994,"children":996},{"className":995},[],[997],{"type":27,"value":800},{"type":27,"value":999},"）",{"type":21,"tag":988,"props":1001,"children":1002},{},[1003,1008,1010,1016],{"type":21,"tag":68,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":27,"value":81},{"type":27,"value":1009}," に ",{"type":21,"tag":68,"props":1011,"children":1013},{"className":1012},[],[1014],{"type":27,"value":1015},"diff: diffSections",{"type":27,"value":1017}," の1行を足す",{"type":21,"tag":29,"props":1019,"children":1020},{},[1021,1023,1028],{"type":27,"value":1022},"関数の本体は一切触らなくて良く、",{"type":21,"tag":51,"props":1024,"children":1025},{},[1026],{"type":27,"value":1027},"テストや既存動作への回帰リスクもほぼゼロ",{"type":27,"value":1029}," です。",{"type":21,"tag":29,"props":1031,"children":1032},{},[1033],{"type":27,"value":1034},"「分岐」を「辞書」に変えるだけのリファクタリングなのに、後から見返すと効果が大きい典型例でした。",{"type":21,"tag":22,"props":1036,"children":1038},{"id":1037},"ステップ2動的ルートの複製",[1039],{"type":27,"value":1040},"ステップ2：動的ルートの複製",{"type":21,"tag":29,"props":1042,"children":1043},{},[1044,1046,1052,1054,1060,1062,1068,1070,1076],{"type":27,"value":1045},"次は Vue ページ側です。",{"type":21,"tag":68,"props":1047,"children":1049},{"className":1048},[],[1050],{"type":27,"value":1051},"app/pages/manual/picom/",{"type":27,"value":1053}," には ",{"type":21,"tag":68,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":27,"value":1059},"index.vue",{"type":27,"value":1061},"（マニュアルトップ）と ",{"type":21,"tag":68,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":27,"value":1067},"[slug].vue",{"type":27,"value":1069},"（各章の動的ページ）の2つがあり、両方が ",{"type":21,"tag":68,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":27,"value":1075},"useManualNavigation('picom')",{"type":27,"value":1077}," を呼び出しています。",{"type":21,"tag":29,"props":1079,"children":1080},{},[1081],{"type":27,"value":1082},"これを 4ツール分用意する必要があります。やり方は2通り考えました。",{"type":21,"tag":1084,"props":1085,"children":1087},"h3",{"id":1086},"案-a単一の-manualtoolslugvue-に統合",[1088,1090,1096],{"type":27,"value":1089},"案 A：単一の ",{"type":21,"tag":68,"props":1091,"children":1093},{"className":1092},[],[1094],{"type":27,"value":1095},"/manual/[tool]/[slug].vue",{"type":27,"value":1097}," に統合",{"type":21,"tag":29,"props":1099,"children":1100},{},[1101,1103,1109,1111,1117],{"type":27,"value":1102},"パラメータ ",{"type":21,"tag":68,"props":1104,"children":1106},{"className":1105},[],[1107],{"type":27,"value":1108},"[tool]",{"type":27,"value":1110}," と ",{"type":21,"tag":68,"props":1112,"children":1114},{"className":1113},[],[1115],{"type":27,"value":1116},"[slug]",{"type":27,"value":1118}," の両方を動的にし、1組の Vue ページで全ツールを賄う案です。コード量は最小になります。",{"type":21,"tag":1084,"props":1120,"children":1122},{"id":1121},"案-bツールごとに-manualtoolslugvue-を複製",[1123,1125,1131],{"type":27,"value":1124},"案 B：ツールごとに ",{"type":21,"tag":68,"props":1126,"children":1128},{"className":1127},[],[1129],{"type":27,"value":1130},"manual/{tool}/[slug].vue",{"type":27,"value":1132}," を複製",{"type":21,"tag":29,"props":1134,"children":1135},{},[1136,1138,1143],{"type":27,"value":1137},"物理的にツール別のディレクトリを掘る案。コードの重複は増えますが、",{"type":21,"tag":51,"props":1139,"children":1140},{},[1141],{"type":27,"value":1142},"ツールごとに違う breadcrumb や OG 画像を素直に書ける",{"type":27,"value":1144}," 利点があります。",{"type":21,"tag":29,"props":1146,"children":1147},{},[1148,1150,1155],{"type":27,"value":1149},"結局、",{"type":21,"tag":51,"props":1151,"children":1152},{},[1153],{"type":27,"value":1154},"案 B",{"type":27,"value":1156}," を採用しました。理由は次の通りです。",{"type":21,"tag":1158,"props":1159,"children":1160},"ul",{},[1161,1166,1171,1183,1188],{"type":21,"tag":988,"props":1162,"children":1163},{},[1164],{"type":27,"value":1165},"各ツールの breadcrumb リンクはツール名も URL も異なる。動的にするとリテラルが増えて読みにくくなる",{"type":21,"tag":988,"props":1167,"children":1168},{},[1169],{"type":27,"value":1170},"OG 画像のパスをツールごとに分けたい場合に、動的分岐が面倒",{"type":21,"tag":988,"props":1172,"children":1173},{},[1174,1176,1181],{"type":27,"value":1175},"PICOM はすでに案 B の形で動いていたため、",{"type":21,"tag":51,"props":1177,"children":1178},{},[1179],{"type":27,"value":1180},"既存コードを壊さず",{"type":27,"value":1182}," 拡張できる",{"type":21,"tag":988,"props":1184,"children":1185},{},[1186],{"type":27,"value":1187},"重複コードは 60 行程度で、複雑な分岐コードよりも読みやすい",{"type":21,"tag":988,"props":1189,"children":1190},{},[1191],{"type":27,"value":1192},"将来的にマニュアルのデザインを製品に合わせるということも行いたい",{"type":21,"tag":29,"props":1194,"children":1195},{},[1196],{"type":27,"value":1197},"複製後のディレクトリ構造はこうなりました。",{"type":21,"tag":197,"props":1199,"children":1201},{"code":1200},"app/pages/manual/\n  ├── picom/\n  │   ├── index.vue\n  │   └── [slug].vue\n  ├── diff/\n  │   ├── index.vue\n  │   └── [slug].vue\n  ├── yominchu/\n  │   ├── index.vue\n  │   └── [slug].vue\n  └── yomogi/\n      ├── index.vue\n      └── [slug].vue\n",[1202],{"type":21,"tag":68,"props":1203,"children":1204},{"__ignoreMap":7},[1205],{"type":27,"value":1200},{"type":21,"tag":29,"props":1207,"children":1208},{},[1209,1211,1223],{"type":27,"value":1210},"コピペ臭はありますが、",{"type":21,"tag":51,"props":1212,"children":1213},{},[1214,1216,1221],{"type":27,"value":1215},"中身の差は ",{"type":21,"tag":68,"props":1217,"children":1219},{"className":1218},[],[1220],{"type":27,"value":1075},{"type":27,"value":1222}," の引数と breadcrumb リンクだけ",{"type":27,"value":1224}," です。読むほうが楽で、保守時の事故も少ないです。\n正直、AIエージェントを利用できる現環境下で、コピペを全力で避ける必要性は薄くなったと感じています。コピペ内容も小規模ですし。",{"type":21,"tag":22,"props":1226,"children":1228},{"id":1227},"ステップ3nuxt-content-側のディレクトリ",[1229],{"type":27,"value":1230},"ステップ3：Nuxt Content 側のディレクトリ",{"type":21,"tag":29,"props":1232,"children":1233},{},[1234,1240],{"type":21,"tag":68,"props":1235,"children":1237},{"className":1236},[],[1238],{"type":27,"value":1239},"content/tool_manuals/",{"type":27,"value":1241}," 配下にもツールごとにディレクトリを掘ります。",{"type":21,"tag":197,"props":1243,"children":1245},{"code":1244},"content/tool_manuals/\n  ├── picom/\n  │   ├── index.md\n  │   ├── getting-started.md\n  │   └── ... (11ファイル)\n  ├── diff/\n  ├── yominchu/\n  └── yomogi/\n",[1246],{"type":21,"tag":68,"props":1247,"children":1248},{"__ignoreMap":7},[1249],{"type":27,"value":1244},{"type":21,"tag":29,"props":1251,"children":1252},{},[1253,1255,1261,1263,1269,1270,1276,1278,1284,1286,1292,1294,1299],{"type":27,"value":1254},"各 ",{"type":21,"tag":68,"props":1256,"children":1258},{"className":1257},[],[1259],{"type":27,"value":1260},".md",{"type":27,"value":1262}," ファイルの frontmatter には ",{"type":21,"tag":68,"props":1264,"children":1266},{"className":1265},[],[1267],{"type":27,"value":1268},"sitemap.loc",{"type":27,"value":1110},{"type":21,"tag":68,"props":1271,"children":1273},{"className":1272},[],[1274],{"type":27,"value":1275},"sitemap.lastmod",{"type":27,"value":1277}," を入れておき、",{"type":21,"tag":68,"props":1279,"children":1281},{"className":1280},[],[1282],{"type":27,"value":1283},"@nuxtjs/sitemap",{"type":27,"value":1285}," が ",{"type":21,"tag":68,"props":1287,"children":1289},{"className":1288},[],[1290],{"type":27,"value":1291},"sitemap.xml",{"type":27,"value":1293}," に自動で流し込む仕組みです。新しいマニュアルを追加する作業は、",{"type":21,"tag":51,"props":1295,"children":1296},{},[1297],{"type":27,"value":1298},"ほぼ Markdown を置くだけ",{"type":27,"value":1300}," に収まります。",{"type":21,"tag":197,"props":1302,"children":1306},{"code":1303,"language":1304,"meta":7,"className":1305,"style":7},"---\ntitle: はじめかた - Yomogi マニュアル\ndescription: Yomogi の初回アクセスから...\ndate: 2026-04-14\nsitemap:\n  loc: \"/manual/yomogi/getting-started\"\n  lastmod: \"2026-04-14\"\n  priority: 0.8\n---\n","yaml","language-yaml shiki shiki-themes vitesse-dark",[1307],{"type":21,"tag":68,"props":1308,"children":1309},{"__ignoreMap":7},[1310,1318,1335,1352,1370,1383,1410,1435,1453],{"type":21,"tag":207,"props":1311,"children":1312},{"class":209,"line":15},[1313],{"type":21,"tag":207,"props":1314,"children":1315},{"style":489},[1316],{"type":27,"value":1317},"---\n",{"type":21,"tag":207,"props":1319,"children":1320},{"class":209,"line":247},[1321,1325,1330],{"type":21,"tag":207,"props":1322,"children":1323},{"style":256},[1324],{"type":27,"value":259},{"type":21,"tag":207,"props":1326,"children":1327},{"style":225},[1328],{"type":27,"value":1329},":",{"type":21,"tag":207,"props":1331,"children":1332},{"style":272},[1333],{"type":27,"value":1334}," はじめかた - Yomogi マニュアル\n",{"type":21,"tag":207,"props":1336,"children":1337},{"class":209,"line":308},[1338,1343,1347],{"type":21,"tag":207,"props":1339,"children":1340},{"style":256},[1341],{"type":27,"value":1342},"description",{"type":21,"tag":207,"props":1344,"children":1345},{"style":225},[1346],{"type":27,"value":1329},{"type":21,"tag":207,"props":1348,"children":1349},{"style":272},[1350],{"type":27,"value":1351}," Yomogi の初回アクセスから...\n",{"type":21,"tag":207,"props":1353,"children":1354},{"class":209,"line":357},[1355,1360,1364],{"type":21,"tag":207,"props":1356,"children":1357},{"style":256},[1358],{"type":27,"value":1359},"date",{"type":21,"tag":207,"props":1361,"children":1362},{"style":225},[1363],{"type":27,"value":1329},{"type":21,"tag":207,"props":1365,"children":1367},{"style":1366},"--shiki-default:#C99076",[1368],{"type":27,"value":1369}," 2026-04-14\n",{"type":21,"tag":207,"props":1371,"children":1372},{"class":209,"line":406},[1373,1378],{"type":21,"tag":207,"props":1374,"children":1375},{"style":256},[1376],{"type":27,"value":1377},"sitemap",{"type":21,"tag":207,"props":1379,"children":1380},{"style":225},[1381],{"type":27,"value":1382},":\n",{"type":21,"tag":207,"props":1384,"children":1385},{"class":209,"line":455},[1386,1391,1395,1400,1405],{"type":21,"tag":207,"props":1387,"children":1388},{"style":256},[1389],{"type":27,"value":1390},"  loc",{"type":21,"tag":207,"props":1392,"children":1393},{"style":225},[1394],{"type":27,"value":1329},{"type":21,"tag":207,"props":1396,"children":1397},{"style":266},[1398],{"type":27,"value":1399}," \"",{"type":21,"tag":207,"props":1401,"children":1402},{"style":272},[1403],{"type":27,"value":1404},"/manual/yomogi/getting-started",{"type":21,"tag":207,"props":1406,"children":1407},{"style":266},[1408],{"type":27,"value":1409},"\"\n",{"type":21,"tag":207,"props":1411,"children":1412},{"class":209,"line":464},[1413,1418,1422,1426,1431],{"type":21,"tag":207,"props":1414,"children":1415},{"style":256},[1416],{"type":27,"value":1417},"  lastmod",{"type":21,"tag":207,"props":1419,"children":1420},{"style":225},[1421],{"type":27,"value":1329},{"type":21,"tag":207,"props":1423,"children":1424},{"style":266},[1425],{"type":27,"value":1399},{"type":21,"tag":207,"props":1427,"children":1428},{"style":272},[1429],{"type":27,"value":1430},"2026-04-14",{"type":21,"tag":207,"props":1432,"children":1433},{"style":266},[1434],{"type":27,"value":1409},{"type":21,"tag":207,"props":1436,"children":1437},{"class":209,"line":474},[1438,1443,1447],{"type":21,"tag":207,"props":1439,"children":1440},{"style":256},[1441],{"type":27,"value":1442},"  priority",{"type":21,"tag":207,"props":1444,"children":1445},{"style":225},[1446],{"type":27,"value":1329},{"type":21,"tag":207,"props":1448,"children":1450},{"style":1449},"--shiki-default:#4C9A91",[1451],{"type":27,"value":1452}," 0.8\n",{"type":21,"tag":207,"props":1454,"children":1455},{"class":209,"line":533},[1456],{"type":21,"tag":207,"props":1457,"children":1458},{"style":489},[1459],{"type":27,"value":1317},{"type":21,"tag":22,"props":1461,"children":1463},{"id":1462},"実際の拡張コスト",[1464],{"type":27,"value":1462},{"type":21,"tag":29,"props":1466,"children":1467},{},[1468],{"type":27,"value":1469},"PICOM マニュアルが既にあった状態から、diff / yominchu / yomogi の3ツール分のマニュアル基盤を整えるのに要したコード作業の内訳はこうです。",{"type":21,"tag":1158,"props":1471,"children":1472},{},[1473,1484,1489],{"type":21,"tag":988,"props":1474,"children":1475},{},[1476,1482],{"type":21,"tag":68,"props":1477,"children":1479},{"className":1478},[],[1480],{"type":27,"value":1481},"useManualNavigation.ts",{"type":27,"value":1483}," への 3 ツール分の sections 追加",{"type":21,"tag":988,"props":1485,"children":1486},{},[1487],{"type":27,"value":1488},"動的ルート Vue ページ 6 ファイルの複製・微修正",{"type":21,"tag":988,"props":1490,"children":1491},{},[1492],{"type":27,"value":1493},"マニュアル Markdown 9 ファイルの執筆・確認",{"type":21,"tag":29,"props":1495,"children":1496},{},[1497,1499,1504,1506,1511],{"type":27,"value":1498},"大半はコード作業ではなく",{"type":21,"tag":51,"props":1500,"children":1501},{},[1502],{"type":27,"value":1503},"文章執筆",{"type":27,"value":1505},"で、これは想定通りです。Nuxt Content v2 の強みは「コンテンツ追加コストを文章執筆そのものに絞れる」点にあります。\nさらに、文章執筆は AI エージェントを活用して下書きを生成できます。つまり、実質的にマニュアルの運用コストは",{"type":21,"tag":51,"props":1507,"children":1508},{},[1509],{"type":27,"value":1510},"内容の確認",{"type":27,"value":1512},"に集中できるということです。",{"type":21,"tag":22,"props":1514,"children":1516},{"id":1515},"まとめ",[1517],{"type":27,"value":1515},{"type":21,"tag":1158,"props":1519,"children":1520},{},[1521,1534,1546,1558],{"type":21,"tag":988,"props":1522,"children":1523},{},[1524,1526,1532],{"type":27,"value":1525},"「1つ目」を作るときは ",{"type":21,"tag":68,"props":1527,"children":1529},{"className":1528},[],[1530],{"type":27,"value":1531},"if toolSlug === 'picom'",{"type":27,"value":1533}," のハードコードで十分。早すぎる抽象化は不要",{"type":21,"tag":988,"props":1535,"children":1536},{},[1537,1539,1544],{"type":27,"value":1538},"「2つ目」を追加する瞬間に、",{"type":21,"tag":51,"props":1540,"children":1541},{},[1542],{"type":27,"value":1543},"辞書化 + ディレクトリ複製",{"type":27,"value":1545}," のリファクタが効く",{"type":21,"tag":988,"props":1547,"children":1548},{},[1549,1551,1556],{"type":27,"value":1550},"Vue ページは DRY より ",{"type":21,"tag":51,"props":1552,"children":1553},{},[1554],{"type":27,"value":1555},"breadcrumb や OG の素直さ",{"type":27,"value":1557}," を優先して複製を選ぶ判断もあり",{"type":21,"tag":988,"props":1559,"children":1560},{},[1561],{"type":27,"value":1562},"Nuxt Content v2 + frontmatter sitemap の組み合わせで、マニュアル追加は純粋な執筆コストに収束する",{"type":21,"tag":29,"props":1564,"children":1565},{},[1566],{"type":27,"value":1567},"「スケールさせる」という言葉はつい大袈裟に捉えがちですが、実際には小さな工夫をしただけに過ぎません。個人開発のマニュアルサイト設計の参考になれば幸いです。",{"type":21,"tag":1569,"props":1570,"children":1571},"style",{},[1572],{"type":27,"value":1573},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":247,"depth":247,"links":1575},[1576,1577,1578,1579,1581,1587,1588,1589],{"id":24,"depth":247,"text":24},{"id":94,"depth":247,"text":94},{"id":179,"depth":247,"text":182},{"id":686,"depth":247,"text":1580},"ステップ1：sectionsByTool レコードへの昇格",{"id":1037,"depth":247,"text":1040,"children":1582},[1583,1585],{"id":1086,"depth":308,"text":1584},"案 A：単一の /manual/[tool]/[slug].vue に統合",{"id":1121,"depth":308,"text":1586},"案 B：ツールごとに manual/{tool}/[slug].vue を複製",{"id":1227,"depth":247,"text":1230},{"id":1462,"depth":247,"text":1462},{"id":1515,"depth":247,"text":1515},"markdown","content:articles:tech:development:nuxt-content-manual-site.md","content","articles/tech/development/nuxt-content-manual-site.md","articles/tech/development/nuxt-content-manual-site","md",1779021349355]