この記事の内容は、あくまでも私個人の意見や好みの話です。一意見としてお聞きいただければ幸いです。また、時節が変わるにつれて私個人の好みも変わっていくことがありますので、その点は悪しからず。
AstroというWebフロントエンドのフレームワークをご存知でしょうか。自分も最近知って使うようになり、とても気に入ってしまったので、その紹介をしていきたいと思います。
Astroを知る前
Webフロントエンドのフレームワークといえば皆さんは何を思いつきますか。Vue, React, Svelteなどなどいろいろとあるかと思います。私も最近はほとんどReactを使って開発をしていました。
ただそんな中で感じていたのは、ちょっとした静的なページを作りたいときに、React使うのは重たいなぁといった感覚です。APIと頻繁にデータをやり取りするだとか、ログイン機能があるだとか、そういう所謂WebアプリであればReactで実装するのはやりやすいです。でも、たとえばブログとかポートフォリオとか、そういった静的ページを作りたいだけなのにReactのSPAが必要かと言われるとうーん、と思います。
でもだからって、バニラのHTMLやJSを使うかと言われるとそれも不便です。不便だからReactに逃げてきた訳です。
どんな機能が欲しかったのか
じゃあどんな機能が欲しいのか、Reactほどリッチではなくていいけど、バニラのHTMLとJSで物足りないことは何なんでしょうか。私にとっての答えは主に下の2つでした。
- コンポーネントの概念
- JSXのようなテンプレートエンジン
サイトで使うヘッダーだとかボタンだとか、そういった部品をコンポーネントとして分けて実装し、責務を分離したり再利用可能にしたりするというのは、最近のWeb開発では一般的なことなのかなと思います。Reactのようなフレームワークだとやっぱりそれができるのが一番嬉しいです。同じコードを繰り返し書く手間が省けます。修正があっても1箇所で済みます。
バニラのHTMLにもWeb Componentsという概念があることは聞いたことがありました。ただ、あまり一般的ではない印象ですし、その分学習コストや参考になるドキュメントも少ないのかなーと感じてしまいます…。
次のJSXというのはReactでも利用されていることで有名ですね。HTMLライクにタグを書いていき、一部でJSの式や値を参照できるという記法です。たとえば以下みたいにすれば、JSの変数name
がHTMLの中に展開されてレンダリングされます。
var name = "mochi";
return (
<div>
<p>{name}</p>
</div>
);
JSの文法さえ分かればfor文で要素を繰り返し表示したり、Array.map()
で配列をリストとして表示したりといったことも容易に行えます。大学の授業でバニラのJSのgetElementById()
みたいなDOM操作を習いましたが、JSXの方が圧倒的に楽です…。
特に最近のIDEなら補完が効くのも嬉しい点です。JSのstring型でHTMLをいっぱい書いて、element.innerHTMLに代入するとかにはもう戻れない気がします。
「JSの文法さえ分かれば」というのを強調しているのは、Vueのv-for
のような独自の書き方を意識してのことです。私も初めはVueを使っていましたが、Vueだけでしか使えないv-for
のような独自の書き方を学ぶのが、他に応用することができず少々面倒くさいなーと感じてしまいました。
ReactにもuseState
とかuseEffect
とか特有の機能はありますが、基本的なことはHTML/CSS/JSと似た書き方で扱えます。これは、初めのハードルとして低いのかなと思っています。
そんなこんなでコンポーネントとJSXが良くて最近はReactを使うことが多かった訳ですが、それでも静的サイトを作るには少しリッチすぎると感じてしまいます。
先ほどもあげたuseState
とかuseEffect
とかのような機能は、静的サイトじゃまず使いません。ルーティングを設定するのにもたとえばreact-router-dom
で設定して、生成されたものはSPAの形になります。そこまでは要らないんだけどなぁー。
Reactみたいなコンポーネントとかテンプレートエンジンが使えて、シンプルに静的サイト作れるフレームワーク。そんな都合の良いものないかなー。
Astroがありました
ありました。Astroというものです。たとえばJSXのような以下のような書き方ができます。また、以下の要素をコンポーネントとして使い回すこともできます。もちろんコンポーネントのpropsなども設定可能です。それが非常にシンプルなHTML/JS/CSSっぽい書き方で書けています。これに出会って開発してみると、「あぁ、僕が求めていたものはこれだ」なんて気持ちになりました。
---
const name = "mochi"
---
<div>
<p>{name}</p>
</div>
<style>
p {
color: red;
}
</style>
詳細なドキュメントは公式サイトに投げますが、いくつか特に好きな点を挙げておきます。
Content-driven
という設計思想
設計思想として、ログインなどの伴うWebアプリケーションを構築するフレームワークではなく、コンテンツが主体のブログのようなWebサイトを構築するフレームワークであるとしています。もう、まさに自分の求めていたものでした。
ファイルベースのルーティング
Next.jsのApp Routerを使ったことのある方にはお馴染みのファイルベースのルーティングになっています。src/pages/
ディレクトリ以下のファイルがURLのパスにそのまま対応します。src/pages/photo.astro
というファイルがあれば、URLの/photo
にレンダリングされます。
react-router-dom
のような設定方法だと、ページが増えるたびにルータの設定も修正する必要があるなど面倒だなーと思っていました。このファイルベースのルーティングであれば、そうした追加の設定などが不要になり便利だなと思っています。
Vueの単一ファイルコンポーネントのような書き方とスタイルのスコープ
先ほど挙げたAstroのコンポーネントのサンプルを見て、Vueの単一ファイルコンポーネントのようだと感じた方もいるかと思います。自分がAstroで開発する時は、このようにスクリプト部、HTML部、スタイル部と分けて記述をしています。昔Vueを書いていた名残りかもしれません…。ただ、こうすることで、この1つのファイル内にそのコンポーネントの実装が集約されるというのは嬉しいなと感じる点です。
ここでのスクリプト部に書かれた処理は、ビルド時に1度だけ実行されます。毎回のページ表示時にクライアント側で実行されるものではないことにご注意ください。 参考
また、この例では<style>
タグを使って<p>
要素のスタイルを指定しています。このとき、このスタイルはこのコンポーネント内のみのスコープになります。すなわち、ここでcolor: red;
と設定していても、他のコンポーネントの<p>
タグでは普通の色で表示されます。このように意識せずにスタイルのスコープを制限できるという機能は非常に嬉しいなと思っています。
---
const name = "mochi"
---
<div>
<p>{name}</p>
</div>
<style>
p {
color: red;
}
</style>
Reactのコンポーネントを再利用したり、Markdownをそのままページとしてレンダリングできたりする
今までReactなどで作ってきたコンポーネントがある場合、それをそのまま再利用することが可能です。こうしたReactのコンポーネントであれば、クライアント側で実行される処理をスクリプトとして書くことも可能です。React以外にもSvelteやVueなどのフレームワークも公式で対応されています。
Markdownのファイルをそのままページとして表示することができます。また、Markdown用のレイアウトを作って、それを適用してページを表示するといったことも可能です。たとえばこのQiitaの記事も Markdownで書いていますが、それをそのままフォルダに置けばブログ記事のように表示されますよ言われれば、非常に便利です。
おわりに
そんなこんなでAstroの紹介をしてきました。ぜひ皆さんも、一度お使いになってみてはと思います。よいAstroライフを👋
参考