メインコンテンツへスキップ

Svelte 5 移行ガイド

バージョン5は、刷新された構文とリアクティブシステムを備えています。最初は異なって見えるかもしれませんが、すぐに多くの類似点に気付くでしょう。このガイドでは、変更点を詳細に説明し、アップグレード方法を示します。それに加えて、これらの変更を行った理由についても説明します。

新しい構文にすぐに移行する必要はありません。Svelte 5は古いSvelte 4の構文も引き続きサポートしており、新しい構文を使用するコンポーネントと古い構文を使用するコンポーネントを混在させることができます。多くの人が、最初は数行のコード変更だけでアップグレードできると予想しています。また、これらの多くの手順を自動的に支援する移行スクリプトも提供しています。

リアクティブ構文の変更

Svelte 5の中核は、新しいルーンAPIです。ルーンは基本的に、リアクティビティについてSvelteに情報を伝えるコンパイラの命令です。構文上、ルーンはドル記号で始まる関数です。

let -> $state

Svelte 4では、コンポーネントの最上位レベルにあるlet宣言は暗黙的にリアクティブでした。Svelte 5では、より明示的になります。変数は、$stateルーンを使用して作成された場合にリアクティブになります。カウンターを$stateでラップして、カウンターをルーンモードに移行しましょう。

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

他に変更はありません。countは依然として数値そのものであり、.valuegetCount()のようなラッパーなしで直接読み書きできます。

その理由

最上位レベルでletが暗黙的にリアクティブであることはうまく機能しましたが、リアクティビティが制約されることを意味していました。つまり、他の場所でlet宣言はリアクティブではありませんでした。そのため、コードをコンポーネントの最上位レベルから再利用のためにリファクタリングする際には、ストアを使用せざるを得ませんでした。これは、まったく別のリアクティビティモデルを学ぶ必要があり、結果として作業しにくいことがよくありました。Svelte 5ではリアクティビティがより明示的であるため、コンポーネントの最上位レベル以外でも同じAPIを使い続けることができます。チュートリアルで詳細を学ぶことができます。

$: -> $derived/$effect

Svelte 4では、コンポーネントの最上位レベルにある$:ステートメントを使用して、導出、つまり他の状態の計算によって完全に定義される状態を宣言できました。Svelte 5では、これは$derivedルーンを使用して実現されます。

<script>
	let count = $state(0);
	$: const double = $derived(count * 2);
</script>

$stateと同様に、他に変更はありません。doubleは依然として数値そのものであり、.valuegetDouble()のようなラッパーなしで直接読み取ることができます。

$:ステートメントは、副作用を作成するためにも使用できます。Svelte 5では、これは$effectルーンを使用して実現されます。

<script>
	let count = $state(0);
	$:$effect(() => {
		if (count > 5) {
			alert('Count is too high!');
		}
	});
</script>
その理由

$:は優れたショートハンドであり、使い始めるのが簡単でした。ほとんどのコードの前に$:を付ければ、何となく動作しました。この直感性はその欠点でもありました。コードが複雑になるほど、理由付けが難しくなりました。コードの意図は導出を作成することですか、それとも副作用を作成することですか?$derived$effectを使用すると、事前に少し多くの意思決定を行う必要があります(ネタバレ注意:90%の時間は$derivedを使用します)が、将来の自分やチームの他の開発者はより簡単に理解できます。

見つけるのが難しい落とし穴もありました。

  • $:はレンダリングの直前にのみ更新されたため、再レンダリングの間は古い値を読み取ることができました。
  • $:はティックごとに1回しか実行されなかったため、ステートメントが想定よりも少ない頻度で実行される可能性がありました。
  • $:の依存関係は、依存関係の静的分析によって決定されました。これはほとんどの場合うまく機能しましたが、依存関係が関数に移動され、その結果見えなくなるリファクタリング中に微妙な方法で破損する可能性がありました。
  • $:ステートメントは、依存関係の静的分析を使用して順序付けられました。場合によっては、同順位があり、その結果順序が間違っている可能性があり、手動による介入が必要になります。順序付けは、コードのリファクタリング中に破損し、その結果一部の依存関係が見えなくなる可能性もあります。

