Next.jsでWebサイトを作ったときの違和感
Astroを使い始める前、私はNext.jsでいくつかのWebサイトを実装していました。Next.jsはReactのメタフレームワークとして圧倒的なシェアを持ち、機能も豊富で、技術選定で迷ったらNext.jsを使っておけば問題ない、と考えていました。
ところが実際に「コーポレートサイト」「テキスト主体のページ」「ブログ」といったコンテンツ中心のWebサイトを作ってみると、どうにも噛み合わない感覚が残りました。
構成によっては、ほぼ静的なページでも数百KBのJavaScriptが配信されることがある。API RoutesもMiddlewareもISRも使っていないのに、フレームワーク全体がアプリケーション寄りの機能を前提に設計されているので、静的サイトとして出力するために、デフォルトの機能をオプトアウトする前提で実装する場面がちらほら。
使わない設定を把握するための調査をしているうちに、「そもそもNext.jsを使う意味は何だろう」という気持ちになってきました。
やはりNext.jsはWebアプリケーション寄りのフレームワークで、コンテンツ中心のWebサイトを作るには、ややオーバースペックだと感じるようになりました。
Astroはコンテンツ主導型Webサイトのためのフレームワーク
Webアプリは状態管理・認証・サーバー処理・リアルタイム性など高度なJavaScriptの実装が必要なので、フレームワークの基盤としてJavaScriptありきで設計されます。 一方、コンテンツ配信メインのWebサイトはページの表示速度やSEOなどが大切で、JavaScriptは「必要なUI表現が実装できれば十分」という感覚がしっくり来ます。
この違いを真正面から受け止めて設計されているのが、Astroというフレームワークです。
Astroの公式サイトには、The web framework for content-driven websites(コンテンツ主導型ウェブサイトのためのWebフレームワーク)と書かれています。
マーケティングサイト、ドキュメント、ブログ、ポートフォリオ、コーポレートサイト、ECのブランドサイト、これらがAstroの主戦場と言えるでしょう。
では、具体的にAstroにはどんな機能があるのでしょうか? 設計思想を交えて、私が気に入っているポイントを順に紹介します。
1. 「JavaScriptを送らない」がデフォルト
Astroの最も特徴的な思想は、デフォルトでクライアントJavaScriptをゼロにすることです。
.astroファイルのフロントマターに書いたJavaScriptは、ビルド時にサーバー側で実行されHTMLに変換されます。クライアントにはHTMLだけが届きます。
2. UIライブラリを自由に選べる
クリックやスクロールで動作する動的なUIはどう実装するか?AstroはReact・Vue・Svelte・Solidなど、お好みのUIライブラリをコンポーネント単位で組み込むことが可能です。
これを支えているのがアイランドアーキテクチャという仕組みです。静的なHTMLという「海」の中に、インタラクティブな「島」が浮かんでいるイメージで、Next.jsのように「ページ全体がReactアプリ」という構造ではなく、「ページはHTMLで、必要な部分だけがUIコンポーネントの島」という構造になっています。
インタラクティブなUI部品が必要になったら、その箇所だけclient:*ディレクティブを付けてオプトインします。
---import Counter from '../components/Counter.jsx';---<Counter client:load />client:load(即時ハイドレーション)、client:idle(ページの初期読み込みが終わり、ブラウザが待機状態になったとき)、client:visible(ビューポートに入ったら)、client:media(メディアクエリが一致したら)など、どのタイミングでハイドレーションするかまで宣言的に指定できます。
実用上、1サイトで複数のUIライブラリを混ぜることは稀ですが、「自分の好きなUIライブラリを持ち込める」「フレームワークの将来的な乗り換えが楽」という意味で大きな安心感があります。
3. .astroテンプレート構文が書きやすい
Astro独自の.astro構文も気に入っているポイントです。
---// フロントマター(サーバーサイドJS)import { getCollection } from 'astro:content';const posts = await getCollection('blog');---
<ul> {posts.map(post => <li>{post.data.title}</li>)}</ul>
<style> /* スコープ付きCSS */ ul { padding: 0; }</style>
<script> // クライアントサイドJS console.log('Hello from the browser');</script>ポイントは3つあります。
JSX(TSX)に似た構文で、Next.jsから移行しやすい。{...}の式展開やコンポーネントの書き方はReact経験者なら違和感なく書けます。
HTML・スコープ付きCSS・クライアントサイドJSを1ファイルにまとめられる。VueのSFCやSvelteのように、CSSもJSもページ内に閉じるべき処理をまとめて書けるのが嬉しいですね。
「サーバー側で動くJS」と「クライアントで動くJS」が構文レベルで明確に分かれている。フロントマター(--- で囲まれた部分)に書いたJavaScriptはビルド時に実行され、クライアントには送られないため、配信されるJavaScriptが削減されます。DOMの操作やブラウザイベントに対する処理は<script>タグに書くか、前述のようにUIコンポーネントをclient:*付きで配置します。
テンプレートエンジンとUIライブラリのように、役割を明確に分けている。ここもAstroならではの発想が垣間見えます。
4. Webサイトを作るための機能が揃っている
コンテンツ駆動サイトに特化しているだけあって、Webサイト制作に必要な機能が公式で揃っています。
- Content Collections + Content Layer API: ローカルのMarkdown / MDX / JSON / YAMLをZodスキーマで型安全に扱える仕組み。社員紹介ページの一覧やブログ記事のような、CMSを導入するほどではないが構造化したいコンテンツに最適です。
- 公式のRSS・sitemapパッケージ: 別途ライブラリを探して組む必要がない。
- View Transitions: MPAでありながらSPA風の滑らかなページ遷移を後付けできる。
- Markdown/MDXでのページ作成:
src/pagesに.mdを置けばそのままページになる。
歴史あるNext.jsやNuxt.jsには一歩及ばないかもしれませんが、それでも必要十分なパッケージが揃っている実感があります。Webサイトを作る分には困ることがない、という印象です。
5. ホスティング環境に合わせたアダプタ
アダプタとは、デプロイ先の環境に合わせてAstroの出力を最適化するプラグインです。
Astroは基本的にビルド時に静的HTMLを生成する設計です。生成された成果物は、Cloudflare Pages・Netlify・Vercel・S3 など、静的ホスティングならどこにでも置けます。何なら国産レンタルサーバーも大丈夫! サーバー機能が必要になっても、Node.js・Vercel・Netlify・Cloudflare Workers・Denoなど、アダプタを切り替えればホスティング先を変えられます。
静的HTMLの生成がビルド時に完結する設計なので、ホスティング側の制約を気にせず作れる。これはWebサイト制作で意外と効いてきます。このサイトはホスティング先としてCloudflare Pagesを採用していますが、別環境への移行が必要になっても、コードベースを大きく書き換えずに対応できる安心感があります。
まとめ
紹介した内容はAstroの魅力のほんの一部ですが、伝わったでしょうか?
Next.jsは「Webアプリを作る」ために、多くの強力な機能を内蔵しています。
Astroは「コンテンツ駆動Webサイトを作れる」ことを目指していて、そのために必要なものを揃え、不要なものを削ぎ落とし、Webサイトとしての性能向上や実装体験の良さを追求しています。
それぞれのフレームワークに特長があり、適切な技術選択が必要です。将来的に、Next.jsがパワーアップするかもしれないし、新たなプロダクトが台頭してくるかもしれません。
エンジニアとして、これからもキャッチアップを続けていこうと思います!