高速なWEBサイトを構築したいという人向けに新たなStatic Site Generator(静的サイトジェネレーター)が登場しました。その名前はAstro。本文書ではAstroを使って主要な機能の動作確認を行なっています。

Astroとは

Astroは開発時に利用するJavaScriptを可能な限り除いた静的なHTMLファイルを作成することで高速なWEBアプリケーションを構築することを目的としたStatic Site Generator(Static Site Builder)です。

Astroではビルド後に作成されるJavaScriptのバンドルサイズを小さくしクライアント側でのJavaScript処理の負荷をなくすことで高速化を実現しています。開発時に利用するJavaScriptはビルドの際に取り除かれますが、カルーセルやショッピングカードなどクライアント側(ブラウザ上)でJavaScriptが必要な場合は利用した機能に関連するコンポーネントでJavaScriptを利用できるように設定を行い、残りのコンポーネントは静的なHTMLファイルとして作成します。

JavaScriptのサイズを少なくすることによる高速化よりも個人的に最も興味を惹かれたのがコンポーネントを作成する際に好きなフレームワークを選択できる点です。本ブログでこれまでに紹介したStatic Site Generator機能を持つGatsby, Next.jsであればReact、Nuxt.jsであればVue.jsを利用することが必須になりますがAstroではReact, Vue.js、Svelteなど好きなフレームワーク/ライブラリを利用することができます。利用しないことも可能でAstroも独自の記述方法を利用してコードを記述することができます。

利用できるフレームワーク/ライブラリ
利用できるフレームワーク/ライブラリ

コンポーネントを作成する際にあるコンポーネントではReact、別のコンポーネントではVue.jsを利用するといったことが可能です。好きなフレームワーク/ライブラリで作成したコンポーネントはクライアント側で利用するJavaScriptがなければビルド時にすべて静的なHTMLファイルへと変換されます。

ビルド後にどうようなファイルが作成されるのか、好きなフレームワークを選択できるとはどういうものなのかAstroを実際に動作させて確認していきます。

プロジェクトの作成

npm, yarn, pnpmコマンドを利用してAstroプロジェクトを作成することができます。ここではnpmコマンドを利用してプロジェクトの作成を行います。インストール方法についてはドキュメントを参考に行なっています。


% npm create astro@latest
Need to install the following packages:
  create-astro@latest
Ok to proceed? (y) 
Welcome to Astro! (create-astro v0.12.4)
Lets walk through setting up your new Astro project.

? Where would you like to create your new project? › ./my-astro-site
? Which template would you like to use? › - Use arrow-keys. Return to submit.
❯   Just the basics
    Blog
    Documentation
    Portfolio
    Completely empty
✔ Template copied!
✔ Would you like us to run "npm install?" … yes
✔ Packages installed!
✔ Initialize a new git repository? This can be useful to track changes. … yes
✔ Setup complete.
✔ Ready for liftoff!

 Next steps 

You can now cd into the my-astro-site project directory.
Run npm run dev to start the Astro dev server. CTRL-C to close.
Add frameworks like react and tailwind to your project using astro add

Stuck? Come join us at https://astro.build/chat
Good luck out there, astronaut.

コマンドを実行するとプロジェクト名の設定(デフォルトはmy-astro-site)とテンプレートの選択を行うことができます。テンプレートの選択によって作成されるファイルが異なります。ここではデフォルトの”Jest the basics”を選択します。

インストールの最後のメッセージにある通りreactやtailwindを利用したい場合は追加する必要があります。追加方法と利用方法については後ほど説明します。

フォルダ構成

作成されたmy-astro-siteに移動してフォルダ構成を確認します。プロジェクトフォルダ直下にはnode_modules, public, srcフォルダがあります。srcフォルダの中にはさらにcomponents, layouts, pagesフォルダを確認することができその中に拡張子astroを持つファイルが存在します。

フォルダ構成
フォルダ構成
astroの拡張子を持つファイルはAstro ComponentsでAstro独自の記述方法(シンタックス)で記述します。ReactやVueなどのフレームワークを利用しなくてもAstroコンポーネントのみでアプリケーションを作成することができます。

srcフォルダの中にソースコードを記述し、publicフォルダにはフォントや画像などを保存することができます。