最後に、TypeScriptに非対応でした(エディターツールはそれをTypeScriptで有効にするためにいくつかの困難を乗り越える必要がありました)。これは、Svelteのリアクティビティモデルを真に普遍的なものにするための障害でした。

$derived$effectは、以下の点を改善します。

  • 常に最新の値を返す
  • 安定するために必要な回数だけ実行する
  • ランタイムで依存関係を決定するため、リファクタリングの影響を受けない
  • 必要に応じて依存関係を実行するため、順序付けの問題の影響を受けない
  • TypeScriptに対応

export let -> $props

Svelte 4では、コンポーネントのプロパティはexport letを使用して宣言されました。各プロパティは1つの宣言でした。Svelte 5では、すべてプロパティは$propsルーンを通じて、デストラクチャリングによって宣言されます。

<script>
	export let optional = 'unset';
	export let required;
	let { optional = 'unset', required } = $props();
</script>

プロパティの宣言が、いくつかのexport let宣言を持つよりも単純でないケースがいくつかあります。

  • プロパティの名前を変更したい場合(たとえば、名前が予約済みの識別子であるため(例:class))
  • 事前にどのプロパティを期待するか分からない場合
  • すべてプロパティを別のコンポーネントに転送したい場合

これらのケースではすべて、Svelte 4で特別な構文が必要です。

  • 名前変更:export { klass as class}
  • その他プロパティ:$$restProps
  • すべてプロパティ:$$props

Svelte 5では、$propsルーンにより、追加のSvelte固有の構文なしでこれが簡単にできます。

  • 名前変更:プロパティの名前変更を使用するlet { class: klass } = $props();
  • その他プロパティ:スプレッドを使用するlet { foo, bar, ...rest } = $props();
  • すべてプロパティ:デストラクチャリングしないlet props = $props();
<script>
	let klass = '';
	export { klass as class};
	let { class: klass, ...rest } = $props();
</script>
<button class={klass} {...$$restPropsrest}>click me</button>
その理由

export letは、より物議を醸すAPIの決定の1つであり、プロパティをexportするのかimportするのかを考えるべきかどうかについて多くの議論がありました。$propsにはこの特徴がありません。また、他のルーンとも一致しており、一般的な考え方は「Svelteにおけるリアクティビティに関する特別なものはすべてルーンである」ということに集約されます。

export letには多くの制限もあり、上記のように追加のAPIが必要でした。$propsはこれを1つの構文的概念に統合し、通常のJavaScriptのデストラクチャリング構文に大きく依存しています。

イベントの変更

Svelte 5では、イベントハンドラが改良されました。Svelte 4ではon:ディレクティブを使用してイベントリスナーを要素にアタッチしましたが、Svelte 5では他のプロパティと同じようにプロパティになります(つまり、コロンを削除します)。

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

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

プロパティであるため、通常のショートハンド構文を使用できます…

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

	function onclick() {
		count++;
	}
</script>

<button {onclick}>
	clicks: {count}
</button>

…ただし、名前付きイベントハンドラ関数を使用する場合は、より説明的な名前を使用する方が通常は優れています。

コンポーネントイベント

Svelte 4では、createEventDispatcherを使用してディスパッチャを作成することで、コンポーネントはイベントを送信できました。

この関数はSvelte 5で非推奨になりました。代わりに、コンポーネントはコールバックプロップを受け入れる必要があります。つまり、これらのコンポーネントにプロパティとして関数を渡します。

アプリ
<script>
	import Pump from './Pump.svelte';

	let size = $state(15);
	let burst = $state(false);

	function reset() {
		size = 15;
		burst = false;
	}
</script>

<Pump
	on:inflate={(power) => {
		size += power.detail;
		if (size > 75) burst = true;
	}}
	on:deflate={(power) => {
		if (size > 0) size -= power.detail;
	}}
/>

