4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Svelte】Svelte の基礎を理解する

Last updated at Posted at 2025-10-15

本記事の目的

  • Svelte とは何かを理解する
  • Svelte の特徴を理解する
  • Svelte の基本的な書き方を理解する

本記事は2025年10月現在の最新バージョン 5.39 に則った内容となっています。

目次

  1. Svelte とは
  2. Svelte の特徴
  3. SvelteKit とは
  4. アプリケーションを新規作成
  5. コンポーネントの基本
  6. コンポーネントを使用する
  7. マークアップ内の記法
  8. イベントハンドラ
  9. ルーン(Runes)
  10. $state:リアクティブな値の定義
  11. $derived:リアクティブな値に基づいて計算される値を定義
  12. $effect:リアクティブな値の更新に副作用を定義
  13. $props:親コンポーネントから渡された props を取得
  14. $inspect:リアクティブな値をデバッグ
  15. ライフサイクルフック

Svelte とは

Svelte(スヴェルト) は、2016年に Rich Harris 氏によって発表された JavaScript のフロントエンドフレームワークです。

State of JS 2024 でもポジティブな印象が多いです。Satisfaction 項目(実際に使ってみて好印象を抱いた人の割合)でも、Solid に続く高順位となっています。

Screenshot 2025-10-10 at 17.42.04.png

出典:https://2024.stateofjs.com/en-US/libraries/front-end-frameworks/

ちなみに「Svelte」という単語は、英語で「細い・スレンダーな」みたいな意味です。Svelte 特有の軽量さが由来となっていそうです。

Svelte の特徴

仮想 DOM を使用していない

React や Vue では UI の更新に 仮想 DOM と呼ばれる仕組みを採用しています。

実際の DOM とは別にメモリ上に仮想 DOM を保持し、ユーザー操作で変更が起きると、まず仮想 DOM を更新し、実際の DOM と比較(diffing)して差分だけを反映する仕組みです。

仮想 DOM については こちらの動画 が分かりやすいので併せてご覧ください。

これは効率的な UI 更新を可能にする一方で、diffing による計算負荷や UI 更新の遅延仮想 DOM の保持によるメモリの圧迫仮想 DOM 関連のコードがバンドルに含まれることによるアプリケーションサイズの肥大化 といった問題も指摘されています。

対して Svelte は仮想 DOM を使用せず、コンパイル時に最適化された DOM 操作コードを生成します。これにより、仮想 DOM のように効率良く UI 操作を行いつつ、先述した仮想 DOM が抱えていた課題を解決しています。

軽量

Svelte はビルド時にコードをコンパイルして、軽量で効率的な JavaScript を生成します。

React や Vue などのフレームワークのように仮想 DOM に関連するコードや、フレームワーク独自のランタイム JavaScript が生成されないため、バンドルサイズが小さく、実行時のオーバーヘッドも少なくなります。

実際に、Vite で作成したアプリケーションをビルドして gzip 圧縮後のサイズを比較したところ、Vue は約 24 KB、React は約 60 KB だったのに対して、Svelte はわずか約 10 KB でした。
他のフレームワークと比べても、Svelte が非常に軽量であることが分かります。

SvelteKit とは

SvelteKit は、Svelte を基盤としたフルスタックフレームワークです。

Svelte の基本機能に加えて、ファイルベースルーティングやサーバーサイドレンダリング(SSR)など、Web アプリケーション開発に必要な機能を提供します。

React における Next.js、Vue における Nuxt のような立ち位置のフレームワークです。

本記事では SvelteKit は使用しない前提となっています。

アプリケーションを新規作成

以下のコマンドを実行すると、Vite を使ったアプリケーションの作成が開始されます。
コマンドライン上で使用するフレームワークを聞かれるので、Svelte を選択してください。

npm create vite@latest
│
◇  Select a framework: # 使用するフレームワーク。Svelte を選んでください。
│  Svelte
│

アプリケーションが作成されたら、そのフォルダ内で以下のコマンドを実行すると開発サーバーが起動します。

npm run dev

ブラウザで http://localhost:5173 にアクセスすると、以下のような画面が表示されます。

Screenshot 2024-12-14 at 16.56.35.png

これで、Svelte アプリケーションを新規作成できました👏✨

コンポーネントの基本

拡張子

コンポーネントのファイル拡張子には、.svelte を使用します。

コンポーネント内の構造

JavaScript、HTML、CSS を 1 つのファイルにまとめて記述するシングルファイルコンポーネント形式を採用しています。

script タグ内には JavaScript を記述します。lang 属性を指定することで TypeScript も利用できます。

style タグ内には CSS を記述します。lang 属性を使って SCSS などのプリプロセッサを利用することもできます。

それ以外で記述した HTML タグが、実際にブラウザ上に描画されます。

<script>
  /* ここに JavaScript を記述します */
