Svelte 5正式リリース - Runesによる新しいリアクティビティシステム

2025.12.02

Svelte 5の概要

Svelte 5は、フレームワークの根本的な進化となるメジャーリリースです。「Runes」と呼ばれる新しいリアクティビティシステムにより、より明示的で予測可能なコードが書けるようになりました。

flowchart TB
    subgraph Svelte5["Svelte 5 主要な変更点"]
        subgraph Runes["Runes (新リアクティビティ)"]
            R1["$state() - リアクティブな状態宣言"]
            R2["$derived() - 派生値の計算"]
            R3["$effect() - 副作用の実行"]
            R4["$props() - コンポーネントのプロパティ"]
            R5["$bindable() - 双方向バインディング可能なプロップ"]
        end

        subgraph Perf["パフォーマンス向上"]
            P1["最大2倍の高速化"]
            P2["バンドルサイズ削減"]
            P3["メモリ使用量の改善"]
            P4["より効率的な差分検出"]
        end

        subgraph DX["開発者体験"]
            D1["TypeScriptサポート強化"]
            D2["より明示的なリアクティビティ"]
            D3["デバッグの容易さ"]
            D4["段階的な移行パス"]
        end
    end

Runesの基本

$state - リアクティブな状態





Name: {user.name}

    {#each items as item}
  • {item}
  • {/each}

$derived - 派生状態



Count: {count}

Doubled: {doubled}

Stats: Sum={stats.sum}, Avg={stats.avg}

$effect - 副作用


コンポーネントのプロパティ

$props








$bindable - 双方向バインディング




 value = e.currentTarget.value}
/>





Hello, {name}!

Snippets(スニペット)




{#snippet row(item)}
  
    {item.name}
    ¥{item.price}
  
{/snippet}

{#snippet header()}
  
    Name
    Price
  
{/snippet}



    {@render header()}
  
    {#each items as item (item.id)}
      {@render row(item)}
    {/each}
  
  
  

Svelte 4 vs Svelte 5 比較

機能Svelte 4Svelte 5
リアクティブ変数let count = 0;let count = $state(0);
派生値$: doubled = c * 2;let doubled = $derived(c*2);
副作用$: console.log(c);$effect(() => log(count));
プロパティexport let name;let { name } = $props();

イベントハンドリング














...
console.log(e.detail)} />

クラスコンポーネント













マイグレーション

自動マイグレーション

# svelte-migrateを使用
npx sv migrate svelte-5

# または特定のファイル
npx sv migrate svelte-5 src/components/Button.svelte

段階的な移行







// svelte.config.js
export default {
  compilerOptions: {
    // Runesを無効化してレガシーモードで動作
    runes: false
  }
};

SvelteKit統合

// +page.svelte
<script>
  let { data } = $props();

  let posts = $state(data.posts);
  let search = $state('');

  let filtered = $derived(
    posts.filter(p => p.title.toLowerCase().includes(search.toLowerCase()))
  );
</script>

<input bind:value={search} placeholder="Search..." />

{#each filtered as post (post.id)}
  <article>
    <h2>{post.title}</h2>
    <p>{post.excerpt}</p>
  </article>
{/each}

パフォーマンス改善

Svelte 5 パフォーマンス比較 (js-framework-benchmark)

項目Svelte 4Svelte 5
DOM操作速度1.0x0.5x (2倍高速)
バンドルサイズ (Hello World)3.2KB2.8KB (-12.5%)
メモリ使用量100%70% (-30%)

まとめ

機能Svelte 4Svelte 5
リアクティブ変数let x = 0let x = $state(0)
派生値$: y = x * 2let y = $derived(x * 2)
副作用$: { ... }$effect(() => { ... })
プロパティexport let proplet { prop } = $props()
スロット<slot />{@render children()}
イベントon:clickonclick

参考リンク

← 一覧に戻る