Astro.jsのチュートリアルとテーマ触った所感


## 概要
この記事は[watnowアドベントカレンダー](https://qiita.com/advent-calendar/2023/watnow-calendar)の23日目です。

就活のために自己紹介サイトを制作しようと思い、パフォーマンスに優れるとのことでAstro.jsというSSGフレームワークを調査した時に感じた点を断片的に記載します。

https://astro.build/

実際に行ったこととして[公式チュートリアル](https://docs.astro.build/ja/tutorial/0-introduction/)を一通りこなし、配布されているテンプレートを自分用にカスタマイズしている途中です。

また、僕自身JSフレームワークが本業ではなくAstro.jsも初心者ですので誤った情報や不適切な表現がある場合はお伝え頂けると幸いです。

### 記事の対象者
JavaScriptアプリケーションに入門したばかりの方、Astro.jsについて馴染みがない方、各JSフレームワークにそれほど熟練していない方、Astro.jsについてざっくりとしたポイントを押さえておきたい方

### Astroを選択した理由
就活のためのWebサイトなので、とにかくパフォーマンスに優れるものを選択しようと思いました。その時点でSSGであることは確定していたのですが、特にそこに重点を置いているという前評判も人づてにあり、またLighthouseでのパフォーマンス計測が満点になったという情報も印象的だったので採用しました。

他のメリットとしてReactやVueなどメジャーな他プラットフォームとの互換性があり、移行や共通化にも強いというのも魅力でした。

## 所感

### `.astro`ファイル
まず以降の前提として、Astro.jsでは`.md`や`.astro`のファイル形式でページやコンポーネントを記述します。その中では先頭のコードフェンスと呼ばれる`---`で囲われた領域にJSで処理を記載し、その下に見た目をHTMLで記述するという構成になっています。

なお`.astro`ファイルのJavaScriptはTypeScriptで記載すると自動で解釈させることも可能です。

```example.js
/* Qiitaが対応していないので.jsとしていますが本来は.astroです */
---
import { Icon } from 'astro-icon/components';
import { twMerge } from 'tailwind-merge';
import type { CallToAction } from '~/types';

const {
  variant = 'secondary',
  target,
  text = Astro.slots.render('default'),
  icon = '',
  class: className = '',
  type,
  ...rest
} = Astro.props as CallToAction;

const variants = {
  primary: 'btn-primary',
  secondary: 'btn-secondary',
  tertiary: 'btn btn-tertiary',
  link: 'cursor-pointer hover:text-primary',
};
---

{
  type === 'button' || type === 'submit' || type === 'reset' ? (
    <button type={type} class={twMerge(variants[variant] || '', className)} {...rest}>
      <Fragment set:html={text} />
      {icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />}
    </button>
  ) : (
    <a
      class={twMerge(variants[variant] || '', className)}
      {...(target ? { target: target, rel: 'noopener noreferrer' } : {})}
      {...rest}
    >
      <Fragment set:html={text} />
      {icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />}
    </a>
  )
}

```

このコードフェンス部をフロントマターと呼称しているのですがフロントマターという言葉は「前付け、奥付、前書き」などの意味がある一般用語で、もともと`.md`や`.html`に`json`や`yaml`形式でメタデータを持たせるための機能として存在するようです。
### ハイドレーション

こうした構成になっているのは、不要なJavaScriptコードをサーバーから送信させない**ハイドレーション**を意識したもののようです。

フロントマターに記載したものはサイト公開時のビルドの段階で全て処理され、他に指定がない限りクライアントが受け取ることはありません。そのためとにかく早いです。いかにもSSGメインらしい設計と言えますし、こうした記載形式だとコーディング時にも簡単に意識できるので好感です。

ダークモードやボタンの動作など、どうしてもクライアントサイドで実行が必要なコードは`client:*`ディレクティブを使って明示することで読み込まれます。

```hydration_example.js
// JavaScriptが送信されず、実行されない 
<MyReactComponent />

// JavaScriptが送信され読み込み時に実行される
<MyComponent client:load />
```
https://docs.astro.build/ja/reference/directives-reference/#client-directives

### アイランドアーキテクチャ
https://docs.astro.build/ja/concepts/islands/

詳しくは公式サイトにありますが、上記のようにハイドレーションを行い、コンポーネント単位で必要なJavaScriptのみをクライアントに使用させることがアイランドアーキテクチャの要点です。

またコンポーネント単位でJavaScriptを処理するのでReact、Preact、Svelte、Vue、SolidJSなどの複数のUIフレームワークをサポートしています。
インテグレーションという仕組みで後から機能を拡張することでそれらに対応しています。

https://docs.astro.build/ja/core-concepts/framework-components/

個人的にはこの辺りはあまり必要ありません。`.astro`の文法はほぼJSXであり直接実装すれば良いからです。
そのため既にNextやNuxtで構成している開発者の移行を想定したものと思われます。

https://docs.astro.build/ja/guides/migrate-to-astro/

### ルーティング

https://docs.astro.build/ja/core-concepts/routing/

Astro.jsのページルーティングはディレクトリベースです。ルーターライブラリなどを追記せず、プロジェクトのソースコードの中から`src/pages`という予約済みのディレクトリを参照し、その構造と同じルーティングを生成します。

https://docs.astro.build/ja/core-concepts/project-structure/

この点についてはかなり好みだと思います。
ルーターの記載や実行結果を確認しなくても動作が予測できると同時に、逆にいうとAstro側が用意したルールに従い優先順などに気をつける必要があります。

Ruby on Railsにも似通っていますが、そちらのように現在存在するルートを確認する方法は調べた限りありません。
僕の場合テンプレートの再利用だったので気をつけなければ意図しないページが公開されてしまうという状態でした。
今後の発展に期待か、あるいは他の方法があるのかもしれません。


### `.astro`の文法
繰り返しになりますがほぼJSXで記載できます。
若干の[JSXとAstroの違い](https://docs.astro.build/ja/core-concepts/astro-syntax/#astro%E3%81%A8jsx%E3%81%AE%E9%81%95%E3%81%84)に注意する必要がありますが、HTMLを知っていれば最初は十分とあるようにそれほど難しいものではありません。

この点はSSGで構成されるWebサイトは高度な処理より見た目やコンテンツが重視されるので要件的に安心していいとも言えます。
ただしハイドレーションのおかげで多少パフォーマンスを気にせずビルド時のコードを書けるというのは特徴的な利点です。

### ドキュメント
そうした機能を揃えているということでもあり、サポートするというAstro側の姿勢でもある、メタ的な情報を踏まえたドキュメントが充実しています。

具体的には、例えばCMSの紹介がかなり充実しています。チュートリアルなどで扱うように、直接プロジェクト内にコンテンツを配置することがデフォルトですが、CMSを使用して外部を連携することでサービスを構成することも強く意識されているようです。

https://docs.astro.build/ja/guides/cms/

スポンサーにCMSサービス事業者がいることからも明らかなのですが、それに限らず多くのサービスをサポートしています。
もちろんCMSを利用した場合でも、ある程度のコンテンツ量まではパフォーマンスを重視したSSGで、頻繁に更新され大量にあるようなものは部分的なSSRで対応する、といった構成が可能です。

また他にもサイトホスティングサービスもスポンサーであり、SSGの運用として実用的な自動デプロイが想定されているのでチュートリアルでGithubにコミットを行いNetlifyから実際に公開するステップがあります。

さらにはサーバーレスバックエンドや、i18nなど実用に即したガイドが豊富で心強く感じます。この辺りは後発のフレームワークとして知見が生かされいるようにも思います。

https://docs.astro.build/ja/guides/backend/

https://docs.astro.build/ja/guides/internationalization/

### テンプレート
[テーマとスターターテンプレート](https://astro.build/themes/)というセクションがあり、結構な量の無料または有料のテンプレートが使用できます。またこの閲覧サイトが流石にはやくて快適です。

## まとめ
全体を通して、開発もパフォーマンスも軽量に、後付けも行うことで必要十分なSSGを構築できる実用的なフレームワークなのではないでしょうか。
少なくとも個人的な用途でSSGが適するシーンでは今後も使い続けたいと思います。