astro.config.mjsがastroに関する設定ファイルです。本文書ではReactなどを追加設定する場合に利用します。package.jsonファイルにはインストールされているパッケージやスクリプトが記述されています。

VScodeのExtentionsのインストール

components, layouts, pagesの中に作成されている拡張子astroのコードはハイライトされていないのでVSCodeを利用している場合はExtentionsのAtroをインストールします。

AstroのExtensions
AstroのExtensions

インストールを行うとコードがハイライトされます。

アプリケーションの起動

srcフォルダの中のファイルの詳細を確認する前にnpm run devコマンドを実行して開発サーバを起動します。


 % npm run dev

> @example/minimal@0.0.1 dev
&grt; astro dev

fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
  🚀  astro  v1.0.0-beta.63 started in 31ms
  
  ┃ Local    http://localhost:3000/
  ┃ Network  use --host to expose
  
  ▶ This is a  beta  prerelease build
    Feedback? https://astro.build/issues

localhost:3000にアクセスを行うとブラウザには以下の画面が表示されます。

Astroの”Just the basics”テンプレートの初期画面
Astroの”Just the basics”テンプレートの初期画面

ブラウザに表示されている内容はsrc¥pages¥index.astroファイルに記述されています。一つのファイルにJavaScriptのimport, HTML, scriptタグが記述されていることがわかります。Vue.jsやMarkdownのfront-matterを記述方法に似ていますがどちらでもありません。これがAstro独自の記述方法です。


---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
---
<Layout title="Welcome to Astro.">
  <main>
    <h1>Welcome to <span class="text-gradient">Astro</span></h1>
    <p class="instructions">
      Check out the <code>src/pages</code> directory to get started.<br/>
      <strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
    </p>
    <ul role="list" class="link-card-grid">
      <Card href="https://docs.astro.build/" title="Documentation" body="Learn how Astro works and explore the official API docs." /> 
      <Card href="https://astro.build/integrations/" title="Integrations" body="Supercharge your project with new frameworks and libraries." /> 
      <Card href="https://astro.build/themes/" title="Themes" body="Explore a galaxy of community-built starter themes." /> 
      <Card href="https://astro.build/chat/" title="Chat" body="Come say hi to our amazing Discord community. ❤️" />
    </ul>
  </main>
</Layout>

<style>
  :root {
    --astro-gradient: linear-gradient(0deg,#4F39FA, #DA62C4);
  }

  h1 {
    margin: 2rem 0;
  }
//略
</style>

Astro 設定ファイル

Astroの設定ファイルであるastro.config.mjsファイルではどのようなことが設定できるのか確認します。

デフォルトではportは3000ですがportを変更したい場合はastro.config.mjsファイルで行うことができます。変更後は一度npm run devコマンドを停止し再度実行すると変更したportで起動します。


import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
  server: { port: 8080 },
});

Astro Components

Astro独自の記述方法で記述されているコンポーネントはAstro Componentsと呼ばれます。Astro Componentsは大きく2つのパートに分かれており一つはComponent Script(—と—で囲まれている部分)、もう一つはComponent Templateです。

Component Scriptではコンポーネントのimportやコンポーネントに渡されるprops、変数の定義、外部リソースからのデータ取得を行うJavaScriptコードを記述することができます。

Component TemplateにはHTMLを記述することができます。HTMLだけではなくJavaScriptの埋め込み、importしたコンポーネントやAstro独自のディレクティブも利用できます。styleタグを追加してCSSも設定できます。

Cardコンポーネント

componentsフォルダにあるCard.astroを確認してAstro Componentsの記述方法を確認します。


---
export interface Props {
    title: string,
    body: string,
    href: string,
}
const {href, title, body} = Astro.props;
---
<li class="link-card">
    <a href={href}>
        <h2>
            {title}
            <span>→</span>
        </h2>
        <p>
            {body}
        </p>
    </a>
</li>
<style>
//略
</style>

Component Scriptの中でTypeScriptのinterfaceでPropsの型を定義し、親コンポーネントから渡されるpropsはAstro.propsの中に保存されてhref, title, bodyとして取り出して利用できることがわかります。渡されたpropsは{}を利用することでComponent Templateの中で利用できます。

propsを渡している親コンポーネントのindex.astroファイルを確認するとCardコンポーネントにへのpropsの渡し方も確認できます。