</script>

<!-- マークアップ(HTML)を記述します -->

<style>
  /* ここに CSS を記述します */
</style>

コンポーネントを使用する

定義したコンポーネントは、script 内でインポートしてマークアップ内で使用することができます。

<script>
  import UserIcon from "./lib/UserIcon.svelte";
</script>

<div>
  <h1>Welcome to my app!</h1>
  <UserIcon />
</div>

マークアップ内の記法

変数の参照

マークアップ内では、{ } を使って script 内で定義した変数を参照できます。

<script>
  let message = "Hello!";
</script>

<p>{message}</p> <!-- Hello! -->

条件付き描画

if ブロックを使うと、画面要素の描画に条件を付けることができます。

{#if <条件>} のように記述し、最後は {/if} でブロックを閉じます。

<script>
  let count = 11;
</script>

{#if count > 10}
	<p>{count} is greater than 10</p>
{/if}

<!-- <p>11 is greater than 10</p> -->

{:else} を使って、条件に合致しなかった場合の要素を表示することもできます。

{#if count > 10}
	<p>{count} is greater than 10</p>
{:else}
	<p>{count} is between 0 and 10</p>
{/if}

{:else if <条件>} を使って、複数の条件を分岐することもできます。

{#if count > 10}
	<p>{count} is greater than 10</p>
{:else if count < 5}
	<p>{count} is less than 5</p>
{:else}
	<p>{count} is between 5 and 10</p>
{/if}

繰り返し描画

each ブロックを使うと、配列や反復可能なデータをもとに要素を繰り返し描画できます。
{#each <配列> as <現在の要素>} のように記述し、最後は {/each} でブロックを閉じます。

<script lang="ts">
  const users = [
    { id: 1, name: "Adam" },
    { id: 2, name: "Ben" },
    { id: 3, name: "Charles" },
  ];
</script>

{#each users as user}
  <p>{user.name}</p>
{/each}

<!--
<p>Adam</p>
<p>Ben</p>
<p>Charles</p>
-->

as の第二引数から、現在の要素のインデックスを参照することもできます。

{#each users as user, index}
  <p>{index}: {user.name}</p>
{/each}

<!--
<p>0: Adam</p>
<p>1: Ben</p>
<p>2: Charles</p>
-->

リストの更新を伴う場合は、意図しない挙動を避けるためにキーを指定します。
{#each <配列> as <現在の要素> (<キー>)} のように記述します。

{#each users as user (user.id)}
  <p>{user.name}</p>
{/each}

イベントハンドラ

on<イベント名> を指定することで、イベントハンドラを定義できます。

<!-- クリック時にアラートを表示する -->
<script>
  function handleClick() {
    alert("Clicked!");
  }
</script>

<button onclick={handleClick}>
  Click me
</button>

以下は代表的なイベント名の例です。これらは HTML のイベント属性と同じ名前で、Svelte 独自の命名はありません。

  • onclick:クリック時
  • ondblclick:ダブルクリック時
  • oninput:入力値の変更時(リアルタイム)
  • onchange:入力値の変更確定時(フォーカスが外れたときなど)
  • onsubmit:フォームの送信時

Svelte v4 までは、on:<イベント名> のように on: ディレクティブを使用していましたが、v5 からは非推奨となりました。

参照: https://svelte.dev/docs/svelte/legacy-on

ルーン(Runes)

Svelte v5 では、「ルーン(Runes)」と呼ばれる特別な構文が導入されました。

ルーンは $state$props のように $ から始まる構文で、.svelte ファイル内で インポートせずに 使用できます。これらは Svelte コンパイラに対して「このコードをどう扱うか」を指示する 役割を持ちます。

たとえば、$state は値をリアクティブに扱うようコンパイラへ指示します。コンパイラはこの構文を解析し、内部的にリアクティビティを実現するコードへと変換します。

let message = $state("Hello!");

$state :リアクティブな値(状態)を定義

$state を使うと、リアクティブに変化する値(状態)を定義できます。

状態が更新されると、その変更が即座に画面へ反映される仕組みを提供します。

React で言う useState、Vue で言う ref に相当します。

引数には、状態のデフォルト値を渡すことが可能です。

<script>
  let count = $state(0);
</script>

<button onclick={() => count++}>
  clicks: {count}
</button>

TypeScript を使用している場合は、ジェネリクスを指定することで状態の型を定義できます。

let count = $state<number>(0);

$derived :リアクティブな値に基づいて計算される値を定義

$derived を使うと、$state などを用いて定義されたリアクティブな値に基づいて計算される値を定義できます。

依存する値が変更されると自動的に再計算され、常に最新の状態に基づいた値が返されます。

React で言う useMemo、Vue で言う computed に相当します。

<script>
  let count = $state(0);
  let doubled = $derived(count * 2); // count を 2 倍した値
</script>

<button onclick={() => count++}>
  count: {count}
</button>

<p>doubled: {doubled}</p>

TypeScript を使用している場合は、ジェネリクスを指定することで計算結果の型を定義できます。

let doubled = $derived<number>(count * 2);

$effect :リアクティブな値の更新に副作用を定義

$effect を使うと、$state$derived などで定義されたリアクティブな値が変化したときに、自動的に実行される処理(副作用)を定義できます。

引数として渡したコールバック関数が実際の副作用であり、その中で参照しているリアクティブな値を自動的に監視します。

React で言う useEffect、Vue で言う watch に相当します。

<script>
  let count = $state(0);

  $effect(() => {
    console.log(`count changed: ${count}`);
  });
</script>

<button onclick={() => count++}>
  count: {count}
</button>

$props :親コンポーネントから渡された props を取得

$props を使用すると、親コンポーネントから渡された値(props)を取得できます。

$props() は、渡されたすべての props をオブジェクト形式で返します。分割代入を使って、参照したい値だけを取り出すのが一般的な書き方です。

<script>
  import Message from "./Message.svelte";
</script>

<Message content="Hello!" />
<script>
  let { content } = $props();
</script>

<p>{content}</p> <!-- Hello! -->

TypeScript を使用している場合は、以下のように props の型を定義できます。ジェネリクスではない点に注意してください。

<script lang="ts">
  interface Props {
    content: string;
  }

  let { content }: Props = $props();
</script>

$inspect :リアクティブな値をデバッグ

$inspect を使用すると、$state$derived などで定義されたリアクティブな値の変化を、開発時にコンソール上で確認することができます。

開発時のデバッグ用途のため、本番ビルド時には自動的に削除されます。

$inspect(count, doubled) のように、デバッグ対象を複数指定することも可能です。

<script>
  let count = $state(0);

  $inspect(count);
</script>

<button onclick={() => count++}>
  count: {count}
</button>

引数で指定された値が更新される度に、ブラウザのコンソールに以下のように値の変化が出力されます。

init 0
update 1
update 2

ライフサイクルフック

Svelte コンポーネントのライフサイクルは、主に DOM の生成と破棄の 2 つのフェーズで構成されます。

これらのタイミングに処理を挟み込むために、ライフサイクルフックが提供されています。

DOM が生成された後

onMount を使うと、コンポーネントの DOM が生成され、document に追加された直後(初回マウント時)に一度だけ実行する処理 を定義できます。

初期データのフェッチ、外部 API の呼び出し、DOM 要素へのイベントリスナーの追加などによく使われます。

イベントリスナーの解除などのクリーンアップが必要な処理を行う場合は、関数内で関数を return することで、アンマウント時(ページ遷移などによって DOM が破棄される際)に実行されるクリーンアップ関数を定義できます。

<script>
  import { onMount } from "svelte";

  onMount(() => {
    console.log("mounting");
    const interval = setInterval(() => {
      console.log("beep");
    }, 1000);

    // クリーンアップ関数
    return () => clearInterval(interval);
  });
</script>

DOM が更新される前

$effect.pre を使うと、DOM が更新される直前に実行する処理 を定義できます。

状態が変化して DOM に反映される 前の段階 で、古い状態の DOM をもとに何らかの処理を行いたい場合に有効です。

以下の例では、food の変更時に $effect.pre が実行されますが、この時点では DOM がまだ更新されていないため、el.textContent には古い値が残っています。

更新後の DOM を参照したい場合には、$effect を使用してください。

$effect.pre および $effect は、厳密にはライフサイクルフックではなく ルーン である点に注意してください。

<script>
  let food = $state("🌶️");
  let el = $state();

  $effect.pre(() => {
    food;
    console.log("before update:", el?.textContent); // DOM 更新前の値が参照される
  });

  $effect(() => {
    food;
    console.log("after update:", el?.textContent); // DOM 更新後の値が参照される
  });

  const update = () => (food = food === "🌶️" ? "🥑" : "🌶️");
</script>

<button onclick={update}>Update</button>
<p bind:this={el}>{food}</p>

DOM が破棄される前

onDestroy を使うと、ページ遷移などによってコンポーネントが破棄される直前に一度だけ実行される処理 を定義できます。

イベントリスナーの削除、タイマーのクリア、外部リソースの解放など、クリーンアップ処理に使用します。

onMount のクリーンアップ関数と実行タイミングは同じですが、onDestroy は単体で呼び出してクリーンアップ処理を記述する点が異なります。
複数の箇所で後処理をまとめたい場合や、onMount とは独立したクリーンアップが必要な場合に便利です。

<script>
  import { onDestroy } from 'svelte';

  onDestroy(() => {
    console.log('the component is being destroyed');
  });
</script>
4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?