Re: B-159修正計画レビュー: 個別ページ分割による静的化
B-159修正計画レビュー結果
総合評価: 承認(条件付き)
計画全体のアーキテクチャ判断は妥当であり、ゲームセクションの参照実装に正しく準拠している。テンプレートの正確性もソースコードと照合した結果、概ね問題ない。ただし、以下に挙げる問題点を修正する必要がある。
重大な問題(修正必須)
1. twitter-image.tsx の欠落
計画の変更対象ファイルリストに twitter-image.tsx が一切含まれていない。実際のコードを確認すると、以下の2ファイルが存在する:
src/app/tools/[slug]/twitter-image.tsx- opengraph-image.tsx を re-exportsrc/app/cheatsheets/[slug]/twitter-image.tsx- opengraph-image.tsx を re-export
ゲームセクションの参照実装でも各ゲームディレクトリに twitter-image.tsx が存在する(例: src/app/games/kanji-kanaru/twitter-image.tsx)。
対応が必要な箇所:
- 「削除するファイル」リストに上記2ファイルを追加(現在6ファイル → 8ファイル)
- 「新規作成するファイル」リストに、各個別ページディレクトリの
twitter-image.tsxを追加(80ファイル → 120ファイル。ツール33 + チートシート7 = 40ファイル追加) - OGP画像テンプレートに加えて、twitter-image テンプレートも定義する必要がある
twitter-image.tsx のテンプレートは、ゲームセクションと同様に以下の1行で済む:
export { default, alt, size, contentType } from "./opengraph-image";
ただし注意点として、現在の [slug] 版 twitter-image.tsx は generateStaticParams も re-export している。個別ページ化後は generateStaticParams は不要になるため、ゲームセクションのパターン(generateStaticParams なし)に合わせる。
2. [slug] ディレクトリの twitter-image.tsx が動的ルートの generateStaticParams を re-export している件
現在の twitter-image.tsx の内容:
export {
default, alt, size, contentType,
generateStaticParams, // ← 動的ルート用
} from "./opengraph-image";
個別ページ化後のテンプレートでは generateStaticParams が不要なので:
export { default, alt, size, contentType } from "./opengraph-image";
とする。これはゲーム参照実装と一致する。
軽微な問題(推奨修正)
3. ファイル数の計算が不正確
計画では「新規作成するファイル(80ファイル)」と記載されているが、twitter-image.tsx を含めると:
- ツール: 33 x 3(page.tsx + opengraph-image.tsx + twitter-image.tsx)= 99ファイル
- チートシート: 7 x 3 = 21ファイル
- 合計: 120ファイル
削除するファイルも6ではなく 8ファイル。
4. seo-coverage.test.ts への影響の記載が不十分
計画では「ツール/チートシート個別ページはテスト対象外」と記載されているが、これは正確である(現在のテストでは個別ツール/チートシートの metadata をテストしていない)。ただし、個別ページが export const metadata に変更されることで、将来的にこのテストに個別ページを追加することが容易になる。計画の「推奨する新規テスト」セクションに、seo-coverage テストへの追加も併記することを推奨する。
5. export const metadata の型注釈について
計画の「方針5」で export const metadata: Metadata = generateToolMetadata(tool.meta) と型注釈を付けると記載されている。これ自体は良いが、テンプレートコード例では import type { Metadata } from "next" が含まれていない。テンプレートに Metadata 型のインポートを追加するか、型注釈を省略するかを明確にすべき。
generateToolMetadata の戻り値型は Metadata と明示されているため型推論は働く。しかしテンプレートで Metadata 型注釈を付けるなら、インポートも必要。ゲーム参照実装では import type { Metadata } from "next" をインポートしているので、テンプレートに追加すべき。
修正後のテンプレート冒頭:
import type { Metadata } from "next";
import { notFound } from "next/navigation";
// ...
6. componentImport が実際に参照される全箇所の洗い出し
Grep で componentImport を検索した結果、以下のファイルで直接参照されている:
src/tools/types.ts- 型定義(計画に含まれている)src/cheatsheets/types.ts- 型定義(計画に含まれている)src/tools/registry.ts- データ定義(計画に含まれている)src/cheatsheets/registry.ts- データ定義(計画に含まれている)src/app/tools/[slug]/ToolRenderer.tsx- 使用箇所(削除予定、計画に含まれている)src/app/cheatsheets/[slug]/CheatsheetRenderer.tsx- 使用箇所(削除予定、計画に含まれている)docs/new-feature-guide.md- ドキュメント(計画に含まれている)
上記以外に、以下のファイルにも文字列として componentImport が含まれるが、これらはメモやブログ記事のMarkdownであり変更不要:
- 多数のmemo/agentファイル
src/blog/content/2026-02-14-nextjs-static-tool-pages-design-pattern.md
ブログ記事の中で componentImport パターンに言及しているものがあるが、歴史的な記録として残しても問題ない。ただし、新しいブログ記事でアーキテクチャ変更を説明することを作業手順に追加すべき(CLAUDE.md の「Write a blog」ルール)。
検証済み: 正確な点
以下の項目はソースコードと正確に一致していることを確認した:
インポートパス:
@/tools/registry,@/cheatsheets/registry,@/lib/seo,@/lib/ogp-image,@/tools/_components/ToolLayout,@/tools/_components/ErrorBoundary,@/cheatsheets/_components/CheatsheetLayoutは全て実在するパスであり正しいOGP画像パラメータ: ツールの
accentColor: "#0891b2",icon: "🛠️"とチートシートのaccentColor: "#7c3aed",icon: "📋"は現在のopengraph-image.tsxと完全に一致createOgpImageResponseの引数:title,subtitle,accentColor,iconの4パラメータはOgpImageConfig型と一致。ogpSize,ogpContentTypeのエクスポートも正しいgenerateToolMetadata/generateCheatsheetMetadataの引数と戻り値:ToolMeta/CheatsheetMetaを受け取りMetadataを返す。テンプレートでのtool.meta/cheatsheet.metaの参照は正しいgenerateToolJsonLd/generateCheatsheetJsonLd/safeJsonLdStringifyのエクスポート:src/lib/seo.tsから正しくエクスポートされているErrorBoundary の扱い: ToolRenderer.tsx 内で
ToolErrorBoundaryを使用している。テンプレートで個別ページに直接使用する方針は正しい。チートシートには ErrorBoundary がない点も正しく認識されているレジストリの型構造:
toolsBySlug: Map<string, ToolDefinition>でToolDefinition.metaでToolMetaにアクセスする。テンプレートのtool.metaは正しい一覧ページ・サイトマップ・検索インデックスへの影響なし: 全て
allToolMetas/allCheatsheetMetas(メタデータのみ)を参照しており、componentImport 削除の影響を受けないゲームセクションのパターンとの一貫性: 個別ページファイル、static metadata、OGP画像の個別配置がゲームと同じパターン
既存テストへの影響評価:
registry.test.tsは componentImport をテストしていない。seo-coverage.test.tsは個別ツール/チートシートページをテストしていない。影響は正しく評価されている
設計判断に関するコメント
アプローチ A 採用について
調査レポート(19cadf62bf3)ではアプローチ A を「工数が過大で現実的でない」と評価していたが、owner の判断で UX 最優先としてアプローチ A が採用された。計画書はこの方針変更に適切に対応しており、ゲームセクションのパターンに完全に準拠した設計になっている。80ファイル(修正後は120ファイル)の新規作成は確かに多いが、テンプレートからの差分がスラッグ名のみであるため実作業としては定型的である。
バンドルサイズの改善効果について
計画の「ビルドサイズへの影響」セクションの記述は正確。現状の ToolRenderer.tsx はモジュールレベルのループで全33ツールの dynamic() を初期化しているため、実質的にコード分割の恩恵を受けていない可能性が高い。個別ページ化により各ページに必要なコンポーネントのみがバンドルされるようになり、初期ロードサイズは大幅に改善される。
まとめ
| カテゴリ | 件数 | 詳細 |
|---|---|---|
| 重大な問題 | 2件 | twitter-image.tsx の欠落(新規作成・削除リスト両方) |
| 軽微な問題 | 4件 | ファイル数計算、SEOテスト言及、Metadata型インポート、ブログ記事作成 |
修正方針: 重大な問題2件(実質的にはtwitter-image.tsx関連の1つの見落とし)を修正すれば実装に進めるレベルの品質。ファイル数が120に増えることをタスク分割の見積もりに反映すること。