{#if burst}
	<button onclick={reset}>new balloon</button>
	<span class="boom">💥</span>
{:else}
	<span class="balloon" style="scale: {0.01 * size}">
		🎈
	</span>
{/if}
ポンプ
<script>
	import { createEventDispatcher } from 'svelte';
	const dispatch = createEventDispatcher();
	
	let { inflate, deflate } = $props();
	let power = $state(5);
</script>

<button onclick={() => dispatch('inflate', power)inflate(power)}>
	inflate
</button>
<button onclick={() => dispatch('deflate', power)deflate(power)}>
	deflate
</button>
<button onclick={() => power--}>-</button>
Pump power: {power}
<button onclick={() => power++}>+</button>

バブリングイベント

イベントを要素からコンポーネントに「転送」するために<button on:click>を行う代わりに、コンポーネントはonclickコールバックプロップを受け入れる必要があります。

<script>
	let { onclick } = $props();
</script>

<button on:click {onclick}>
	click me
</button>

これは、他のプロップと共にイベントハンドラを要素に「スプレッド」できることも意味します。個々のイベントを手作業で転送する必要はありません。

<script>
	let props = $props();
</script>

<button {...$$props} on:click on:keydown on:all_the_other_stuff {...props}>
	click me
</button>

イベント修飾子

Svelte 4では、ハンドラにイベント修飾子を追加できます。

<button on:click|once|preventDefault={handler}>...</button>

修飾子はon:に固有であり、そのため最新のイベントハンドラでは機能しません。ハンドラ自体にevent.preventDefault()などのものを追加する方が好ましいです。すべてのロジックが1か所に存在するからです。

イベントハンドラは関数であるため、必要に応じて独自のラッパーを作成できます。

<script>
	function once(fn) {
		return function (event) {
			if (fn) fn.call(this, event);
			fn = null;
		};
	}

	function preventDefault(fn) {
		return function (event) {
			event.preventDefault();
			fn.call(this, event);
		};
	}
</script>

<button onclick={once(preventDefault(handler))}>...</button>

capturepassivenonpassiveの3つの修飾子は、ラッパー関数として表現できません。イベントハンドラが実行されるときに適用するのではなく、バインドされるときに適用する必要があるためです。

captureの場合、イベント名に修飾子を追加します。

<button onclickcapture={...}>...</button>

一方、イベントハンドラのpassiveオプションの変更は、軽々しく行うべきではありません。使用例がある場合(おそらくないでしょう!)は、アクションを使用してイベントハンドラを自分で適用する必要があります。

複数のイベントハンドラ

Svelte 4では、これは可能です。

<button on:click={one} on:click={two}>...</button>

要素(現在はイベントハンドラを含む)の重複属性/プロパティは許可されていません。代わりに、これを行います。

<button
	onclick={(e) => {
		one(e);
		two(e);
	}}
>
	...
</button>

プロップをスプレッドする場合は、ローカルイベントハンドラをスプレッドのに配置する必要があります。そうしないと、上書きされる可能性があります。

<button
	{...props}
	onclick={(e) => {
		doStuff(e);
		props.onclick?.(e);
	}}
>
	...
</button>
その理由

createEventDispatcherは常に少し冗長でした。

  • 関数をインポートする
  • ディスパッチ関数を得るために関数を呼び出す
  • 文字列とペイロードを使用して、そのディスパッチ関数を呼び出す
  • イベント自体は常に `CustomEvent` であったため、反対側では ` .detail` プロパティを介して上記のペイロードを取得します。

コンポーネントのコールバックプロップを使用することは常に可能でしたが、`on:` を使用してDOMイベントをリスンする必要があったため、構文の一貫性のためにコンポーネントイベントに `createEventDispatcher` を使用することが理にかなっていました。イベント属性(`onclick`)が導入されたことで、状況は逆転しました。コールバックプロップがより適切な方法となりました。

イベント修飾子の削除は、イベント修飾子の簡潔な構文を好んでいた人にとって後退に見える変更の一つと言えるでしょう。それらが頻繁に使用されるわけではないことを考慮すると、より小さな表面積と引き換えにより明示的な記述を選択しました。また、修飾子は一貫性がなく、ほとんどがDOM要素でのみ使用可能でした。

同じイベントに対する複数のリスナーも不可能になりましたが、これは可読性を妨げるアンチパターンでした。属性が多くなると、2つのハンドラーが互いに隣接していない限り、それらを見つけるのが難しくなります。また、2つのハンドラーが独立していることを意味しますが、実際には `one` 内の `event.stopImmediatePropagation()` のようなものは、`two` の呼び出しを防ぎます。

コールバックプロップと通常の要素プロパティを優先して `createEventDispatcher` と `on:` ディレクティブを非推奨にすることで、

  • Svelteの学習曲線を削減します。
  • 特に `createEventDispatcher` を使ったボイラープレートコードを削減します。
  • リスナーがない可能性のあるイベントに対して `CustomEvent` オブジェクトを作成するオーバーヘッドを削減します。
  • イベントハンドラーの展開機能を追加します。
  • コンポーネントに提供されたイベントハンドラーを特定できる機能を追加します。
  • 特定のイベントハンドラーが必須かオプションかを指定できる機能を追加します。
  • 型安全性を向上させます(以前は、Svelteがコンポーネントが特定のイベントを発行しないことを保証することは事実上不可能でした)。

スロットの代わりにスニペット

Svelte 4では、スロットを使用してコンテンツをコンポーネントに渡すことができました。Svelte 5では、より強力で柔軟なスニペットに置き換えられたため、スロットはSvelte 5で非推奨となりました。

ただし、引き続き動作し、コンポーネントでスニペットとスロットを混在させることができます。

カスタム要素を使用する場合は、以前と同様に `` を使用してください。将来のバージョンでは、Svelteが内部のスロットバージョンを削除すると、それらのスロットはそのまま残されます。つまり、変換する代わりに通常のDOMタグが出力されます。

デフォルトコンテンツ

Svelte 4では、UIの一部を子コンポーネントに渡す最も簡単な方法は `` を使用することでした。Svelte 5では、代わりに `children` プロップを使用し、`{@render children()}` で表示します。

<script>
	let { children } = $props();
</script>

<slot />
{@render children?.()}

複数のコンテンツプレースホルダー

複数のUIプレースホルダーが必要な場合は、名前付きスロットを使用する必要がありました。Svelte 5では、代わりにプロップを使用し、任意の名前を付けて `{@render ...}` でレンダリングします。

<script>
	let { header, main, footer } = $props();
</script>

<header>
	<slot name="header" />
	{@render header()}
</header>

<main>
	<slot name="main" />
	{@render main()}
</main>

<footer>
	<slot name="footer" />
	{@render footer()}
</footer>

データの上位への受け渡し

Svelte 4では、`` にデータを渡し、親コンポーネントで `let:` を使用して取得していました。Svelte 5では、スニペットがこの役割を引き継ぎます。

アプリ
<script>
	import List from './List.svelte';
</script>

<List items={['one', 'two', 'three']} let:item>
	{#snippet item(text)}
		<span>{text}</span>
	{/snippet}
	<span slot="empty">No items yet</span>
	{#snippet empty()}
		<span>No items yet</span>
	{/snippet}
</List>
リスト
<script>
	let { items, item, empty } = $props();
</script>

{#if items.length}
	<ul>
		{#each items as entry}
			<li>
				<slot item={entry} />
				{@render item(entry)}
			</li>
		{/each}
	</ul>
{:else}
	<slot name="empty" />
	{@render empty?.()}
{/if}
その理由

スロットは使い始めるのは簡単でしたが、ユースケースが高度になるにつれて、構文は複雑で分かりにくくなりました。

  • `let:` 構文は、他のすべての `:` ディレクティブが変数を「受信」するのに対し、変数を「作成」するため、多くの人にとって分かりにくいものでした。
  • `let:` で宣言された変数のスコープは明確ではありませんでした。上記の例では、`empty` スロットで `item` スロットプロップを使用できるように見えますが、実際はそうではありません。
  • 名前付きスロットは、`slot` 属性を使用して要素に適用する必要がありました。要素を作成したくない場合もあったため、`<svelte:fragment>` APIを追加する必要がありました。
  • 名前付きスロットはコンポーネントにも適用でき、`let:` ディレクティブが使用できる場所のセマンティクスが変わりました(現在でも、メンテナンス担当者でさえ、どちらの方法で機能するのか分からないことがよくあります)。

スニペットは、より可読性が高く、明確であることで、これらの問題をすべて解決します。同時に、プロップとしてコンポーネントに渡すだけでなく、どこでもレンダリングできるUIセクションを定義できるため、より強力です。

移行スクリプト

ここまでで、以前と後で何がどのように変化したか、古い構文と新しい構文がどのように関連しているかをかなり理解しているはずです。これらの移行の多くがかなり技術的で反復的であり、手動で行いたくないものだということも明らかになったでしょう。

私たちも同じ考えでした。そのため、移行の大部分を自動的に行う移行スクリプトを提供しています。`npx sv migrate svelte-5` を使用してプロジェクトをアップグレードできます。これにより、次のことが行われます。

  • `package.json` のコア依存関係を更新します。
  • runeへの移行(`let` -> `$state` など)
  • DOM要素のイベント属性への移行(`on:click` -> `onclick`)
  • スロットの作成をレンダリングタグへの移行(`` -> `{@render children()}`)
  • スロットの使用をスニペットへの移行(`
    ...
    ` -> `{#snippet x()}
    ...
    {/snippet}`)
  • 明らかなコンポーネント作成の移行(`new Component(...)` -> `mount(Component, ...)`)

VS Codeでは「Migrate Component to Svelte 5 Syntax」コマンドを使用して、Playgroundでは「Migrate」ボタンを使用して、単一のコンポーネントを移行することもできます。

すべてを自動的に移行できるわけではなく、一部の移行は後で手動でクリーンアップする必要があります。次のセクションでは、これについて詳しく説明します。

run

移行スクリプトが一部の `$:` ステートメントを `svelte/legacy` からインポートされた `run` 関数に変換していることに気付くかもしれません。これは、移行スクリプトがステートメントを `$derived` に確実に移行できず、それが副作用であると結論付けた場合に発生します。場合によっては間違っている可能性があり、代わりに `$derived` を使用することをお勧めします。他の場合では正しい可能性がありますが、`$:` ステートメントはサーバーでも実行されるのに対し `$effect` は実行されないため、それを変換するのは安全ではありません。代わりに、`run` が暫定的な解決策として使用されます。`run` は、サーバーで一度実行され、クライアントで `$effect.pre` として実行されるという点で、`$:` のほとんどの特徴を模倣します(`$effect.pre` はDOMへの変更が適用される前に実行されます。ほとんどの場合、代わりに `$effect` を使用することをお勧めします)。

<script>
	import { run } from 'svelte/legacy';
	run(() => {
	$effect(() => {
		// some side effect code
	})
</script>

イベント修飾子

イベント修飾子はイベント属性には適用できません(例:`onclick|preventDefault={...}` はできません)。したがって、イベントディレクティブをイベント属性に移行する際には、これらの修飾子の関数置換が必要です。これらは `svelte/legacy` からインポートされ、たとえば `event.preventDefault()` を使用するなどして、移行する必要があります。

<script>
	import { preventDefault } from 'svelte/legacy';
</script>

<button
	onclick={preventDefault((event) => {
		event.preventDefault();
		// ...
	})}
>
	click me
</button>

自動移行されないもの

移行スクリプトは `createEventDispatcher` を変換しません。コンポーネントのユーザーにとって問題を引き起こす可能性があり、移行スクリプトでは検出できないため、手動で調整する必要があります。

移行スクリプトは `beforeUpdate/afterUpdate` を変換しません。コードの実際の意図を判断できないためです。経験則として、多くの場合、`$effect.pre`(`beforeUpdate` と同時に実行される)と `tick`(`svelte` からインポートされ、DOMへの変更が適用されるまで待機してから作業を実行できます)の組み合わせを使用できます。

コンポーネントはクラスではなくなった

Svelte 3および4では、コンポーネントはクラスです。Svelte 5では関数であり、異なる方法でインスタンス化されます。コンポーネントを手動でインスタンス化する必要がある場合は、`svelte` からインポートされた `mount` または `hydrate` を使用してください。SvelteKitを使用していてこのエラーが発生する場合は、まず最新のSvelteKitバージョンに更新してください。SvelteKitをサポートしています。SvelteKitを使用せずにSvelteを使用している場合、おそらく調整する必要がある `main.js` ファイル(または同様のファイル)があります。

import { function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>, options: MountOptions<Props>): Exports

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
} from 'svelte';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte'
const app = new App({ target: document.getElementById("app") }); const
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
=
mount<Record<string, any>, {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<...>>(component: ComponentType<...> | Component<...>, options: MountOptions<...>): {
    ...;
} & Record<...>

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
(const App: LegacyComponentTypeApp, { target: Document | Element | ShadowRoot

Target element where the component will be mounted.

target
: var document: Documentdocument.Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

@paramelementId String that specifies the ID value.
getElementById
("app") });
export default
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
;

`mount` と `hydrate` のAPIはまったく同じです。違いは、`hydrate` がターゲット内のSvelteのサーバーサイドレンダリングされたHTMLを取得してそれをハイドレートすることです。どちらも、コンポーネントのエクスポートと、潜在的なプロパティアクセサー(`accessors: true` でコンパイルした場合)を含むオブジェクトを返します。クラスコンポーネントAPIで知られている `$on`、`$set`、`$destroy` メソッドは含まれません。これらはその代替です。

`$on` の場合、イベントをリスンする代わりに、オプション引数の `events` プロパティを介して渡します。

import { function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>, options: MountOptions<Props>): Exports

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
} from 'svelte';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte'
const app = new App({ target: document.getElementById("app") }); app.$on('event', callback); const
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
=
mount<Record<string, any>, {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<...>>(component: ComponentType<...> | Component<...>, options: MountOptions<...>): {
    ...;
} & Record<...>

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
(const App: LegacyComponentTypeApp, { target: Document | Element | ShadowRoot

Target element where the component will be mounted.

target
: var document: Documentdocument.Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

@paramelementId String that specifies the ID value.
getElementById
("app"), events?: Record<string, (e: any) => any> | undefined

Allows the specification of events.

@deprecatedUse callback props instead.
events
: { event: anyevent: callback } });

`events` の使用は推奨されません。代わりに、コールバックを使用してください

`$set` の場合、代わりに `$state` を使用してリアクティブなプロパティオブジェクトを作成し、操作します。`.js` または `.ts` ファイル内で行っている場合は、` .svelte.js` または ` .svelte.ts` を含めるように拡張子を調整します。

import { function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>, options: MountOptions<Props>): Exports

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
} from 'svelte';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte'
const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } }); app.$set({ foo: 'baz' }); const
const props: {
    foo: string;
}
props
=
function $state<{
    foo: string;
}>(initial: {
    foo: string;
}): {
    foo: string;
} (+1 overload)
namespace $state

Declares reactive state.

Example:

let count = $state(0);

https://svelte.dokyumento.jp/docs/svelte/$state

@paraminitial The initial value
$state
({ foo: stringfoo: 'bar' });
const
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
=
mount<Record<string, any>, {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<...>>(component: ComponentType<...> | Component<...>, options: MountOptions<...>): {
    ...;
} & Record<...>

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
(const App: LegacyComponentTypeApp, { target: Document | Element | ShadowRoot

Target element where the component will be mounted.

target
: var document: Documentdocument.Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

@paramelementId String that specifies the ID value.
getElementById
("app"), props?: Record<string, any> | undefined

Component properties.

props
});
const props: {
    foo: string;
}
props
.foo: stringfoo = 'baz';

`$destroy` の場合、代わりに `unmount` を使用します。

import { function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>, options: MountOptions<Props>): Exports

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
, function unmount(component: Record<string, any>): void

Unmounts a component that was previously mounted using mount or hydrate.

unmount
} from 'svelte';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte'
const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } }); app.$destroy(); const
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
=
mount<Record<string, any>, {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<...>>(component: ComponentType<...> | Component<...>, options: MountOptions<...>): {
    ...;
} & Record<...>

Mounts a component to the given target and returns the exports and potentially the props (if compiled with accessors: true) of the component. Transitions will play during the initial render unless the intro option is set to false.

mount
(const App: LegacyComponentTypeApp, { target: Document | Element | ShadowRoot

Target element where the component will be mounted.

target
: var document: Documentdocument.Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

@paramelementId String that specifies the ID value.
getElementById
("app") });
function unmount(component: Record<string, any>): void

Unmounts a component that was previously mounted using mount or hydrate.

unmount
(
const app: {
    $on?(type: string, callback: (e: any) => void): () => void;
    $set?(props: Partial<Record<string, any>>): void;
} & Record<string, any>
app
);

暫定的な解決策として、インスタンス化した後にSvelte 4で知られているAPIを維持するために、`svelte/legacy` からインポートされた `createClassComponent` または `asClassComponent` を使用することもできます。

import { 
function createClassComponent<Props extends Record<string, any>, Exports extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>>(options: ComponentConstructorOptions<Props> & {
    component: ComponentType<SvelteComponent<Props, Events, Slots>> | Component<Props>;
}): SvelteComponent<Props, Events, Slots> & Exports

Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.

@deprecatedUse this only as a temporary solution to migrate your imperative component code to Svelte 5.
createClassComponent
} from 'svelte/legacy';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte'
const app = new App({ target: document.getElementById("app") }); const const app: SvelteComponent<Record<string, any>, any, any> & Record<string, any>app =
createClassComponent<Record<string, any>, Record<string, any>, any, any>(options: ComponentConstructorOptions<Record<string, any>> & {
    component: Component<...> | ComponentType<...>;
}): SvelteComponent<...> & Record<...>

Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.

@deprecatedUse this only as a temporary solution to migrate your imperative component code to Svelte 5.
createClassComponent
({ component: Component<Record<string, any>, {}, string> | ComponentType<SvelteComponent<Record<string, any>, any, any>>component: const App: LegacyComponentTypeApp, ComponentConstructorOptions<Props extends Record<string, any> = Record<string, any>>.target: Document | Element | ShadowRoottarget: var document: Documentdocument.Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

@paramelementId String that specifies the ID value.
getElementById
("app") });
export default const app: SvelteComponent<Record<string, any>, any, any> & Record<string, any>app;

このコンポーネントを制御できない場合は、自動適用される後方互換性のために `compatibility.componentApi` コンパイラオプションを使用できます。つまり、`new Component(...)` を使用するコードは調整せずに動作し続けます(ただし、各コンポーネントにわずかなオーバーヘッドが追加されます)。これにより、`bind:this` を介して取得するすべてのコンポーネントインスタンスに `$set` と `$on` メソッドも追加されます。

/// svelte.config.js
export default {
	
compilerOptions: {
    compatibility: {
        componentApi: number;
    };
}
compilerOptions
: {
compatibility: {
    componentApi: number;
}
compatibility
: {
componentApi: numbercomponentApi: 4 } } };

`mount` と `hydrate` は同期ではないため、関数が返されるまでに `onMount` は呼び出されず、保留中のプロミスブロックはまだレンダリングされていません(`#await` は、すぐに解決される可能性のあるプロミスを待機するためにマイクロタスクを待機します)。その保証が必要な場合は、`mount/hydrate` を呼び出した後に `svelte` からインポートされた `flushSync` を呼び出します。

サーバーAPIの変更

同様に、サーバーサイドレンダリング用にコンパイルされた場合、コンポーネントには `render` メソッドがなくなります。代わりに、`svelte/server` から `render` 関数を渡します。

import { 
function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
} from 'svelte/server';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte';
const { html, head } = App.render({ props: { message: 'hello' }}); const { const html: stringhtml, const head: string

HTML that goes into the &#x3C;head>

head
} =
render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    ...;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
(const App: LegacyComponentTypeApp, { props?: Omit<Record<string, any>, "$$slots" | "$$events"> | undefinedprops: { message: stringmessage: 'hello' }});

Svelte 4では、コンポーネントを文字列にレンダリングすると、すべてのコンポーネントのCSSも返されました。Svelte 5では、ほとんどの場合、他の方法(SvelteKitなど)で処理するツールチェーンを使用しているため、デフォルトではそうではなくなりました。`render` からCSSを返す必要がある場合は、`css` コンパイラオプションを `'injected'` に設定すると、`