最近、静的サイトジェネレーターとして人気のAstroと、バージョン5で新しいリアクティビティAPI(Runes)が導入されたSvelte。今回はこの2つの技術を組み合わせた開発環境を、ハンズオン形式で実際に構築してみました。
最終的な構成
今回構築した環境の最終的なファイル構成は以下のようになりました。モノレポでの利用も想定し、frontend
ディレクトリ内にAstroプロジェクトを作成しています。
svelte-study/
├── .devcontainer/
│ └── devcontainer.json
├── frontend/
│ ├── .gitignore
│ ├── astro.config.mjs
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── README.md
│ ├── svelte.config.js
│ ├── tsconfig.json
│ ├── public/
│ │ └── favicon.svg
│ └── src/
│ ├── components/
│ │ └── Counter.svelte
│ └── pages/
│ └── index.astro
└── README.md
実際に作業したリポジトリはこちらで公開しています。DevContainerで動作するように設定済みです。
環境構築の手順
環境構築はpnpm
を使い、以下のコマンドを順番に実行していきました。
1. Astroプロジェクトの作成
まず、Astroのプロジェクトを最小限のテンプレートで作成します。
pnpm create astro@latest frontend --template minimal --typescript --install --git --yes
上記のコマンドでは、frontend
という名前のディレクトリに、TypeScriptが有効化された最小構成のAstroプロジェクトがGitリポジトリの初期化と同時にセットアップされます。
2. Svelte統合の追加
次に、作成したAstroプロジェクトにSvelteを追加します。
cd frontend
pnpm astro add svelte
このコマンドを実行すると、AstroがSvelteを扱えるように関連パッケージがインストールされ、設定ファイル(astro.config.mjs
, svelte.config.js
)が自動で更新・生成されました。非常にスムーズな統合体験でした。
3. Sassの追加
Svelteコンポーネント内でSCSS記法を使いたかったため、Sassも追加しました。
pnpm add -D sass
これで、Svelteの<style>
タグでlang="scss"
が使えるようになります。
4. 開発サーバーの起動
最後に、開発サーバーを起動して動作を確認します。
pnpm dev --host
今回はDevContainer環境で開発していたため、コンテナ外のブラウザからアクセスできるよう--host
オプションを付けています。
作成したファイルと実装のポイント
動作確認のために、いくつかのファイルを作成・編集しました。
カウンターコンポーネント(Counter.svelte)
Svelte 5の新しい記法$state
を試すため、簡単なカウンターコンポーネントを作成しました。
<script lang="ts">
let count = $state<number>(0);
function increment(): void {
count += 1;
}
function decrement(): void {
count -= 1;
}
function reset(): void {
count = 0;
}
</script>
<div class="counter">
<h2>Svelte Counter Component</h2>
<p class="count">Count: {count}</p>
<div class="buttons">
<button onclick={increment}>+</button>
<button onclick={decrement}>-</button>
<button onclick={reset}>Reset</button>
</div>
</div>
<style lang="scss">
.counter {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
text-align: center;
}
.count {
font-size: 1.5rem;
font-weight: bold;
margin: 1rem 0;
}
.buttons {
display: flex;
gap: 0.5rem;
justify-content: center;
}
button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
&:first-child {
background: #28a745;
color: white;
}
&:nth-child(2) {
background: #dc3545;
color: white;
}
&:last-child {
background: #007bff;
color: white;
}
&:hover {
opacity: 0.8;
}
}
</style>
<script lang="ts">
とすることでTypeScriptが有効になり、$state<number>(0)
のように型安全な状態管理ができています。また、<style lang="scss">
内でSCSSのネスト記法も問題なく使えました。
メインページ(index.astro)
作成したSvelteコンポーネントをAstroページで呼び出します。
---
import Counter from '../components/Counter.svelte';
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro + Svelte Demo</title>
</head>
<body>
<main>
<h1>Astro + Svelte 開発環境</h1>
<Counter client:load />
</main>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 2rem;
line-height: 1.6;
}
main {
text-align: center;
}
h1 {
color: #333;
margin-bottom: 1rem;
}
</style>
</body>
</html>
ここで重要なのが、<Counter client:load />
の部分です。Astroはデフォルトでコンポーネントをサーバーサイドでレンダリングしますが、インタラクティブな動作(今回の場合はボタンクリック)にはクライアントサイドのJavaScriptが必要です。client:load
ディレクティブを指定することで、ページ読み込みと同時にコンポーネントがハイドレーションされ、インタラクティブになります。
まとめ
以上の手順で、AstroとSvelte 5を組み合わせた最新の開発環境を非常に簡単に構築することができました。astro add
コマンドによるインテグレーションが優秀で、手動での煩雑な設定はほとんど必要ありませんでした。Svelte 5の新しい$state
記法も直感的で、少ない記述量でコンポーネントを記述できると感じました。