みなさんよくWeb制作をすると思います。やはり楽に制作を進めたいので何かしらのフレームワークを使用する機会が非常に多いものです。しかし、ちょっとしたブログやランディングページを作りたいときにReact.jsやVue.jsを使用するのはオーバースペックだと思ったことはありませんか。
Web制作では速度などのパフォーマンスが重視されます。それに対し先程のフレームワークではSPAであり、決して初回のロード時間が早くありません。こういう場合には各ページのロードが早いMPAにしたいです。
そんな場合におすすめできるフレームワークがAstro.js(以下Astroという)です。理由は次章で紹介します。
Astroとは
Astroについてもっと詳しく知りたければ、ネットを探せばいくらでもあると思います。
JavaScript
AstroはゼロJSを目標にしており、余計なJavaScriptが生成されません。Astro内に書かれたJavaScriptはビルド時に実行され、HTMLに変換されます。そのため、クライアントでのコード実行が必要なく非常に軽いページを作れます。
Astroでは専用のスペースにJavaScriptを書くだけでなく、いわゆるJSXのような記法でJavaScriptを書きます。
もちろんクライアント側で実行するJavaScriptを埋め込むことも可能です。
コンポーネント
Astroはコンポーネント指向のためコードの使い回しが可能です。たとえばヘッダーコンポーネントを作れば、全てのページに同じヘッダーを適用できます。フレームワークを常用する人にとっては欠かせない機能でしょう。
アイランドアーキテクチャ
Astroアイランドという仕組みで、様々なUIフレームワークをAstro内で使うことができます。たとえばReact, Vue, SvelteなどのUIフレームワークをサイト内に埋め込むことで、慣れた言語で実装したりWebアプリにしたりするために使います。他の使用可能なUIフレームワークについては公式ドキュメントを見てください。
Markdown
Markdownをそのまま取り込んで描画することが可能です。自動的にHTMLに変換され、CSSを適用できます。実際にブログなどを作るときはこの機能が使えるでしょう。
機能
Astroで使える素晴らしい機能の解説です。
JavaScript
Astroでは2種類のJavaScriptが使用できます。1つはビルド時に実行して静的ファイルに変換するもので、もう1つはHTMLで使うようなscriptタグです。
今解説するのは前者のJavaScriptです。まずは簡単なコードの例を見てみます。
---
const text = "Hello, World!";
---
<p>{text}</p>
前ページのAstroコードを実際にブラウザで表示してみるとpタグで「Hello, World!」とレンダリングされます。今の状態だとあまりメリットを感じないかもしれません。私がよく使う使い方は以下のようなコードを書きたいときです。
<ul>
<li class="content border" id="apple">りんご</li>
<li class="content border" id="banana">ばなな</li>
<li class="content border" id="grape">ぶどう</li>
</ul>
この場合「めろん」など新しい項目を追加するのも大変ですし、class
の内容を変更することになったら3つとも変更しなければなりません。
HTMLで解決できないことはありませんが、Astroだともっとスマートに可能です。
---
const fruits = [
{
id: "apple",
name: "りんご",
},
{
id: "banana",
name: "ばなな",
},
{
id: "grape",
name: "ぶどう",
},
];
---
<ul>
{
fruits.map((fruit) => (
<li class="content border" id={fruit.id}>{fruit.name}</li>
))
};
前ページのコードのようにコンテンツを配列やオブジェクト形式で管理してHTMLに変換することで、コードをシンプルに読みやすく書きやすくできます。
先程の例だとコードの行数は逆に増えてしまっていますが、もっと規模の大きいWeb制作をしていくときにはメニューやリストに使用し、コードを大幅に削減できました。
実はここではTypeScriptを使うことができます。Astroプロジェクト作成時に対話型でDo you plan to write TypeScript?
と聞かれるのでYesと答えればTypeScriptに対応します。TypeScriptが分かる人であればAstro.props
という怪しい型さえ覚えれば問題なく使用できると思います。
scriptタグ
じゃあ動的な動作はどうしたらいいのかというと、それはHTMLと何も変わりません。
<script>
window.alert("Hello, World!")
</script>
このように書けば「Hello, World!」とアラートされます。「じゃあこれはいつものscriptタグなんだな」と思うかもしれませんが、実は微妙に違う挙動をします。
Astroのscriptタグはすべてheadタグの中にtype="module"埋め込まれます。そのため常に遅延読み込みされ、asyncやdefer属性は使用されません。
scriptタグの中に書かれたTypeScriptは自動的にトラスコンパイルなどの処理がされます。node_modules
をscriptタグから読み込むことも可能になっているわけです。
これらの処理のおかげで、コンポーネント内にscriptタグを置きそのコンポーネントを複数並べたとしてもscriptタグ自体は1つのみ生成されます。場合によってはこの処理がじゃまになる機会があります。その際はscriptタグにis:inline
属性をつければ皆さんのよく知るscriptタグになってくれます。
ちなみに以下のコードのように書くことで、静的なJavaScriptからscriptタグの中身へと変数の受け渡しができる機能が存在します。
---
const text = "Hello, World!";
---
<script define:vars={{text}}>
window.alert(text);
</script>
styleタグ
皆さんもお気づきの通りstyleタグも特殊です。ただscriptタグほどクセは強くなく、非常にシンプルなものです。
コンポーネント内に書かれたstyleタグのCSSはそのコンポーネントのHTMLにしか効果がないというものです。ここで指定したCSSがあっちのコンポーネントに適用されてしまうなんてことは起こりません。
もちろん全体に適用したいときにも対応していて、is:global
属性をつけることができます。
SCSSを使用することもとても簡単です。
npm install -D sass
これを実行するだけでAstroはSCSSに対応するようになります。ただscriptタグのときと違いlang="scss"
と属性で言語を指定する必要があることに注意です。
変数はscriptタグとほぼ同じなので割愛します。
読み込んでいるコンポーネントに対してCSSを適用したいときがあるでしょう。
<Card class="card">
<p>Hello, World!</p>
</Card>
実際にこのようにclass
を与えてみるとプロパティ 'class' は型 'IntrinsicAttributes & Props' に存在しません。
と怒られてしまいました。これはTypeScriptを使っているため発生したエラーで、JavaScriptだと発生しません。けれどもいざCSSを適用しようとすると、効果が現れません。
Card
コンポーネント側にコードを指定する必要があります。
---
const { class: className, ...rest } = Astro.props;
---
<div class={className} {...rest}><!-- 好きなコード --></div>
class: className
のように遠回しな指定をした理由はclass
がJavaScriptの予約語であるため使用できないからです。
...rest
はCard
コンポーネントに与えられた属性をすべてオブジェクト形式にしています。それを子コンポーネントに送りスコープしています。多分他の方法があるはずです。
参考文献