SvelteKit
Svelteベースのフルスタックフレームワーク。SSGモードも提供し、17k超のGitHubスターを誇る軽量高速フレームワーク。
トレンド・動向
Svelteの軽量性とパフォーマンスを活かしたSSGとして注目。コンパイル時最適化により高速サイトを生成。
# 静的サイトジェネレータ
SvelteKit
## 概要
SvelteKitは、Svelteベースのフルスタックフレームワークで、強力なSSG機能も提供します。17k超のGitHubスターを誇る軽量高速フレームワークで、Svelteの軽量性とパフォーマンスを活かしたSSGとして注目されています。コンパイル時最適化により高速サイトを生成します。
## 詳細
SvelteKitは2020年から開発が始まった次世代フレームワークで、従来のJavaScriptフレームワークとは異なるアプローチを採用しています。Svelteのコンパイル時最適化により、ランタイムでのオーバーヘッドを最小限に抑え、極めて高速なサイトを生成できます。
### 主要機能
#### 1. 柔軟なレンダリングモード
- **静的生成(SSG)**: `adapter-static`を使用してビルド時に全ページを事前レンダリング
- **サーバーサイドレンダリング(SSR)**: 動的なサーバーレンダリング
- **シングルページアプリケーション(SPA)**: クライアントサイドのみのレンダリング
- **プリレンダリング**: 選択的なページ事前レンダリング
#### 2. Svelte駆動の軽量設計
- **コンパイル時最適化**: ビルド時にフレームワークコードを除去
- **ゼロランタイム**: 最小限のJavaScriptバンドル
- **ファイルベースルーティング**: 直感的なディレクトリベースルーティング
- **TypeScript統合**: ファーストクラスのTypeScriptサポート
#### 3. パフォーマンス重視の設計
- **高速ビルド**: 効率的なビルドプロセス
- **最小バンドルサイズ**: 不要なコードの自動除去
- **プリロード戦略**: インテリジェントなコードプリロード
- **SEO最適化**: 組み込みのメタタグとSEOサポート
#### 4. 開発者体験
- **ホットリロード**: 高速な開発環境での変更反映
- **型安全性**: 自動生成された型定義
- **エラーハンドリング**: 分かりやすいエラーメッセージ
- **デバッグツール**: 統合されたデバッグ機能
## メリット・デメリット
### メリット
- **軽量性**: Svelteの特性により極めて軽量なバンドルサイズ
- **高速パフォーマンス**: コンパイル時最適化による高いランタイム性能
- **学習コストの低さ**: シンプルな構文とファイルベースルーティング
- **柔軟性**: 複数のレンダリングモードとアダプターサポート
- **TypeScript統合**: 優秀なTypeScript開発体験
- **SEOフレンドリー**: 静的生成による検索エンジン最適化
### デメリット
- **エコシステム**: ReactやVueと比較してライブラリが少ない
- **コミュニティサイズ**: より小さなコミュニティ
- **企業採用**: 大企業での採用事例がまだ限定的
- **学習リソース**: ドキュメントや学習教材が比較的少ない
## 参考ページ
- [公式サイト](https://kit.svelte.dev/)
- [Svelteドキュメント](https://svelte.dev/docs)
- [GitHubリポジトリ](https://github.com/sveltejs/kit)
- [アダプター一覧](https://kit.svelte.dev/docs/adapters)
- [チュートリアル](https://learn.svelte.dev/)
## 書き方の例
### 1. インストールとセットアップ
**SvelteKitプロジェクトの作成**
```bash
# 新しいSvelteKitプロジェクトを作成
npm create svelte@latest my-sveltekit-app
cd my-sveltekit-app
# 依存関係をインストール
npm install
# 開発サーバーを起動
npm run dev
```
**SSG用のsvelte.config.js**
```javascript
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
// 出力ディレクトリ設定
pages: 'build',
assets: 'build',
fallback: undefined,
precompress: false,
strict: true
}),
paths: {
base: process.env.NODE_ENV === 'production' ? '/my-site' : ''
}
}
};
```
### 2. ページ作成とルーティング
**src/routes/+page.svelte**
```svelte
<script>
// ページメタデータ
import { page } from '$app/stores';
export let data;
</script>
<svelte:head>
<title>ホームページ - SvelteKitサイト</title>
<meta name="description" content="SvelteKitで構築した静的サイト" />
</svelte:head>
<main>
<h1>SvelteKitサイトへようこそ</h1>
<p>高速で軽量な静的サイトです。</p>
<a href="/blog">ブログを見る</a>
</main>
<style>
main {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
h1 {
color: #ff3e00;
text-align: center;
}
</style>
```
**src/routes/+layout.js**
```javascript
// 全ページの事前レンダリングを有効化
export const prerender = true;
```
### 3. 動的ルートとデータ取得
**src/routes/blog/[slug]/+page.js**
```javascript
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export async function load({ params }) {
try {
const post = await import(`../../../posts/${params.slug}.md`);
return {
content: post.default,
meta: post.metadata
};
} catch (e) {
throw error(404, `投稿が見つかりません: ${params.slug}`);
}
}
// 動的ルートの事前レンダリング設定
export const prerender = true;
/** @type {import('./$types').EntryGenerator} */
export function entries() {
return [
{ slug: 'first-post' },
{ slug: 'second-post' },
{ slug: 'third-post' }
];
}
```
**src/routes/blog/[slug]/+page.svelte**
```svelte
<script>
export let data;
</script>
<svelte:head>
<title>{data.meta.title} - ブログ</title>
<meta name="description" content={data.meta.description} />
</svelte:head>
<article>
<header>
<h1>{data.meta.title}</h1>
<time datetime={data.meta.date}>{data.meta.date}</time>
</header>
<div class="content">
<svelte:component this={data.content} />
</div>
</article>
<style>
article {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
header {
margin-bottom: 2rem;
border-bottom: 1px solid #eee;
padding-bottom: 1rem;
}
.content {
line-height: 1.6;
}
</style>
```
### 4. 状態管理
**src/lib/stores.js**
```javascript
import { writable } from 'svelte/store';
// テーマ管理
export const theme = writable('light');
// ユーザー設定
export const userSettings = writable({
language: 'ja',
notifications: true
});
// カウンター例
export const count = writable(0);
```
**src/routes/settings/+page.svelte**
```svelte
<script>
import { theme, userSettings } from '$lib/stores.js';
function toggleTheme() {
theme.update(t => t === 'light' ? 'dark' : 'light');
}
</script>
<main>
<h1>設定</h1>
<section>
<h2>外観</h2>
<label>
<input type="radio" bind:group={$theme} value="light" />
ライトテーマ
</label>
<label>
<input type="radio" bind:group={$theme} value="dark" />
ダークテーマ
</label>
</section>
<section>
<h2>言語設定</h2>
<select bind:value={$userSettings.language}>
<option value="ja">日本語</option>
<option value="en">English</option>
</select>
</section>
</main>
```
### 5. フォーム処理
**src/routes/contact/+page.server.js**
```javascript
import { fail } from '@sveltejs/kit';
/** @type {import('./$types').Actions} */
export const actions = {
default: async ({ request }) => {
const data = await request.formData();
const name = data.get('name');
const email = data.get('email');
const message = data.get('message');
// バリデーション
if (!name || !email || !message) {
return fail(400, {
error: '全ての項目を入力してください',
name,
email,
message
});
}
// メール送信処理(実装は省略)
console.log('お問い合わせ受信:', { name, email, message });
return {
success: true
};
}
};
```
**src/routes/contact/+page.svelte**
```svelte
<script>
import { enhance } from '$app/forms';
export let form;
</script>
<svelte:head>
<title>お問い合わせ</title>
</svelte:head>
<main>
<h1>お問い合わせ</h1>
{#if form?.success}
<div class="success">
お問い合わせありがとうございました。
</div>
{/if}
{#if form?.error}
<div class="error">
{form.error}
</div>
{/if}
<form method="POST" use:enhance>
<label>
お名前
<input type="text" name="name" value={form?.name ?? ''} required />
</label>
<label>
メールアドレス
<input type="email" name="email" value={form?.email ?? ''} required />
</label>
<label>
メッセージ
<textarea name="message" required>{form?.message ?? ''}</textarea>
</label>
<button type="submit">送信</button>
</form>
</main>
<style>
form {
max-width: 500px;
margin: 0 auto;
}
label {
display: block;
margin-bottom: 1rem;
}
input, textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
background: #ff3e00;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.success {
background: #d4edda;
color: #155724;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.error {
background: #f8d7da;
color: #721c24;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
</style>
```
### 6. デプロイとビルド
**静的サイトのビルド**
```bash
# 静的サイトを生成
npm run build
# ローカルでプレビュー
npm run preview
```
**package.jsonのスクリプト例**
```json
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
}
}
```
**GitHub Pagesへのデプロイ設定**
```javascript
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
const dev = process.argv.includes('dev');
export default {
kit: {
adapter: adapter({
fallback: '404.html'
}),
paths: {
base: dev ? '' : process.env.BASE_PATH
}
}
};
```