こんにちは。フロントエンドを担当しています mozato です。
先日 Twitter を徘徊していたところAstro というものを見つけ、気になった部分があったので試してみました。
Astro とは
Snowpack が先日発表した静的サイトジェネレータ (公式ではビルダー) です。
Astro が気になった理由は下記の Tweet の内容です。
🚀 Introducing Astro: A New Kind of Static Site Builder
— fks (@FredKSchott) 2021年6月8日
⚡️ Works with React, Preact, Svelte, Vue
⚡️ Astro renders everything to static HTML
⚡️ Result: 0 bytes of JS, by default
⚡️ Interactive components load on demand
Ship less JavaScript.
https://t.co/lFNN3OVUXi
興味深い⚡️が並んでいます。
特に気になったのは、基本的には JavaScript が使用されず必要な時に読み込んでくれるという内容です。
現在まだ early beta ですが、早速試してみました。 試した時のバージョンは 0.13.2 となります。
環境作成
「🔧 Quick Start」を参考に作成。
https://github.com/snowpackjs/astro#-quick-start
手順通りに進めると、テンプレート選択をする箇所があるのですが、今回は「Starter Kit (Generic)」を使用しました。
試すその前に
まずは「💧 Partial Hydration」に目を通しておきましょう。
https://github.com/snowpackjs/astro#-partial-hydration
なにか動きがあるコンポーネントを使いたい場合は :load , :visible , :idle をコンポーネントの名前につけると良さそうです。
それぞれ JavaScript が読み込まれるタイミングが
:loadはページ表示時:visibleはIntersectionObserverを使用し viewport 内にコンポーネントが入った時:idleはrequestIdleCallback()を使用しブラウザがアイドル状態の時
ということになりそうです。
:idle は試すの大変なので... :load と :visible を試していきます。
試してみる
挙動を確認するための単純なカウンターコンポーネントを作成します。
src/components/Counter.jsx を作成し、内容を下記の様にします。(style は見やすさのため)
import { h } from 'preact'; import { useState } from 'preact/hooks'; export function Counter() { const [count, setCount] = useState(0); const increment = () => setCount((i) => i + 1); const decrement = () => setCount((i) => i - 1); return ( <div style=" display: flex; justify-content: center; padding: 1rem; border: 1px solid #ccc; font-size: 2rem;" > <button style="font-size: inherit;" onClick={decrement} > - </button> <p style="margin: 0 1rem; font-weight: 700;"> {count} </p> <button style="font-size: inherit;" onClick={increment} > + </button> </div> ); }
作成したカウンターコンポーネントを表示させるために、src/pages/index.astro を下記の様に変更します。
---
import { Counter } from '../components/Counter.jsx';
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Astro</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/style/global.css">
<link rel="stylesheet" href="/style/home.css">
<style>
header {
display: flex;
flex-direction: column;
gap: 1em;
max-width: min(100%, 68ch);
}
</style>
</head>
<body>
<main>
<header>
<div>
<img width="60" height="80" src="/assets/logo.svg" alt="Astro logo">
<h1>Welcome to <a href="https://astro.build/">Astro</a></h1>
</div>
</header>
<section>
<h2 style="text-align: center;">
<code><Counter /></code>
</h2>
<Counter />
</section>
</main>
</body>
</html>
ここまでできたら npm start を実行し、http://127.0.0.1:3000/ をブラウザで表示してみましょう。

先ほど作成したカウンターコンポーネントが表示されています。
試しにプラスボタンやマイナスボタンを押してみましょう。
...カウンターコンポーネントでインクリメントやデクリメントの処理を書いていたのですが、動作したでしょうか?
されないはずです!Astro はデフォルトでは HTML のみ出力してくれるからです。
デベロッパーツールの「Network」タブを選択して JavaScript がどうなっているか見てみると、

見事に何も読み込みされていません。
カウンターを動かしたい!
このままだと折角作成したカウンターコンポーネント君が、数を刻むこと無くその役目を終えてしまうので動作する様に変更してみましょう。
:load
まずは :load を試してみます。
:load をつけるとページ表示時に JavaScript を読み込みんでくれるはずです。
src/pages/index.astro で <Counter /> と書いている箇所を下記の様にします。
<Counter:load />
それでは変更を保存しページを再読み込みしつつ、プラスボタンやマイナスボタンを押してみましょう。

きちんとカウンターとして動きました👏
デベロッパーツールの「Network」タブを選択して JavaScript がどうなっているか見てみると、

ページが表示されたタイミングで色々と JavaScript が読み込まれているのがわかります。
:visible
次は個人的に一番気になっていた :visible を試してみます。
:visible をつけるとviewport 内にコンポーネントが入った時に JavaScript が読み込まれるはずです。
src/pages/index.astro で先ほど <Counter:load /> としたところを <Counter:visible /> とします。
<Counter:visible />
まずは最初から viewport 内に表示されている場合を試してみます。 変更を保存したらページを再読み込みしてみましょう。

:load の時と同じですが、最初から viewport 内に表示されているのですぐに JavaScript が読み込まれています。
それでは viewport の外に行ってもらうために margin などをつけて試してみます。
<div style="margin-top: 200vh;"> <Counter:visible /> </div>
さてどうなるか...

わー👏
画面内に入った時に JavaScript が読み込まれていますね!
loading="lazy" みたいに気軽!
「最初に2個 JavaScript があるじゃないか!」
- hmr-client.js
- visible.js
この 2つが最初に読み込まれていますが、visible.js は :visible を実現するために必要なもので、hmr-client.js はビルドすると読み込まれません。
必要なものなので許してください...
まとめ
気になった Astro の動作を簡単ですが試してみました。
必要なければ JavaScript を出力しないのは最高だと思っていたのですが、必要な時に JavaScript を読み込みしてくれるのはすごく面白い機能ですよね。
特にサイトのパフォーマンスを気にするような場面で活躍してくれるのではと思っています。
また最初から
- React
- Vue.js
- Svelte
- Preact
を使えるのも便利です。
全てを一気に使用しているサンプルが公式にある のですが、これが簡単に出来ちゃうのが本当に面白いなーと思います。
自分がブログなり LP を作る仕事を受けたりしたら、Astro を是非使ってみたいと思いました。