<ul role="list" class="link-card-grid">
  <Card href="https://docs.astro.build/" title="Documentation" body="Learn how Astro works and explore the official API docs." /> 
  <Card href="https://astro.build/integrations/" title="Integrations" body="Supercharge your project with new frameworks and libraries." /> 
  <Card href="https://astro.build/themes/" title="Themes" body="Explore a galaxy of community-built starter themes." /> 
  <Card href="https://astro.build/chat/" title="Chat" body="Come say hi to our amazing Discord community. ❤️" />
</ul>

Layoutコンポーネント

index.astroファイルを確認するとimportしたLayoutタグで包まれていることがわかります。


---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
---
<Layout title="Welcome to Astro.">
  <main>
    <h1>Welcome to <span class="text-gradient">Astro</span></h1>
    //略
  </main>
</Layout>
//略

Layoutコンポーネントに対してpropsでtitleを渡しています。

layoutsフォルダのLayout.astroを確認するとbodyタグの中にslotタグが確認できます。


---
export interface Props {
  title: string;
}

const { title } = Astro.props as Props;
---

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <link rel="icon" type="image/x-icon" href="/favicon.ico" />
  <title>{title}</title>
</head>
<body>
  <slot />
</body>
</html>

<style>
//略
</style>

このslotの場所にindex.astroファイルのLayoutタグの中に記述したコードが挿入されて表示されます。Layoutコンポーネントを利用することで共通のレイアウトを複数ページに適用することができます。

プロジェクト作成時のテンプレートに”Just the basic”を選択することでAstrto Componentと基本とレイアウトファイルの作成方法を理解することができました。

テンプレートのCompletely Emptyを選択した場合はsrc/pagesフォルダにindex.astroのみ作成されます。

pageコンポーネント

Astroはファイルベースルーティングを利用しているのでpagesフォルダの中にファイルを作成するとルーティングが自動で設定されます。

pagesフォルダの中にabout.astroファイルを作成します。CSSを利用しない場合はscriptタグを省略することができます。


---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Aboutページ">
  <h1>Astroについて</h1>
</Layout>

ファイル作成後にhttp://localhost:3000/aboutにブラウザからアクセスするとaboutページが表示されます。ファイルベースルーティングなので手動でルーティングを設定する必要はありません。Layoutコンポーネントを利用しているのでブラウザのタブにはpropsのtitleで設定した”Aboutページ”が表示されています。

aboutページの作成
aboutページの作成

ビルドの実行

about.astroページを作成したのでビルドを行うとどのようなフォルダ、ファイルが作成されるのか確認します。ローカルでのビルドの実行はnpm run buildコマンドで実行することができます。


% npm run build

> @example/basics@0.0.1 build
> astro build

fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
08:34:10 [build] Collecting build information...
08:34:10 [build] Completed in 49ms.
08:34:10 [build] Building entrypoints for prerendering...
08:34:12 [build] Completed in 1.23s.

 generating static routes 
▶ src/pages/index.astro
  └─ /index.html (+12ms)
▶ src/pages/about.astro
  └─ /about/index.html (+4ms)
Completed in 34ms.

08:34:12 [build] 2 page(s) built in 1.33s
08:34:12 [build] Comp

ビルドが完了するとプロジェクトフォルダ直下にdistフォルダが作成されます。distフォルダを展開するとaboutフォルダが作成されていることがわかります。aboutフォルダのindex.htmlファイルを見るとHTMLのみで記述されたファイルであることがわかります。下記の画像にはdistフォルダの中身を表示していますがJavaScriptに関連するファイルは存在しないことが確認できます。

aboutページのファイルの中身を確認
aboutページのファイルの中身を確認

外部リソースからのデータ取得

外部リソースからデータを取得したい場合の方法について確認します。外部リソースには無料で利用できるJSONPlaceHolderを利用します。https://jsonplaceholder.typicode.com/postsにアクセスすると100件分のpostデータを取得することができます。

postsフォルダを作成しその中にindex.astroファイルを作成します。データ取得するためのfetch関数はComponent Scriptの中に記述します。取得したデータはmap関数を利用して展開します。ブラウザ上には取得したPostのタイトルを表示させています。


