はじめに
先日こちらのイベントに出させてもらった際、Astro
を知ることになり、使ってみたいなーと思っていたところ会社の新サービスLPで利用できる機会がありました。
社内のフロントエンドチームの中でも利用した事例はなかったですが、
- 社内で一番利用されている、React(JSX)ベースでも書くことができる
- Astro形式のファイルもSPAフレームワーク利用者なら問題なくキャッチアップできそう
ということもあり、Astroを選定することができました。
まだAstroについて知らない人や利用を検討している人へ、本記事での「実際にAstro
利用した感想」や、「Next.js
とのパフォーマンス比較」をもとに導入のきっかけとなれば幸いです。
こんな人に読んで欲しい
- Astroってそもそも何?って人
- Astroの利用を検討している人
- AstroとNext.jsの比較を知りたい人
Astroについて
そもそもAstro
について知らない人も多いかと思います。
Astro
とは可能な限りJavaScriptを取り除き、最適化された静的HTMLを作成するために作られた静的サイトビルダーです。(Gatsby.js
のようなイメージです。)
動的なコンテンツを利用しない限りクライアントのJSの読み込みが「0KB」となり、サイトのビルド時にはHTMLとCSSのみが出力されます。
そのためページ遷移時はSPAのようにHistory APIを利用せず、昔ながらのページの再読み込みを行うMPA形式となります。
[参考]
なんでAstroを利用するのか?
SPAフレームワークでもSSR/SSG/ISRなど、様々な方法で描画を最適化しようという動きはあります。
その中でなぜAstro
を利用するのかというと、大きくは以下が理由になるかと思います。
- 流行りのSPAフレームワークを利用すると、JSファイルのサイズが重い
- JSを読み込んだ後、ハイドレーションの処理に時間がかかる
そもそもSPAフレームワークが生まれた背景として、「画面遷移の際に読み込むデータを最適化する」、「動的コンテンツをブラウザで扱いやすくする」という目的があり、静的サイトをビルドするために作られたフレームワークでないということから、上記のようなギャップが生まれています。
このことから静的サイトの最適化という観点で、Astroのような静的サイトビルダーや/フレームワークがフロントエンド界隈で台頭してきています。
[参考]
Astroを利用してみて
Astro
を利用してLPを構築しましたが、以下が実装面のメリットとして大きいように感じました。
-
Vue
やReact
のようなUIフレームワークに加え、MD/MDX
形式での実装が可能なので学習/運用コストを低くすることができる - コンポーネント思考で画面設計が可能
- ファイルベースのルーティング
- 動的なコンポーネントを好きなタイミングでレンダリングすることが可能(Astro Islands)
社内で利用しているメインフレームワークがReact
のため、今回は.astro
と.tsx
形式でコンポーネントを作成しました。
Next.js
のように/pages
配下から/components
を呼び出すように実装でき、Next.js
ユーザーにはとても直感的でした。
例えばこんな感じのコンポーネントを作成したら、
import { useState } from "react";
export const Counter = () => {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{`Count: ${count}`}
</button>
);
};
以下のような形式で呼び出すことができます。(Astro
まだハイライトされてない;;)
---
import { Counter } from "../components/Counter";
const title = "Astro Example";
---
<main>
<h1>{title}</h1>
<Counter client:load />
</main>
この中にある、
<Counter client:load />
ですが、これがAstro
の特徴である「Astro Islands」になります。
静的なページを作成する際も、SPAのような動的なコンテンツを利用したいタイミングがあるかと思います。
その場合はclient
というディレクティブを必ずつける必要があり、これを付与することで「対象のコンポーネントのみ」をターゲットとしたハイドレーションを実行します。
またclient
は実行タイミングを選択することができ、「スクロール地点」や「画面サイズ」などの細かい設定も可能です。
こちらを利用することにより、「最初に呼び出したいコンポーネント」や「後からの描画でも問題ないコンポーネント」などの重みづけを簡単に設定することができます。
[参考]
Next.jsとAstroを比較してみた
今回の検証ではベースとなるNext.js/Astro
にTailwind CSS
を追加したのみの構成となっています。
# Next.js Project
yarn create next-app --typescript
# https://tailwindcss.com/docs/guides/nextjs
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# Astro project
yarn create astro
# https://docs.astro.build/en/guides/integrations-guide/tailwind/
yarn astro add tailwind
Astro
でLPサイトを作成し、Next.js
の形式に移植をします。
Astro
的な書き方の箇所をJSX形式に変換するだけでしたので、15~20分ほどで作業は完了しました。
(JSX形式で実装していたコンポーネントは、そのまま流用することができました。)
各環境で静的ファイルをExportし、http-server
を用いてローカルサーバを立てます。
これで各環境での検証準備が整いました。
# 静的ファイルを出力したディレクトリへ移動
# デフォルトだと Next.jsは 「/out」、 Astroは 「/dist」 に出力されます。
$ cd /staticfFile/path
# port 8080でサーバーが起動
$ npx http-server
Starting up http-server, serving ./
...
Available on:
http://127.0.0.1:8080
http://192.168.3.7:8080
Hit CTRL-C to stop the server
Lighthouse
今回はlocalhost
の環境で、Chromeのdevtoolにある「Lighthouse」を利用しました。
結果を見てみると「Largest Contentful Paint」の項目が「約2.5倍」も違います。
こちらの項目は、初期ロードから最も大きい要素がレンダリングされるまでの時間になります。
Next.js/Astro共に最適化をしていませんが、デフォルトではかなり大きな差分を生んでいるように見えます。
リクエストサイズ
「Document」や「Stylesheet」のリソースサイズも違いますが、一番大きな差分は「Script」ということがわかります。
冒頭でも説明しましたが、Astro
は可能な限りJavaScriptを読み込まないためこれだけ大きな差分を生んでいます。
Next.jsは静的な画面1ページの描画でも「246.2KB」ものScriptを読み込む必要があるのですね。
最後に
各環境で最適化を行えば結果が変わるかもしれませんが、私の検証環境ではこのような結果となりました。
Astro
を 使ってみたい/検討している という人の参考になれば幸いです!
また本記事ではAstro
とNext.js
の静的サイトの比較を行いましたが、ハイドレーションを多用した動的サイトでの検証はできておりません。
Astro
はReact
以外にもVue
,Svelte
など様々なフロントエンドフレームワークを実行することができるので、既存のアプリケーションでA/Bテストを行った方がいましたらぜひ教えていただきたいです!