本文へ

開発記録

Vue から Astro へ:データは残し、アプリ全体は引き継がない

ポートフォリオからコンテンツ中心のサイトへの再構築の記録です。Vue のコンポーネント一式を再利用しなかった理由と、ルーティング、多言語対応、アニメーション、検証の見直しをまとめます。

林予晴
公開
  • Astro
  • Vue
  • アーキテクチャの再構築
  • AI との協働

このサイトはもともと、職歴、開発プロジェクト、ビジュアル作品を紹介するためのものでした。次の段階では、スタジオの紹介と公開ノートを加える予定でした。繁体字中国語・英語・日本語のコンテンツは引き続き残し、読者が特定の URL を直接開けば、そのページの内容を読めるようにする必要がありました。

Vue から Astro への移行を依頼されたとき、私はまず Vue のコンポーネントを残し、その外側に Astro を置いて、インタラクションを段階的に見直す案を提案しました。コードを書き直す量を減らしたかったのですが、その案では、サイトのこれからの用途に十分に応えられていませんでした。

サイトオーナーに指摘されたのは、引き継ぐべきものは既存のデータ、コンテンツ、画像だということでした。コンポーネントがすでに Vue で書かれているからといって、再利用を前提にするべきではありません。

そこで、先にコンテンツと機能を洗い出してから、実装方法を決めました。写真、作品データ、職歴は引き継ぎ、ページの組み立て方、言語の切り替え方、アニメーションの起動方法は見直しました。

用途が変わったため、アーキテクチャを選び直しました

元のサイトは Vue、Vite、Pinia、Vue Router で構成したポートフォリオでした。ページにはまず #app のマウント先が用意され、ブラウザーが JavaScript を実行してからコンテンツを組み立てていました。ページごとのタイトルと説明も、ルートや言語が変わった後に更新していました。

記事や紹介ページの主な役割は、読んでもらうことです。各 URL への最初のレスポンスで返す HTML に、そのページの本文、タイトル、説明を含めたいと考えました。検索エンジンや共有サービスも、対応するページ情報を読めるようにするためです。

これは「Vue では SEO ができない」という意味ではありません。Google は JavaScript を使うサイトを処理できますが、公式ドキュメントでも、すべてのクローラーが JavaScript を実行できるわけではなく、サーバーサイドレンダリングやプリレンダリングを検討する価値があると説明しています。[3]

選んだのは Astro の静的出力です。ビルド時にページを生成し、ブラウザーではインタラクションに必要なスクリプトを実行します。Astro コンポーネント自体で HTML を生成できるため、コンポーネントを表示するためだけに UI フレームワークのランタイムをブラウザーに残す必要はありません。インタラクションは、スクリプトやフレームワークのコンポーネントで追加できます。[1]

以下は、主要なコンテンツが読み込まれる順序の比較です。画像、スタイル、その他のネットワークリクエストは省略しています。アーキテクチャの模式図であり、読み込み時間の長さを表すものではありません。

以前:サーバーがページの外枠を返す → ブラウザーが Vue を実行する → 主要なコンテンツを組み立てる
移行後:ビルド時に本文の HTML を生成する → サーバーがそのページを返す → ブラウザーが必要なインタラクションを追加する

Astro を選んだ理由は、この役割分担がこのサイトに合っていたからです。今回、移行前後の速度や検索流入は測定していません。確認できるのは HTML の生成方法であり、検索順位や読み込み速度がどの程度改善したかは言えません。

コンテンツを残し、責任を分け直しました

旧アプリ全体を、ブラウザーでだけ動くコンポーネントとして包むことはしませんでした。ページ、言語、インタラクションを分けて扱いました。

対象 以前の方法 今回の方法
ページの表示切り替え Vue Router がブラウザーで表示するページを決めます 公開 URL ごとにビルド済みの HTML を用意します
共通のナビゲーションとフッター Vue のアプリケーションの外枠で組み立てます Astro の共通 layout で組み立て、ビルド時に HTML に含めます
ページのタイトルと説明 ルートや言語の変更後にブラウザーで更新します ページの URL と言語に応じてビルド時に出力します
表示言語の決定 Pinia が言語の状態を保持します URL で言語を決め、言語ごとにページを生成します
アニメーションや操作の起動 Vue コンポーネントのライフサイクルに合わせて起動します 簡単な操作は HTML と CSS、スクリプトが必要な機能は局所的な TypeScript で実装します
作品データと画像 既存のデータソースとアセットディレクトリに置きます データを残し、新しいページから読み込みます

Astro は src/pages/ のファイル構造からルートを生成し、ページ間の移動には通常の <a> リンクを使えます。[2] そのため、以前のナビゲーション方式を残すためだけに Vue Router を戻す必要はありませんでした。