---
import Layout from "../../layouts/Layout.astro";
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await response.json();
---
<Layout title="Post一覧ページ">
  <h1>Post一覧</h1>
  <ul>
    {posts.map(post => (
      <li>{post.title}</li>
    ))}
  </ul>
</Layout>

ブラウザから/postsにアクセスするとJSONPlaceHolderから取得したpostデータ一覧が取得できます。

postsの一覧を表示
postsの一覧を表示

Dynamicルーティングの設定

Post一覧を表示することができたのでPostのタイトルをクリックすると個別のPostページが表示できるように設定を行います。/posts/1, /posts/2のidによって表示させる内容を変更させるためにDynamicルーティングを設定します。

postsフォルダに下に[id].astroファイルを作成します。Dynamicルーティングを設定する際にブラケット[]の中に変数を設定します。URLの/postsの後に続くidはAstro.paramsから取得することができます。取得する際は[]の中で設定した変数名を利用します。


---
const { id } = Astro.params;
console.log(id)
---
<h1>Post:{id}</h1>

[id].astroファイルを作成後に/posts/1にアクセスすると下記のエラーメッセージが表示されます。dynamicルーティングを利用したい場合はgetStaticPaths関数が必須でコンポーネントでexportしなければならないと表示されています。

getStaticPaths関数に関するエラー
getStaticPaths関数に関するエラー

/posts/1, /posts/2, /posts/3にアクセスした場合にページが表示されるようにgetStaticPaths関数の設定を手動で行います。


---
export async function getStaticPaths() {
  return [
    { params: { id: 1 } },
    { params: { id: 2 } },
    { params: { id: 3 } }
  ];
}

const { id } = Astro.params;
console.log(id)
---
<h1>Post:{id}</h1>

getStaticPathsを設定後に/posts/1にアクセスするとAstro.paramsから取得したidを表示することができます。

Post Idの表示
Post Idの表示

getStaticPathsで設定していない/posts/4にアクセスするとNot Foundページが表示されます。

404 Not Foundページの表示
404 Not Foundページの表示
404ページを変更したい場合はpagesフォルダの中に404.astroを作成することで作成した404.astroの内容が表示されます。

手動で設定していたgetStaticPaths関数の設定をJSONPlaceHolderから取得したデータを利用して設定できるように変更を行います。


---
export async function getStaticPaths() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  const posts = await response.json();

  return posts.map(post => {
    return {
      params:{id:post.id}
    }
  })
}

const { id } = Astro.params;
---
<h1>Post:{id}</h1>

postデータは1から100までのidを持っているのでブラウザから/posts/1,..,/posts/100までの範囲であればidがブラウザ上に表示されます。/posts/101では404 Not Foundエラーが表示されます。

npm run devのコマンドを実行したコンソールに[getStaticPaths] invalid path param: id. A string value was expected, but gotのエラーメッセージが表示されます。paramで設定したidにはpost.idで数値で渡されれており文字列を渡す必要があります。toStringメソッドを利用して数値型から文字列型へ変換するとメッセージは消えます。URLの/posts/idのidは文字列として処理されるのでparamsで設定するidも文字列にする必要があります。


params:{id:post.id.toString()}

JSONPlaceHolderから取得できるデータの中にはPostの中身も入っているのでgetStaticPaths関数を利用することでPropsとして渡すことができます。


---
export async function getStaticPaths() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  const posts = await response.json();

  return posts.map(post => {
    return {
      params:{id:post.id},
      props:{post}
    }
  })
}

const { post } = Astro.props;
---
<h1>{post.title}</h1>
<div>
  {post.body}
</div>

ブラウザで確認するとPostのタイトルと内容が表示されます。

Postの内容を表示
Postの内容を表示
個別のPostの情報を別のfetch関数を利用して取得することもできます。

リンクの設定

PostページへのアクセスはブラウザのURLに手動で/posts/Xを入力して行なっていましたがPost一覧からアクセスできるようにリンクの設定を行います。aタグを設定後Post一覧のリンクをクリックするとPostの個別ページが表示されます。


---
import Layout from "../../layouts/Layout.astro";
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await response.json();
---
<Layout title="Post一覧ページ">
  <h1>Post一覧</h1>
  <ul>
    {posts.map(post => (
      <li><a href={`/posts/${post.id}`}>{post.title}</a></li>
    ))}
  </ul>
