開発記録
Vue SPA を Astro のルートに分けた後、責務をどう振り分けるか
作品ページと記事ページをたどり、ルート、layout、コンテンツの規則、ブラウザーのスクリプトが何を決めるのかを整理します。SPA を外した後に、別の巨大なコンポーネントへ責務を集め直さないための記録です。
- Astro
- アーキテクチャのリファクタリング
- 責務の分担
- プログレッシブエンハンスメント
Vue SPA から Astro に移っても、アプリケーションが担っていた仕事は残ります。URL からコンテンツにたどり着けること、ページにタイトルとナビゲーションがあること、作品に表示順があること、操作にコントロールが応答することは、引き続き必要です。Router とグローバルな状態を取り除くのは、実装方法を一つ外すことにすぎません。その責務を誰に渡すかは、まだ決まっていません。
このサイトでは、それらを分けました。URL はネイティブなページが受け持ち、共通の外枠は layout が組み立て、コンテンツの選択は専用のデータ規則に従い、ブラウザーのスクリプトは局所的な操作を担当します。私が重視するのは、ディレクトリが整って見えることよりも、一つの規則を変えたとき、どの出力に影響するかを把握できることです。
作り直す前の棚卸しでは、どの要件を残すかを考えました。この記事ではその次に進み、残すと決めた責務を実装のどこに置くかを説明します。
最初に届くページと、ページを開いた後の動作を分けます
作品のタイトル、紹介、画像、外部リンクは、読者が受け取る HTML に含まれているべきです。一方、カテゴリの切り替え、メイソンリーレイアウト、アニメーションには、ブラウザーで動くスクリプトが必要になる場合があります。同じ画面にあるからといって、同じ実行時の状態でまとめて管理する必要はありません。
次の表は、原文が記録した 2026 年 10 月 12 日時点の実装における責務の概要です。Astro がすべてのプロジェクトに要求する構成ではありません。
| 層 | 決めること | 一緒に引き受けるべきではないこと |
|---|---|---|
| ルートのページ | その URL で使う言語、レイアウト、コンテンツと、動的ルートで生成するページ | 各カードの表示の細部や、すべてのコントロールの状態 |
| 共通の layout | HTML の外枠、metadata、ナビゲーション、フッター、記事に共通する構造 | すべてのページのデータ選択や業務上の規則 |
| コンテンツとデータの規則 | 作品の順序、記事の識別、公開条件、クエリの結果 | DOM イベント、スクロール位置、フォーカス |
| コンテンツのコンポーネント | 渡された言語、データ、文言から読みやすい内容を組み立てること | 公開条件やサイト全体のナビゲーション規則を独自に書き換えること |
| ブラウザーのスクリプト | 局所的な操作への応答、レイアウトの更新、関連リソースのライフサイクル | ページを開いてから主要な本文を追加することや、サイト全体のルーティングを作り直すこと |
Astro の公式ドキュメントでは、layout は再利用できる UI 構造を提供する Astro コンポーネントであり、特別なアプリケーションコンテナーではないと説明されています。[1] この区別があるため、新しい layout の中に、全ページを管理する App を作り直さずに済みます。
作品ページで責務の流れをたどります
このサイトの繁体字中国語版の作品 URL は /about/work です。ここでは繁体字中国語版のルート例として示しています。ルートのページが繁体字中国語を選び、作品のコンテンツコンポーネントを共通の外枠に入れます。作品コンポーネントは、並べ替え済みのプロジェクトデータを読み、既存の除外条件を適用してカードを出力します。
データ層の順序と、ページで表示する範囲は分けて考える必要があります。並べ替え済みのデータには、公開表示していない項目もあります。同じデータに入っているからといって、ルートのページですべてを並べてよいわけではありません。ルートは自分が作品ページだと分かっていても、公開内容を決め直す責務までは持ちません。
カードにも固有の責務があります。言語に応じたタイトルを選び、日付と画像を表示し、データにソースコードへの入口がある場合にだけ、そのリンクを表示します。こうした表示条件を、サイト全体の store にする必要はありません。
この段階で、読者はすでに HTML から作品を読めます。その後のスクリプトが、開発とデザインの二つのセクションの切り替えや、カードの配置を処理します。最初のカードを表示するために、作品データを再取得する必要はありません。
記事にはコンテンツの規則が増えますが、ルートが独自に規則を作る必要はありません
作品ページは固定の入口ですが、記事の URL はコンテンツに基づいて生成する必要があります。このサイトの正式な記事ルートは getPublishedNotes() から公開対象の集合を取得し、言語で記事を選び、slug でパスを作り、stableId で同じ記事の翻訳を探します。
ここには、意図して残した境界があります。ルートはどのクエリ結果からページを生成するかを決めますが、何を公開可能とするかは共通のコンテンツ規則が判断します。各ルートで draft と日付の条件を書き直すことはしません。
記事を取得した後は、記事用の layout が本文をレンダリングし、著者と日付を組み合わせ、本文の見出しから目次を作ります。記事の metadata と、実際に存在する翻訳への入口は、サイト用の layout に渡します。サイト用の layout は、lang、canonical、hreflang、共通のナビゲーションを出力します。
つまり、記事を公開するか、記事をどう読めるようにするか、ページが自分の URL をどう示すかは、つながっていても異なる問題です。整合したデータは必要ですが、すべてを同じコンポーネントに詰め込む必要はありません。
公開条件の契約全体については、共通の公開クエリを参照してください。ここでは、その契約を責務全体の流れの中に位置づけています。
ブラウザーのスクリプトが受け持つのは操作であり、ページの識別ではありません
2026 年 10 月 12 日時点で記録された実装では、作品の切り替えに #development と #design を使っていました。ネイティブなリンクで識別できる移動先を残し、その後でスクリプトが hash を読み、表示するセクションと選択状態を調整します。言語と記事の識別は、引き続き URL とビルド時のデータで決まり、カテゴリを切り替えても変わりません。
この構成では、JavaScript がない状態にも具体的な意味があります。作品の二つのセクションはすでに HTML にあるため、読者は読み進めたり、ネイティブなリンクを使ったりできます。ただし、スクリプトによる切り替えや配置の効果はありません。「スクリプトなしでも読める」を、「すべての操作がスクリプトなしでもまったく同じ」と言い換えてはいけません。
Astro の公式ドキュメントでは、コンポーネント内の <script> と addEventListener で操作を処理でき、イベントを登録するためだけに UI framework を導入する必要はないと説明されています。[2] ただし、ネイティブなイベントを使うだけで、クリーンアップや復元まで自動的に処理されるわけではありません。このサイトの作品スクリプトでも、実行待ちのアニメーション、ResizeObserver、listeners を管理する必要があります。ページから離れる経路と、BFCache から復元する経路にも、それぞれ責務を残す必要があります。
この記事は、コードを根拠に分担を説明しています。コードを読んで確認したクリーンアップの分岐を、すべてのブラウザーライフサイクルを実測した証拠としては扱いません。
外枠を共通化しても、すべての判断を共通化するわけではありません
各ページの違いを長い条件列にして layout に集めれば、見かけ上はファイル数を減らせます。しかし、記事の追加、作品の表示範囲の変更、タイトルの変更でさえ、同じ巨大なコンポーネントを触ることになりかねません。
私は、その規則が何を理由に変わるかで置き場所を判断します。記事の公開条件はコンテンツの契約によって変わります。カードの外観はインターフェースの設計によって変わります。サイトの metadata の出力には共通の形式があります。変更理由が異なるものを、「共通」という言葉だけで無理にまとめる必要はありません。
共通化は、層をまたぐクエリを禁止することでもありません。このサイトの記事用 layout は、関連記事として同じ言語の正式な記事を取得します。大切なのは、公開対象の集合を再利用し、関連コンテンツを表示するついでに別の公開条件を作らないことです。
変更時は、ファイルが属する層だけでなく出力まで追います
次は、この責務の分担から整理した確認方法です。この記事で扱う作業中に新たに得たテスト結果ではありません。
- 作品データや除外条件を変えたら、データファイルを import できるかだけでなく、カードの内容、数、順序を読み返します。
- 記事の公開条件を変えたら、ホーム、一覧、記事ルート、関連記事、sitemap をまとめて照合し、古い条件を使い続ける出口がないか確認します。
- layout の metadata を変えたら、ブラウザーのスクリプト実行後にタイトルが正しく見えるかだけでなく、影響する言語の実際の HTML を確認します。
- 操作スクリプトを変えたら、操作後の状態に加え、初期 HTML とスクリプトなしでの読みやすさを確認します。また、作成したアニメーションや listeners をどう停止、再開するかも確かめます。
責務を分けた後こそ、確認をそのファイルだけで止めることはできません。規則には固有の出所があり、影響はデータを通ってページまで届きます。両方を見て初めて、変更が実際の使用箇所につながったか判断できます。
この記録の範囲
この記事は、2026 年 10 月 12 日時点で記録された、このサイトの作品ルート、サイト用と記事用の layout、作品コンポーネントとスクリプト、公開記事クエリをもとにしています。ネイティブな Astro 静的サイトの責務分担を説明するもので、ログイン、リモートデータの操作、データベースのトランザクションは扱いません。大量のリアルタイム状態を共有するアプリケーションも、すべて UI framework を外すべきだとは主張していません。
この分担は、性能、SEO、すべての端末への対応、正式なデプロイの証明ではありません。フレームワークの選択については、Vue から Astro への移行記録を参照してください。見える振る舞いをすべて残せたかどうかは、対応する出力と操作の検証で確かめる必要があります。
参照資料
[1] https://docs.astro.build/en/basics/layouts [2] https://docs.astro.build/en/guides/client-side-scripts