Nuxt4移行プロジェクトでコンテンツのHTML化ルールを策定した話
朝、handoffドキュメントを開いた瞬間に積み残しの輪郭が見えてきた。前日のPR #28はまだマージ前で、そこから本番デプロイと converter改修と manifest化が連なっている。「全部やって」と一言投げて、後は判断する側に回った。
午前のセッションが落ち着いたところで、ふとコンテンツ配置に違和感が残った。同じ「純粋な解説テキスト」の章なのに、ある章はVueに置かれていて、別の章はHTMLに切り出されている。バンドルサイズの数字は安全圏に入ったのに、運用ルールが空白のままだった。「中途半端」という言葉が口から漏れた。
午後はその違和感を埋めに行った。ルールを言語化してCLAUDE.mdに書き込み、次セッションへの引き継ぎプロンプトを残した。翌セッションでPhase F-1の実行を試したら、想定外の理由で中止判定が出た。
バンドル削減は終わったのに、運用ルールが残っていた
午前のセッションは、handoffを開いた時点でやることが並んでいた。
- PR #28 のレビュー → squash マージ
- 本番デプロイ(Worker 2.744 MiB / margin 261.7 KiB)
- converterに「変換前の Vue構文検出」を追加
- manifest化(CHAPTERS に
available: trueを追加してimport.meta.globを削除) - 簿記3級ノートのslipsパイロット(CSS namespace化 + HTML化)
- 残り5件を一括HTML化してPR #29 を作ってマージ
PR #29 がマージされた時点で、Worker bundle は 2.670 MiB gzip / margin 337.8 KiB に着地した。Plan Cで予測していた 30〜50 KiB削減を超える -75.7 KiB が出て、marginは Green の領域に押し戻された。
ここで一度ユーザー側が手を止めた。「ぶっちゃけ今のままでもいいんですかね。なんか全体的に中途半端な気がしてて」。
数字の問題は片付いていた。それでも違和感が残っていたのは、ルールが言語化されていなかったからだった。同じ純粋テキスト章でも、PR #29で触った6件はHTMLになり、24件はまだVueに残っている。新しく章を追加するときにどっちを選ぶか、誰も決めていない。
判断軸を言語化する
整理してみると、判断軸は2つしかなかった。
- インタラクティブ教材は Vue — 仕訳エンジン、クイズ、状態を持つUI。コーディングしやすさが上回る
- 純粋な解説テキストは HTML — 静的なテキストと表だけの章。Vueに置くとレンダリングコードがバンドルに乗ってエンドユーザー側で無駄が出る
Vueファイルにテンプレートを書くと、たとえ中身が <p> と <table> だけでも、コンパイル後はレンダリング関数としてWorkerバンドルに積まれていく。静的HTMLで配信すれば、Workerは単にファイルを返すだけで済む。エンドユーザーが解説テキストを読むだけのために、Vueのレンダリング層を経由させる必要はなかった。
ルールが決まった瞬間、過去24件のHTML化が「ルールに揃える後追い」として意味を持ち始めた。ルールがないまま放置すると、また別の章が新しくVueに増えて、永遠に中途半端のままになる。
Vue残置 vs HTML化候補をテーブルに固定する
判断軸が決まったところで、過去のコンテンツを棚卸しした。Explore agentを5並列で派遣して、各カテゴリの中身を分類してもらった。
| カテゴリ | Vue残置(インタラクティブ) | HTML化候補(純粋テキスト) |
|---|---|---|
| 簿記3級ノート | 仕訳エンジン搭載章 | 解説テキスト中心の章(PR #29 で6件着地) |
| 法人税申告書別表 | 計算フォーム付き | 解説章 |
| 宅建 | 過去問インタラクティブ | 解説章(49件 HTML化済み) |
| 財務諸表 | (該当少) | 解説章 2件(Phase F-1候補) |
| Excel解説 | 動的サンプル | 純粋チュートリアル |
このテーブルを Plan E(マスタープラン)の中で固定して、Phase F-1〜F-4に分けた。F-1 は財務諸表の2件、サイズが最小なのでパイロットとして置いた。
CLAUDE.mdとmemoに足跡を残す
ルールはCLAUDE.mdに書き込んだ。ただしルール本文だけ書くと、後から読み返したときに「なぜこう決めたか」が消えてしまう。今回の議論ドキュメントをmemo配下に残して、CLAUDE.mdからは参照を貼る形にした。
## コンテンツの配置ルール(Vue vs HTML)
- インタラクティブ教材(仕訳エンジン・クイズ・状態を持つUI)→ Vue
- 純粋な解説テキスト(静的な文章と表だけ)→ 外部HTML
理由とテーブルは memo/2026-06-18/plan-e-full-html-migration.md を参照。
ルールを覚えておけと自分に言い聞かせるよりも、ファイルに書いてClaude Codeに読み込ませる方が確実だった。次回コンテンツを追加するときに、Claude Code自身が「これは純粋テキストなのでHTMLで」と判断してくれる前提を作った。
Phase F-1は次セッションで中止判定が出た
午前のセッションを締める前に、次セッションへの引き継ぎプロンプトを書いた。「Plan E Phase F-1 を実行する。financial-statements の2件を外部HTML化してPRまで通す」。
午後のセッションでPhase F-1を始めたところ、ゲートチェックで思わぬ事実に当たった。対象の2件は表面的には解説テキストに見えたが、中を開くと useI18n + {{ t('...') }} mustache、slot scope <template #entry-image="{ entry }">、動的component が組み込まれていた。converterは変換前のVue構文検出でこれらを必ずrejectする。
F-2候補の4件も並列で読み直したら、全件 v-for + mustache を使っていて、3件は <Case100ChapterPager> という未登録カスタムコンポーネントまで持っていた。
Phase F-1 は中止、Plan E自体も一旦凍結した。コード変更はゼロ、handoff v13 と plan-e v2 を更新して締めた。
学びメモ
- ルールがない状態は「中途半端」を生み続ける — 数字(Worker bundle margin)が安全圏に入っても、判断軸がなければ次の章で同じ問題が再発する。ルールを言語化してCLAUDE.mdに固定すると、判断のたびに人間が悩む必要がなくなった
- 議論プロセスは別ドキュメントに残してCLAUDE.mdから参照する — ルール本文だけだと「なぜそう決めたか」が抜ける。memo配下に議論を残して参照を貼ると、後から読み返したときに前提が復元できる
- 「純粋テキストに見える」と「実際に純粋テキスト」は別物 — ゲートチェックを通すまで判断を確定させないこと。i18nやslot scopeやmustacheが入っていれば、たとえ表示上は解説テキストでもVueに残すしかない
- 計画と現実がズレたら、コードを動かす前に計画書を凍結する — Phase F-1 中止判定が出た瞬間、コードに手を入れず handoff と plan-e を更新するだけで終わらせた。判断結果を文書化するコストは、間違った実装を巻き戻すコストより小さい
明日以降にやること
- Plan E の見直し: ゲートチェックで通る候補が現実にどれだけあるか、純粋テキスト化の方針を再評価する
- 過去24件のHTML化を諦めるか、別のアプローチ(i18n含む章のHTML化基盤を作る)に切り替えるか判断する
- CLAUDE.mdのルールが新規コンテンツ追加時に実際にワークするか、次の章追加で検証する