</Layout>

Markdownの利用

pagesフォルダの中にabout.astroを保存するだけでルーティングが設定されたようにMarkdownファイルをpagesフォルダに保存してもルーティングが自動で行われMarkdownに記述した内容がブラウザ上に表示されます。

動作確認のためpagesフォルダにmarkdown.mdファイルを作成します。


---
title: AstorでMarkDown
---

# AstroでMarkDown

はじめてAstroを利用してMarkDownを書いています。

ブラウザから/markdownにアクセスすると文字化けしたページが表示されますが内容はmarkdown.mdファイルに記述したものであることがわかります。

Markdownファイルの内容表示
Markdownファイルの内容表示

Layoutファイルの設定

MarkdownファイルでもLayoutファイルを利用することができます。layoutsフォルダにMdLayouts.astroファイルを作成して以下を記述します。Markdownに記述した内容はslotに挿入されます。Astroのpropsを通してFront Matterに記述した内容にアクセスすることができます。


---
const { content } = Astro.props;
---
<html>
  <head>
    <title>{content.title}</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <slot />
  </body>
</html>
propsのcontentの中にはFront MatterだけではなくMarkdownファイルの中身も入っています。

作成したLayoutファイルを利用するためにはMarkdownファイルで指定する必要があります。


---
layout: ../layouts/MdLayout.astro
title: AstorでMarkDown
---

# AstroでMarkDown

はじめてAstroを利用してMarkDownを書いています。

再度ブラウザで確認するとmetaタグでcharsetの設定を行なったので文字化けも解消して表示されます。またtitleの設定した値はブラウザのタブに反映されていることがわかります。

Layout適用後に表示される内容
Layout適用後に表示される内容

Markdown.mdファイルのfront matterで設定した値についてはfrontmatterオブジェクトを介してアクセスすることができます。


---
layout: ../layouts/MdLayout.astro
title: AstorでMarkDown
---

# {frontmatter.title}

はじめて Astro を利用して MarkDown を書いています。

表示される内容は変わりませんがtitleを変更するとブラウザに表示されるh1タグの内容も変わります。

ビルドを実行するとdist/markdown/index.htmlが作成され下記の内容に変換されます。


<!DOCTYPE html>
<html>
  <head>
    <title>AstorでMarkDown</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <h1 id="astorでmarkdown">AstorでMarkDown</h1><p>はじめて Astro を利用して MarkDown を書いています。</p>
  </body></html>

Integrationsによるフレームワーク/ライブラリの追加

ここまではAstro Componentのみを利用してきましたが他のフレークワークやライブラリを利用したい場合の設定方法について確認していきます。

Astor IntegrationsではReact、Vue.js、TailwindなどのAstro公式のIntegrationsだけではなくSEOやImageに関する非公式のIntegrationsも提供されています。Integrationsを追加することで機能を拡張することができます。

Reactの利用

npx astro add reactコマンドでインストールを行うことができます。yarn, pnpxコマンドでもインストールできます。それぞれの方法についてはgithubのページを確認してください。


 % npx astro add react
✔ Resolving integrations...

  Astro will make the following changes to your config file:

 ╭ astro.config.mjs ─────────────────────────────╮
 │ import { defineConfig } from 'astro/config';  │
 │                                               │
 │ import react from "@astrojs/react";           │
 │                                               │
 │ // https://astro.build/config                 │
 │ export default defineConfig({                 │
 │   integrations: [react()]                     │
 │ });                                           │
 ╰───────────────────────────────────────────────╯

? Continue? › (Y/n)
  Astro will run the following command:
  If you skip this step, you can always run it yourself later

 ╭────────────────────────────────────────────────────────────────────────╮
 │ npm install --save-dev @astrojs/react react-dom@^18.0.0 react@^18.0.0  │
 ╰────────────────────────────────────────────────────────────────────────╯

✔ Continue? … yes
✔ Installing dependencies...
  
   success  Added the following integration to your project:
  - @astrojs/react

コマンドを実行するとAstroの設定ファイルであるastro.config.mjsにreactの設定が追加されます。


import { defineConfig } from 'astro/config';

import react from "@astrojs/react";

// https://astro.build/config
export default defineConfig({
  integrations: [react()]
});