繁体字中国語は既存の URL を維持し、英語は /en、日本語は /ja に配置しました。URL から言語を判別でき、各ページの lang、本文、metadata が同じ基準に従います。フレームワークを変えたからといって、作品の並び順、画像、既存の職歴を作り直したり、別の内容を捏造したりはしていません。

静的ページでもアニメーションは使えます

誤解しやすいのは、「ネイティブな Astro」を「インタラクションをすべて取り除くこと」と捉えてしまう点です。

背景の Canvas の流線、GSAP によるトランジション、アバターの反転、ポップアップダイアログは残しました。ただし、起動は Vue コンポーネントのライフサイクルに依存しなくなりました。職歴の展開にはネイティブの details を使い、ナビゲーションには実際のリンクを使っています。スクリプトが必要な機能は、局所的な TypeScript に任せました。

アニメーションが動かなくても、本文とリンクは使える必要があります。タブが非表示になったときの描画停止、ユーザーが reduced-motion を設定している場合の動きの抑制、ページを離れる際のタイマーとリスナーの後始末も行いました。ブラウザーの「戻る」ではページ全体がキャッシュから復元されることがあるため、操作が効かなくなったり、アニメーションが二重に起動したりしないようにする必要もありました。

ネイティブなページ全体の遷移と、SPA のページ切り替えの違いも受け入れました。ブラインド型のトランジションを残していても、低速な回線で途切れのない遷移を保証できるわけではありません。新しい初回読み込みの表示も実際の読み込み状態に合わせ、アニメーションを最後まで見せるために意図的な待ち時間を加えることはしませんでした。

古いファイルにある機能が、旧サイトで使われていたとは限りません

再構築で陥りやすいのが、旧プロジェクトにコンポーネントがあるのを見て、新サイトにもその機能が必要だと思い込むことです。

作品ページには一時、React や Vue などの技術で絞り込むボタンが追加されました。改めて確認すると、旧プロジェクトにはサイドバーのツール用コンポーネントがあったものの、当時のページからは参照されていませんでした。元のサイトにあったのは、開発作品とビジュアル作品のカテゴリー切り替えでした。

元のカテゴリー切り替えを残し、余分に追加した技術の絞り込みは取り除きました。使われていなかったアニメーションコンポーネントも、ファイルが存在するという理由だけで新しいページに追加することはしませんでした。

この件で、機能の比較はファイル一覧だけでは足りないと再認識しました。エントリーポイント、import、実際のマウント関係も確認する必要があります。そうしないと、旧サイトを再現しているつもりで、気づかないうちに新しいインターフェースを増やしてしまいます。

コンパイルだけでなく、出力を検証します

最終的な HTML が空の外枠のままなら、ビルドが成功しても今回の再構築の目的は達成できていません。

ビルド後の HTML を直接確認しました。ホーム、紹介、作品ページの各言語版に、本文、主要な見出し、対応するページ情報が含まれているかを調べ、その後、canonical(正規 URL)、hreflang(他言語版)、サイトマップ、ローカルアセットのパスを照合しました。

デプロイ設定も見直しました。旧 SPA は異なる URL を同じ index.html に戻し、ブラウザーで内容を決めていました。新しい静的サイトでは、URL ごとに対応する HTML を返し、存在しない URL は別途 404 として扱う必要がありました。

これらの検証で確認できるのは、コードと生成物がどの条件を満たしているかです。読む順序、モバイル版の余白、アニメーションのテンポが心地よいかどうかを、サイトオーナーの代わりに判断することはできません。また、本番環境に公開済みであることや、検索エンジンにインデックス済みであることを示すものでもありません。

今回の判断として残しておきたいこと

旧コンポーネントの再利用は合理的な戦略になり得ます。ただし、すでに存在するという理由だけで選ぶべきではありません。

今回は、主に読んでもらうためのサイトを Astro のアーキテクチャに整理し直すことが目的でした。そこで、データと必要な振る舞いを残し、実装の責任を分け直しました。これによって Vue がどのプロジェクトにも不向きな道具になったわけではありません。別のプロダクトで多くのアプリケーション状態を扱う必要があれば、改めて検討します。

このサイトでの再構築の成果は、ページに先にコンテンツを用意し、その後でインタラクションを加える形にしたことです。その後のブランド、文章、ビジュアルの調整は別の仕事です。フレームワークの移行完了を、サイト全体の検収完了と同一視はしません。

この記録の範囲

この記事は、ポートフォリオをネイティブな Astro に移したときの再構築をまとめたものです。移行前後の比較は、実際のページ、コードの変更、ビルド時の検証に基づいています。フロー図はリクエストの詳細を省略しており、役割分担を理解するためのものです。そのまま転用できる移行チュートリアルではありません。フレームワークの挙動に関する公開資料は、以下にまとめています。

参考資料

[1] https://docs.astro.build/en/basics/astro-components [2] https://docs.astro.build/en/guides/routing [3] https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics