homeIcon

SvelteKit を使って分かった、React や Next.js との違い

フロントエンド
2025.08.10
2025.08.10

ReactやNext.jsを使う中で、ふと「もっと軽量で、開発体験がシンプルなフレームワークはないだろうか?」と思うことが増えてきました。そんな時に目に留まったのがSvelteKitです。
SvelteKitは「必要な機能は最小限の抽象で、HTMLやブラウザの標準挙動を尊重しながら提供する」という設計思想を持っています。

そこで、今回は簡単なブログアプリの作成を通して、実際に触ってみて分かったReact/Next.jsとの設計や開発体験の違いを具体的なコード例とともに紹介していこうと思います。

SvelteとSvelteKitについて

Svelteの特徴

Svelte(スベルト)は、コンパイラベースのJavaScriptフレームワークです。
ReactやVueのような仮想DOMを使わず、ビルド時に純粋なJavaScriptに変換されます。これにより、ランタイムのオーバーヘッドが減り、パフォーマンスが向上します。

例えば、Reactでカウンターを作る場合、以下のように useState が必要です。

// React
import { useState } from 'react';
 
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

一方、Svelteでは以下のようにシンプルに書けます。

<!-- Svelte -->
<script>
  let count = 0;
</script>
 
<button on:click={() => count++}>
  Count: {count}
</button>

countが変更されると、Svelteが自動でUIを更新します。この直感的な記述が、Svelteの開発体験(DX)の魅力です。

Svelte • Web development for the rest of us

No description available.

OGP Image

SvelteKitとは

SvelteKitは、Svelteをベースにしたフルスタックフレームワークで、Next.jsに似た機能を提供します。例えば、以下のような特徴があります:

  • ファイルベースのルーティング:フォルダ構造でページやAPIを定義。
  • SSR/SSG対応:サーバーサイドレンダリングや静的サイト生成が簡単。
  • APIルート:バックエンドAPIを同じプロジェクト内で構築可能。

SvelteKit アプリはデフォルトではサーバーでレンダリングを行うため、優れた初期ロードパフォーマンスと SEO 特性を備えています。
初回のロードのあとは (モダンなシングルページアプリ、SPA のような) クライアントサイドナビゲーションに移行するため、ユーザーが画面遷移する際の全読み込みを回避できます。

イントロダクション • Docs • Svelte

No description available.

OGP Image

簡単なブログ風アプリを作ってみる

SvelteKitのルーティング

SvelteKitはファイルベースのルーティングを採用しており、プロジェクトのsrc/routes/フォルダ内のファイル構造がそのままURLに対応します。

例えば:

  • src/routes/+page.svelte → トップページ (/)
  • src/routes/blog/+page.svelte → ブログ一覧ページ (/blog)
  • src/routes/about/+page.svelte → Aboutページ (/about)

今回は、以下のページを作成します:

  • トップページ(/
  • ブログ一覧ページ (/blog):記事のリストを表示。
  • 記事詳細ページ (/blog/[slug]):個別の記事内容を表示。

1. SvelteKitプロジェクトのセットアップ

1.1 プロジェクトの作成

SvelteKitのプロジェクトは、以下のコマンドで簡単に作成できます。

npx sv create sample-blog

実行後、以下の選択肢を選びます:

  • テンプレート:SvelteKit minimal
  • TypeScript:Yes
  • その他インストールしたいもの:tailwindcss(ESLint/Prettierなどは任意)
  • パッケージマネージャー:npm

セットアップ後、プロジェクトに移動して依存パッケージをインストールします:

cd sample-blog
npm install

開発サーバーを起動して、初期状態を確認しましょう:

npm run dev

ブラウザでhttp://localhost:5173を開くと、以下のようなSvelteKitのウェルカムページが表示されます。

画像1

1.2 基本レイアウトの作成

ブログの基本レイアウト(ナビゲーションとフッター)を作ります。SvelteKitでは、src/routes/+layout.svelteが全ページに適用されるレイアウトファイルです。

src/routes/+layout.svelte
<script>
  import "../app.css";
</script>
 
<header>
  <h1>sample-blog</h1>
  <a href="/" class="text-blue-500 underline">Home</a>
  <a href="/blog" class="text-blue-500 underline">Blog</a>
</header>
 
<slot />
 
<footer>
  <p>
    Powered by
    <a href="https://svelte.dev" class="text-blue-500 underline">Svelte</a>
  </p>
  <p>© 2025 Miyazaki</p>
</footer>

<slot />は、各ページのコンテンツを挿入する場所です。

1.3 トップページの作成

トップページを作成するため、src/routes/+page.svelteを編集します。

src/routes/+page.svelte
<div class="my-5 font-bold">
  <h2 class="h2">Welcome to My Blog!</h2>
  <p>This is a personal blog built with SvelteKit.</p>
</div>

画面はこんな感じ。

画像2

2. Svelte-Queryのセットアップ

2.1 Svelte-Queryとは?

Svelte-Queryは、Svelte向けのデータフェッチングライブラリで、React Queryにインスパイアされています。APIリクエストを簡単に管理し、以下のような機能を提供します:

  • 自動キャッシュ:取得したデータをキャッシュして再利用。
  • ローディング/エラー状態:状態管理を簡潔に処理。
  • 自動リフェッチ:データが古くなった場合に自動更新。

今回はこれを使用して、外部API(JSONPlaceholder)を利用することでブログデータを取得します。
Svelte-Queryをプロジェクトに追加します。

npm install @sveltestack/svelte-query

2.2 QueryClient の作成

API などから取得したデータの自動でキャッシュや、再フェッチ・更新の管理を行うQueryClientを生成します。

src/lib/queryClient.jsを作成:

src/lib/queryClient.js
import { QueryClient } from '@sveltestack/svelte-query';
export const queryClient = new QueryClient();

2.3 QueryClientProvider をレイアウトで使用

2.2で作成したQueryClientを用いて、全てのページ・コンポーネントで一貫してデータフェッチやキャッシュ管理をするために、QueryClientProvider をアプリ全体に適用します。
QueryClientProviderQueryClientを適用するためのラッパーコンポーネントです。

src/routes/+layout.svelteを以下のように修正します。

src/routes/+layout.svelte
<script>
  import "../app.css";
  import { QueryClientProvider } from "@sveltestack/svelte-query"; // svelte-query から QueryClientProvider をインポート
  import { queryClient } from "$lib/queryClient"; // queryClient インスタンスをインポート
</script>
 
<header>
  <h1>sample-blog</h1>
  <a href="/" class="text-blue-500 underline">Home</a>
  <a href="/blog" class="text-blue-500 underline">Blog</a>
</header>
 
<!-- アプリケーション全体を QueryClientProvider でラップ -->
<QueryClientProvider client={queryClient}> 
  <slot />
</QueryClientProvider> 
 
<footer>
  <p>
    Powered by
    <a href="https://svelte.dev" class="text-blue-500 underline">Svelte</a>
  </p>
  <p>© 2025 Miyazaki</p>
</footer>

3. ブログ一覧ページの作成

src/routes/blog/+page.svelteを作成し、以下を記述:

src/routes/blog/+page.svelte
<script>
  import { useQuery } from "@sveltestack/svelte-query";
 
  const query = useQuery("posts", async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts");
    if (!response.ok) throw new Error("データの取得に失敗しました");
    return response.json();
  });
</script>
 
<div>
  <h1>ブログ記事一覧</h1>
 
  {#if $query.isLoading}
    <div>
      <p>読み込み中...</p>
    </div>
  {:else if $query.isError}
    <p>
      エラー: {typeof $query.error === "object" && $query.error && "message" in $query.error
      ? $query.error.message : "不明なエラー"}
    </p>
  {:else}
    <div>
      {#each $query.data as post}
        <div class="my-5">
          <h2 class="text-xl font-bold">
            {post.title}
          </h2>
          <p>投稿ID: {post.id}</p>
          <p>
            {post.body.slice(0, 30)}...
          </p>
          <a href="/blog/{post.id}" class="text-blue-500 underline">
            続きを読む →
          </a>
        </div>
      {/each}
    </div>
  {/if}
</div>

解説:

  • useQueryフックを使って、postsキーでAPIデータを取得。
  • $query.isLoadingでローディング状態を表示。
  • $query.isErrorでエラー状態を処理。
  • データが取得できたら($query.data)、#eachディレクティブで記事をループ表示。
  • JSONPlaceholderのidslugとして詳細ページにリンク。

4. 記事詳細ページの作成

4.1 ルートデータの取得

SvelteKitでは、ダイナミックルートのために+page.js(または+page.server.js)でデータを準備できます。

src/routes/blog/[slug]/+page.jsを作成:

src/routes/blog/[slug]/+page.js
/** @param {{ params: { slug: string } }} context */
export function load({ params }) {
return {
  slug: params.slug
};
}

このload関数は、URLの[slug]部分をdata.slugとしてページに渡します。これにより、ページ側でslugを使って記事を検索できます。

4.2 ダイナミックルートの作成

記事詳細ページは、URLのslugに基づいて表示します。

src/routes/blog/[slug]/+page.svelteを作成:

src/routes/blog/[slug]/+page.svelte
<script>
import { useQuery } from "@sveltestack/svelte-query";
import { error } from "@sveltejs/kit";
 
export let data;
 
const query = useQuery(["post", data.slug], async () => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${data.slug}`
  );
  if (!response.ok) throw error(404, "記事が見つかりません");
  return response.json();
});
</script>
 
<div class="my-5">
 {#if $query.isLoading}
   <div>
     <p>読み込み中...</p>
   </div>
 {:else if $query.isError}
   <p>
     エラー: {typeof $query.error === "object" && $query.error && "message" in $query.error
     ? $query.error.message : String($query.error)}
   </p>
 {:else}
   <h1 class="text-xl font-bold">{$query.data.title}</h1>
   <p>投稿ID: {$query.data.id}</p>
   <p>{$query.data.body}</p>
   <a href="/blog" class="text-blue-500 underline"> ← 一覧に戻る </a>
 {/if}
</div>

解説:

  • export let dataで、SvelteKitが提供するslugを受け取る。
  • postsからslugに一致する記事を検索。見つからない場合は404エラーを投げる。

5. 動作確認

改めて開発サーバーを起動します。

npm run dev

ブラウザでhttp://localhost:5173を開くと、以下のようなブログサイト風のものができています。

▼ ブログ一覧ページ

画像3

▼ 記事詳細ページ

画像4

所感

今回、SvelteKit を使ってブログ風アプリを構築してみて、「HTML・CSS・JavaScriptの標準仕様を最大限活かしつつ、必要な部分だけをフレームワークが補ってくれる」 という感覚を強く持ちました。
React / Next.js のようにフックやコンポーネントライフサイクルを明示的に扱う必要が少なく、let で宣言した変数を書き換えるだけで UI が再描画されるのは、とても直感的です。

特に印象的だったのは以下の点です

  • リアクティビティがシンプル
    React では useStateuseEffect を意識して状態管理しますが、Svelte では単に変数を更新すれば自動で反映されるため、状態管理のためのボイラープレートが大幅に減りました。

  • API 連携が分かりやすい
    +page.js の load 関数でデータ取得を明確に分離でき、SSR/SSGの切り替えが直感的でした。Next.js の getServerSidePropsgetStaticProps よりも構造がシンプルに感じました。

  • 初期レンダリングが軽快
    バンドルサイズが小さく、ランタイムオーバーヘッドも少ないため、初回表示までが非常に速いです。Next.js の App Router でも最適化は進んでいますが、素のパフォーマンスは SvelteKit に軍配が上がる場面がありました。

React / Next.js などのフレームワークとはまた違う、シンプルさと直感的な記述ができると感じました。

さいごに

今回は、SvelteKit を実際に触ってみて感じた React / Next.js との違いや特徴を紹介しました。
まだエコシステムの規模では React / Next.js に及ばない部分もありますが、そのシンプルさやパフォーマンスは魅力的で、特に小規模〜中規模のプロジェクトでは有力な選択肢になり得ると感じました。

この記事が、これから SvelteKit を試してみたい方や、他フレームワークとの比較検討をしている方の参考になれば嬉しいです。

参考

Share