[{"data":1,"prerenderedAt":397},["ShallowReactive",2],{"content-/eurekapu-nuxt4-content-html-rules":3,"all-pages-for-dir":395,"og-image-/eurekapu-nuxt4-content-html-rules":396},{"id":4,"title":5,"body":6,"category":377,"description":378,"extension":379,"meta":380,"navigation":233,"ogImage":381,"path":382,"project_name":383,"published":384,"publishedAt":385,"seo":386,"stem":387,"tags":388,"todo":381,"unpublished":384,"updatedAt":381,"__hash__":394},"pages/2026-06/2026-06-18/eurekapu-nuxt4-content-html-rules.md","Nuxt4移行プロジェクトでコンテンツのHTML化ルールを策定した話 - インタラクティブはVue、純粋テキストはHTML",{"type":7,"value":8,"toc":368},"minimark",[9,14,18,21,24,29,32,63,71,74,77,80,83,97,108,111,115,118,196,199,203,206,265,268,272,275,293,304,307,310,336,339,364],[10,11,13],"h1",{"id":12},"nuxt4移行プロジェクトでコンテンツのhtml化ルールを策定した話","Nuxt4移行プロジェクトでコンテンツのHTML化ルールを策定した話",[15,16,17],"p",{},"朝、handoffドキュメントを開いた瞬間に積み残しの輪郭が見えてきた。前日のPR #28はまだマージ前で、そこから本番デプロイと converter改修と manifest化が連なっている。「全部やって」と一言投げて、後は判断する側に回った。",[15,19,20],{},"午前のセッションが落ち着いたところで、ふとコンテンツ配置に違和感が残った。同じ「純粋な解説テキスト」の章なのに、ある章はVueに置かれていて、別の章はHTMLに切り出されている。バンドルサイズの数字は安全圏に入ったのに、運用ルールが空白のままだった。「中途半端」という言葉が口から漏れた。",[15,22,23],{},"午後はその違和感を埋めに行った。ルールを言語化してCLAUDE.mdに書き込み、次セッションへの引き継ぎプロンプトを残した。翌セッションでPhase F-1の実行を試したら、想定外の理由で中止判定が出た。",[25,26,28],"h2",{"id":27},"バンドル削減は終わったのに運用ルールが残っていた","バンドル削減は終わったのに、運用ルールが残っていた",[15,30,31],{},"午前のセッションは、handoffを開いた時点でやることが並んでいた。",[33,34,35,39,42,45,57,60],"ul",{},[36,37,38],"li",{},"PR #28 のレビュー → squash マージ",[36,40,41],{},"本番デプロイ（Worker 2.744 MiB / margin 261.7 KiB）",[36,43,44],{},"converterに「変換前の Vue構文検出」を追加",[36,46,47,48,52,53,56],{},"manifest化（CHAPTERS に ",[49,50,51],"code",{},"available: true"," を追加して ",[49,54,55],{},"import.meta.glob"," を削除）",[36,58,59],{},"簿記3級ノートのslipsパイロット（CSS namespace化 + HTML化）",[36,61,62],{},"残り5件を一括HTML化してPR #29 を作ってマージ",[15,64,65,66,70],{},"PR #29 がマージされた時点で、Worker bundle は ",[67,68,69],"strong",{},"2.670 MiB gzip / margin 337.8 KiB"," に着地した。Plan Cで予測していた 30〜50 KiB削減を超える -75.7 KiB が出て、marginは Green の領域に押し戻された。",[15,72,73],{},"ここで一度ユーザー側が手を止めた。「ぶっちゃけ今のままでもいいんですかね。なんか全体的に中途半端な気がしてて」。",[15,75,76],{},"数字の問題は片付いていた。それでも違和感が残っていたのは、ルールが言語化されていなかったからだった。同じ純粋テキスト章でも、PR #29で触った6件はHTMLになり、24件はまだVueに残っている。新しく章を追加するときにどっちを選ぶか、誰も決めていない。",[25,78,79],{"id":79},"判断軸を言語化する",[15,81,82],{},"整理してみると、判断軸は2つしかなかった。",[33,84,85,91],{},[36,86,87,90],{},[67,88,89],{},"インタラクティブ教材は Vue"," — 仕訳エンジン、クイズ、状態を持つUI。コーディングしやすさが上回る",[36,92,93,96],{},[67,94,95],{},"純粋な解説テキストは HTML"," — 静的なテキストと表だけの章。Vueに置くとレンダリングコードがバンドルに乗ってエンドユーザー側で無駄が出る",[15,98,99,100,103,104,107],{},"Vueファイルにテンプレートを書くと、たとえ中身が ",[49,101,102],{},"\u003Cp>"," と ",[49,105,106],{},"\u003Ctable>"," だけでも、コンパイル後はレンダリング関数としてWorkerバンドルに積まれていく。静的HTMLで配信すれば、Workerは単にファイルを返すだけで済む。エンドユーザーが解説テキストを読むだけのために、Vueのレンダリング層を経由させる必要はなかった。",[15,109,110],{},"ルールが決まった瞬間、過去24件のHTML化が「ルールに揃える後追い」として意味を持ち始めた。ルールがないまま放置すると、また別の章が新しくVueに増えて、永遠に中途半端のままになる。",[25,112,114],{"id":113},"vue残置-vs-html化候補をテーブルに固定する","Vue残置 vs HTML化候補をテーブルに固定する",[15,116,117],{},"判断軸が決まったところで、過去のコンテンツを棚卸しした。Explore agentを5並列で派遣して、各カテゴリの中身を分類してもらった。",[119,120,121,137],"table",{},[122,123,124],"thead",{},[125,126,127,131,134],"tr",{},[128,129,130],"th",{},"カテゴリ",[128,132,133],{},"Vue残置（インタラクティブ）",[128,135,136],{},"HTML化候補（純粋テキスト）",[138,139,140,152,163,174,185],"tbody",{},[125,141,142,146,149],{},[143,144,145],"td",{},"簿記3級ノート",[143,147,148],{},"仕訳エンジン搭載章",[143,150,151],{},"解説テキスト中心の章（PR #29 で6件着地）",[125,153,154,157,160],{},[143,155,156],{},"法人税申告書別表",[143,158,159],{},"計算フォーム付き",[143,161,162],{},"解説章",[125,164,165,168,171],{},[143,166,167],{},"宅建",[143,169,170],{},"過去問インタラクティブ",[143,172,173],{},"解説章（49件 HTML化済み）",[125,175,176,179,182],{},[143,177,178],{},"財務諸表",[143,180,181],{},"（該当少）",[143,183,184],{},"解説章 2件（Phase F-1候補）",[125,186,187,190,193],{},[143,188,189],{},"Excel解説",[143,191,192],{},"動的サンプル",[143,194,195],{},"純粋チュートリアル",[15,197,198],{},"このテーブルを Plan E（マスタープラン）の中で固定して、Phase F-1〜F-4に分けた。F-1 は財務諸表の2件、サイズが最小なのでパイロットとして置いた。",[25,200,202],{"id":201},"claudemdとmemoに足跡を残す","CLAUDE.mdとmemoに足跡を残す",[15,204,205],{},"ルールはCLAUDE.mdに書き込んだ。ただしルール本文だけ書くと、後から読み返したときに「なぜこう決めたか」が消えてしまう。今回の議論ドキュメントをmemo配下に残して、CLAUDE.mdからは参照を貼る形にした。",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-markdown shiki shiki-themes vitesse-light vitesse-light","## コンテンツの配置ルール（Vue vs HTML）\n\n- インタラクティブ教材（仕訳エンジン・クイズ・状態を持つUI）→ Vue\n- 純粋な解説テキスト（静的な文章と表だけ）→ 外部HTML\n\n理由とテーブルは memo/2026-06-18/plan-e-full-html-migration.md を参照。\n","markdown","",[49,214,215,228,235,246,254,259],{"__ignoreMap":212},[216,217,220,224],"span",{"class":218,"line":219},"line",1,[216,221,223],{"class":222},"sFA8A","##",[216,225,227],{"class":226},"syTZV"," コンテンツの配置ルール（Vue vs HTML）\n",[216,229,231],{"class":218,"line":230},2,[216,232,234],{"emptyLinePlaceholder":233},true,"\n",[216,236,238,242],{"class":218,"line":237},3,[216,239,241],{"class":240},"snbK4","-",[216,243,245],{"class":244},"sG7-3"," インタラクティブ教材（仕訳エンジン・クイズ・状態を持つUI）→ Vue\n",[216,247,249,251],{"class":218,"line":248},4,[216,250,241],{"class":240},[216,252,253],{"class":244}," 純粋な解説テキスト（静的な文章と表だけ）→ 外部HTML\n",[216,255,257],{"class":218,"line":256},5,[216,258,234],{"emptyLinePlaceholder":233},[216,260,262],{"class":218,"line":261},6,[216,263,264],{"class":244},"理由とテーブルは memo/2026-06-18/plan-e-full-html-migration.md を参照。\n",[15,266,267],{},"ルールを覚えておけと自分に言い聞かせるよりも、ファイルに書いてClaude Codeに読み込ませる方が確実だった。次回コンテンツを追加するときに、Claude Code自身が「これは純粋テキストなのでHTMLで」と判断してくれる前提を作った。",[25,269,271],{"id":270},"phase-f-1は次セッションで中止判定が出た","Phase F-1は次セッションで中止判定が出た",[15,273,274],{},"午前のセッションを締める前に、次セッションへの引き継ぎプロンプトを書いた。「Plan E Phase F-1 を実行する。financial-statements の2件を外部HTML化してPRまで通す」。",[15,276,277,278,292],{},"午後のセッションでPhase F-1を始めたところ、ゲートチェックで思わぬ事実に当たった。対象の2件は表面的には解説テキストに見えたが、中を開くと ",[67,279,280,283,284,287,288,291],{},[49,281,282],{},"useI18n"," + ",[49,285,286],{},"{{ t('...') }}"," mustache、slot scope ",[49,289,290],{},"\u003Ctemplate #entry-image=\"{ entry }\">","、動的component"," が組み込まれていた。converterは変換前のVue構文検出でこれらを必ずrejectする。",[15,294,295,296,299,300,303],{},"F-2候補の4件も並列で読み直したら、全件 ",[49,297,298],{},"v-for + mustache"," を使っていて、3件は ",[49,301,302],{},"\u003CCase100ChapterPager>"," という未登録カスタムコンポーネントまで持っていた。",[15,305,306],{},"Phase F-1 は中止、Plan E自体も一旦凍結した。コード変更はゼロ、handoff v13 と plan-e v2 を更新して締めた。",[25,308,309],{"id":309},"学びメモ",[33,311,312,318,324,330],{},[36,313,314,317],{},[67,315,316],{},"ルールがない状態は「中途半端」を生み続ける"," — 数字（Worker bundle margin）が安全圏に入っても、判断軸がなければ次の章で同じ問題が再発する。ルールを言語化してCLAUDE.mdに固定すると、判断のたびに人間が悩む必要がなくなった",[36,319,320,323],{},[67,321,322],{},"議論プロセスは別ドキュメントに残してCLAUDE.mdから参照する"," — ルール本文だけだと「なぜそう決めたか」が抜ける。memo配下に議論を残して参照を貼ると、後から読み返したときに前提が復元できる",[36,325,326,329],{},[67,327,328],{},"「純粋テキストに見える」と「実際に純粋テキスト」は別物"," — ゲートチェックを通すまで判断を確定させないこと。i18nやslot scopeやmustacheが入っていれば、たとえ表示上は解説テキストでもVueに残すしかない",[36,331,332,335],{},[67,333,334],{},"計画と現実がズレたら、コードを動かす前に計画書を凍結する"," — Phase F-1 中止判定が出た瞬間、コードに手を入れず handoff と plan-e を更新するだけで終わらせた。判断結果を文書化するコストは、間違った実装を巻き戻すコストより小さい",[25,337,338],{"id":338},"明日以降にやること",[33,340,343,352,358],{"className":341},[342],"contains-task-list",[36,344,347,351],{"className":345},[346],"task-list-item",[348,349],"input",{"disabled":233,"type":350},"checkbox"," Plan E の見直し: ゲートチェックで通る候補が現実にどれだけあるか、純粋テキスト化の方針を再評価する",[36,353,355,357],{"className":354},[346],[348,356],{"disabled":233,"type":350}," 過去24件のHTML化を諦めるか、別のアプローチ（i18n含む章のHTML化基盤を作る）に切り替えるか判断する",[36,359,361,363],{"className":360},[346],[348,362],{"disabled":233,"type":350}," CLAUDE.mdのルールが新規コンテンツ追加時に実際にワークするか、次の章追加で検証する",[365,366,367],"style",{},"html pre.shiki code .sFA8A, html code.shiki .sFA8A{--shiki-default:#999999;--shiki-default-font-weight:bold;--shiki-dark:#999999;--shiki-dark-font-weight:bold}html pre.shiki code .syTZV, html code.shiki .syTZV{--shiki-default:#1C6B48;--shiki-default-font-weight:bold;--shiki-dark:#1C6B48;--shiki-dark-font-weight:bold}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":212,"searchDepth":230,"depth":230,"links":369},[370,371,372,373,374,375,376],{"id":27,"depth":230,"text":28},{"id":79,"depth":230,"text":79},{"id":113,"depth":230,"text":114},{"id":201,"depth":230,"text":202},{"id":270,"depth":230,"text":271},{"id":309,"depth":230,"text":309},{"id":338,"depth":230,"text":338},"dev","Eurekapu Nuxt4移行のPlan E Phase F-1で2件のVueをHTML化してPRをマージした。並行して「インタラクティブ教材はVue、純粋な解説テキストはHTML」というコンテンツ配置ルールをCLAUDE.mdに固定した記録。","md",{},null,"/eurekapu-nuxt4-content-html-rules","eurekapu-nuxt4",false,"2026-06-18T00:00:00.000Z",{"title":5,"description":378},"2026-06/2026-06-18/eurekapu-nuxt4-content-html-rules",[389,390,391,392,393],"Nuxt4","Cloudflare Pages","コンテンツ運用","バンドルサイズ","CLAUDE.md","Zwlc6m5mH9tY3xK6B2ceN-GxEn2nLbI1a7hRJOo7anU",[],"https://log.eurekapu.com/og/blog/eurekapu-nuxt4-content-html-rules.png?v=2026-06-18T00%3A00%3A00.000Z&title=Nuxt4%E7%A7%BB%E8%A1%8C%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A7%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AEHTML%E5%8C%96%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E7%AD%96%E5%AE%9A%E3%81%97%E3%81%9F%E8%A9%B1%20-%20%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%81%AFVue%E3%80%81%E7%B4%94%E7%B2%8B%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AFHTML&author=Kei%20Komatsu&sig=1ea4687083148be1",1782176330354]