インストールするだけでReactが利用可能になったので動作確認のためcomponentsフォルダにCounter.jsxファイルを作成します。作成したCounterコンポーネントはボタンをクリックすると画面上のカウントが増減するだけのコンポーネントです。


import { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>React Counter</h1>
      <div>{count}</div>
      <div>
        <button onClick={() => setCount(count + 1)}>increment</button>
        <button onClick={() => setCount(count - 1)}>decrement</button>
      </div>
    </>
  );
};

export default Counter;

作成したCounterコンポーネントをabout.astroファイルでimportします。


---
import Layout from '../layouts/Layout.astro';
import Counter from "../components/Counter"
---
<Layout title="Aboutページ">
  <h1>Astroについて</h1>
  <Counter />
</Layout>

ブラウザから/aboutにアクセスするとCounterコンポーネントで設定した内容が表示されます。Increment, decrementボタンをクリックしてください。どちらをクリックしてもカウントの数は変わりません。

Counterの表示
Counterの表示

Astroでは独自のディレクティブを持っておりクライアント側でのインタラクティブな操作を持つコンポーネントにはclient:loadディレクティブを設定する必要があります。設定しない場合は確認した通りJavaScriptのコードは動きません。


---
import Layout from '../layouts/Layout.astro';
import Counter from "../components/Counter"
---
<Layout title="Aboutページ">
  <h1>Astroについて</h1>
  <Counter client:load />
</Layout>

設定後はincrement, decrementボタンをクリックするとカウントの数が更新されます。

カウンターの増減の確認
カウンターの増減の確認

client:load以外にもclient:visibleなど:の後の設定値よって動作が変わるディレクティブがあります。例えばclient:visibleであればユーザのviewportに入った時にコンポーネントがloadされます。入っていない時にはloadされています。ブラウザのデベロッパーツールのネットワークタブを確認することで違いを確認することができます。

ビルドの実行

ディレクティブのclient loadを追加することによってクライアントでのインタラクティブな操作が実現できるようになった結果ビルド後に作成されるabout.htmlにどのような変化があったか確認します。

npm run buildコマンドを実行するとdistフォルダが作成されるのでabout/index.htmlファイルを確認します。Counterコンポーネントを追加する前にnpm run buildを実行した際はindex.htmlはHTMLのみで記述された下記の内容でした。

aboutページのファイルの中身を確認
aboutページのファイルの中身を確認

Conunterコンポーネントを追加してclient:loadディレクティブを追加すると下記のようなJavaScriptのコードが確認できます。

about.htmlファイルの内容の確認
about.htmlファイルの内容の確認

distフォルダにはclient.4fb2ea36.js, Couter.e0a91ce0.jsなどのJavaScriptファイルも作成されています。

postsフォルダの下には1,2,3,..100フォルダが作成され各フォルダの下にはindex.htmlファイルが作成されいます。

Counterコンポーネントは追加し、client:loadディレクティブを追加しなかった場合のビルド後のabout.htmlも確認しておきます。JavaScriptコードが含まれていないことが確認できます。JavaScriptのコードが存在しないのでボタンをクリックしても何も起こらないのも納得できます。

client:loadを設定していない場合
client:loadを設定していない場合

Astroではディレクティブのclient:load(JavaScriptをクライアント側で利用)を設定することでファイルのサイズが大きくなることがここまでの動作確認で理解できました。

Vue.jsの利用

ReactだけではなくVue.jsも利用できるように追加を行います。npx astro add reactコマンドでインストールを行うことができます。それぞれの方法についてはgithubのページを確認してください。


 % npx astro add vue
✔ Resolving integrations...

  Astro will make the following changes to your config file:

 ╭ astro.config.mjs ─────────────────────────────╮
 │ import { defineConfig } from 'astro/config';  │
 │ import react from "@astrojs/react";           │
 │                                               │
 │ import vue from "@astrojs/vue";               │
 │                                               │
 │ // https://astro.build/config                 │
 │ export default defineConfig({                 │
 │   integrations: [react(), vue()]              │
 │ });                                           │
 ╰───────────────────────────────────────────────╯

✔ Continue? … yes

  Astro will run the following command:
  If you skip this step, you can always run it yourself later

 ╭──────────────────────────────────────────────────╮
 │ npm install --save-dev @astrojs/vue vue@^3.2.30  │
 ╰──────────────────────────────────────────────────╯

✔ Continue? … yes
✔ Installing dependencies...
  
   success  Added the following integration to your project:
  - @astrojs/vue

Astroの設定ファイルastro.config.mjsにはVue.jsの設定が追加されます。Reactを先に追加しておいたので両方が追加された形で表示されます。


import { defineConfig } from 'astro/config';
import react from "@astrojs/react";

import vue from "@astrojs/vue";

// https://astro.build/config
export default defineConfig({
  integrations: [react(), vue()]
});

React, Vue.jsのどちらかを一方を一つのプロジェクトで利用できるというわけではなくコンポーネント毎に別々のフレームワーク/ライブラリを利用することができます。

Componentsフォルダに新たにCounterVue.vueファイルを作成します。Reactの場合と同様に作成したCounterVueコンポーネントはボタンをクリックすると画面上のカウントが増減するだけのコンポーネントです。


<script setup>
import { ref } from 'vue';

const count = ref(0);
</script>
<template>
  <h1>Vue Counter</h1>
  <div>{{ count }}</div>
  <div>
    <button @click="count++">increment</button>
    <button @click="count--">decrement</button>
  </div>
</template>

about.astroコンポーネントでCounterVueコンポーネントをimportします。


---
import Layout from '../layouts/Layout.astro';
import Counter from "../components/Counter"
import CounterVue from "../components/CounterVue.vue"
---
<Layout title="Aboutページ">
  <h1>Astroについて</h1>
  <Counter client:load />
  <CounterVue client:load />
</Layout>

ブラウザから/aboutにアクセスするとReactとVueで作成したコンポーネントが表示されボタンをクリックするとカウンターの数が増減します。どちらも問題なく動作することが確認できます。

カウンターの動作確認
カウンターの動作確認

Astroの特徴の一つである好きなフレームワークを利用できるということが確認できました。

Tailwindの場合

Tailwind CSSもnpx astro add tailwindコマンドでインストールすることができます。


 % npx astro add tailwind
✔ Resolving integrations...

  Astro will make the following changes to your config file:

 ╭ astro.config.mjs ─────────────────────────────╮
 │ import { defineConfig } from 'astro/config';  │
 │ import react from "@astrojs/react";           │
 │ import vue from "@astrojs/vue";               │
 │                                               │
 │ import tailwind from "@astrojs/tailwind";     │
 │                                               │
 │ // https://astro.build/config                 │
 │ export default defineConfig({                 │
 │   integrations: [react(), vue(), tailwind()]  │
 │ });                                           │
 ╰───────────────────────────────────────────────╯

✔ Continue? … yes

  Astro will run the following command:
  If you skip this step, you can always run it yourself later

 ╭───────────────────────────────────────────╮
 │ npm install --save-dev @astrojs/tailwind  │
 ╰───────────────────────────────────────────╯

✔ Continue? … yes
⠹ Installing dependencies...
✔ Installing dependencies...

  Astro will generate a minimal ./tailwind.config.cjs file.

✔ Continue? … yes
  
   success  Added the following integration to your project:
  - @astrojs/tailwind

インストール後Astroの設定ファイルであるastro.config.mjsファイルにTailwindの設定が追加されます。


import { defineConfig } from 'astro/config';
import react from "@astrojs/react";
import vue from "@astrojs/vue";

import tailwind from "@astrojs/tailwind";

// https://astro.build/config
export default defineConfig({
  integrations: [react(), vue(), tailwind()]
});

さらにtailwindの設定ファイルもtailwind.config.cjsファイルも作成されます。

追加の設定を何もしなくてもTailwindが利用できるためlocalhost:3000にアクセスするとh1タグのフォントサイズなどのデフォルトの値もTailwindによって解除されます。

Tailwindインストール後の画面
Tailwindインストール後の画面

h1タグの文字のサイズを大きくしたい場合はtailwindのclassを適用する必要があります。

まとめ

ビルドコマンドによって作成されるファイルの内容を確認することで冒頭で説明した”JavaScriptを可能な限り除いた静的なHTMLを作成する”という意味も理解できたかと思います。React, Vue.jsを追加インストールすることで好きなフレームワークを用いたコンポーネントの作成方法も理解することできました。