Skip to main content

Misc

Svelte 4 migration guide

Edit this page on GitHub

この移行ガイドでは、Svelteバージョン3から4に移行する方法の概要を説明します。各変更の詳細については、リンクされたPRを参照してください。 移行スクリプトを使用して、これらの一部を自動的に移行します: npx svelte-migrate@latest svelte-4

あなたがライブラリ作成者の場合は、Svelte4のみをサポートするか、Svelte3もサポートできるかどうかを検討してください。 重大な変更のほとんどは多くの人に影響を与えないので、これは簡単に実現できるかもしれません。また、peerDependenciesのバージョン範囲も忘れずに更新してください。

最低限必要なバージョン

  • Node16以上にアップグレードしてください。それ以下のバージョンはもうサポートされていません。(#8566)
  • SvelteKitを使用している場合、1.20.4以上にアップグレードしてください (sveltejs/kit#10172)
  • SvelteKit を使わずに Vite を使っている場合は、vite-plugin-svelte2.4.1以上にアップグレードしてください (#8516)
  • webpackを使用している場合は、webpack5以上に、svelte-loaderは3.1.8以上にアップグレードしてください。それ以下のバージョンはサポートされなくなりました。(#8515, 198dbcf)
  • Rollupを使用している場合は、rollup-plugin-svelte7.1.5以上にアップグレードしてください (198dbcf)
  • TypeScriptを使用している場合は、TypeScript5以上にアップグレードしてください。それ以下のバージョンでも動作する可能性はありますが、保証はできません。(#8488)

バンドラーのブラウザ条件

ブラウザ用のフロントエンドバンドルをビルドするとき、バンドラーはbrowser条件を指定しなければならなくなりました。SvelteKitとViteは自動的にこれを処理します。他のものを使っている場合は、onMount のようなライフサイクルのコールバックが呼ばれないことがあるので、モジュールの解決設定を更新する必要があります。

  • Rollup の場合は、@rollup/plugin-node-resolveプラグインのオプションでbrowser: trueを設定することでこれを行います。詳しくは rollup-plugin-svelte ドキュメントを参照してください。
  • wepback では、"browser"conditionNames配列に追加します。また、aliasを設定している場合は、それを更新する必要があるかもしれません。詳しくは svelte-loader のドキュメントを参照してください。

(#8516)

Svelteはコンパイラ出力としてCommonJS (CJS)フォーマットをサポートしなくなり、svelte/registerフックとCJSランタイムバージョンも削除されました。CJS出力フォーマットをまだ使用する必要がある場合は、ビルド後のステップでSvelteのESM出力をCJSに変換するバンドラーの使用を検討してください。(#8613)

Svelteの関数のより厳密な型

createEventDispatcherActionActionReturn、およびonMountには、より厳密な型が追加されました。

  • createEventDispatcherはペイロードがオプション、必須、または存在しないことを指定できるようになり、それに応じてコールサイトがチェックされます (#7224)
ts
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
optional: number | null;
required: string;
noArgument: null;
}>();
Expected 2-3 arguments, but got 1.2554Expected 2-3 arguments, but got 1.
Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.2345Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.
// Svelte バージョン 3:
dispatch('optional');
dispatch('required'); // 詳細引数は省略できます
dispatch('noArgument', 'surprise'); // 詳細な引数を追加することもできます
Expected 2-3 arguments, but got 1.2554Expected 2-3 arguments, but got 1.
Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.2345Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.
// TypeScript strict モードを使用した Svelte バージョン 4:
dispatch('optional');
dispatch('required'); // エラー、引数がありません
dispatch('noArgument', 'surprise'); // エラー、引数を渡すことができません
  • ActionActionReturnのデフォルトのパラメータタイプは undefined になりました。つまり、この action がパラメータを受け取るように指定したい場合は、このように generic を型付けする必要があります。移行スクリプトはこれを自動的に移行します (#7442)
const action: Action = (node, params) => { .. } // 何らかの方法でparamsを使用すると、エラーになります
const action: Action<HTMLElement, string> = (node, params) => { .. } // paramsはstring型です
  • onMount に非同期な関数を返した場合、型エラーを表示するようになりました。これはおそらくバグだからです。コンポーネントの破棄時にコールバックが呼び出されることを期待しているのだと思いますが、それは同期的に関数を返した場合にのみ動作します。
// この変更によって実際のバグが明らかになった例
onMount(
 // onMountに渡される関数が非同期であるため、someCleanup()が呼び出されない
 async () => {
   const something = await foo();
 // onMountに渡された関数が同期されているため、someCleanup()が呼び出される。
 () => {
  foo().then(something =>  ..
   // ..
   return () => someCleanup();
}
);

Svelteを使用したカスタム要素

Svelteでのカスタム要素の作成が大幅に改善されました。tagオプションは廃止され、新しいcustomElementオプションが採用されました:

<svelte:options tag="my-component" />
<svelte:options customElement="my-component" />

この変更は、高度なユースケースのためのより詳細な設定を可能にするために行われました。移行スクリプトは、コードを自動的に調整します。プロパティの更新タイミングも若干変更されました。(#8457)

SvelteComponentTypedは非推奨です

SvelteComponentがすべての型付け機能を持つようになったため、SvelteComponentTypedは非推奨です。すべてのSvelteComponentTypedインスタンスをSvelteComponentに置き換えてください。

 import { SvelteComponentTyped } from 'svelte';
 import { SvelteComponent } from 'svelte';

 export class Foo extends SvelteComponentTyped<{ aProp: string }> {}
 export class Foo extends SvelteComponent<{ aProp: string }> {}

以前、コンポーネントのインスタンスタイプとしてSvelteComponentを使用していた場合、やや不透明なタイプエラーが表示されることがありますが、これは: typeof SvelteComponent: typeof SvelteComponent<any>に変更することで解決します。

<script>
  import ComponentA from './ComponentA.svelte';
  import ComponentB from './ComponentB.svelte';
  import { SvelteComponent } from 'svelte';

  let component: typeof SvelteComponent;
  let component: typeof SvelteComponent<any>;

  function choseRandomly() {
	component = Math.random() > 0.5 ? ComponentA : ComponentB;
  }
</script>

<button on:click={choseRandomly}>random</button>
<svelte:element this={component} />

移行スクリプトは両方を自動的に実行します。 (#8512)

トランジションはデフォルトでlocalになりました

ページナビゲーションの混乱を防ぐため、トランジションはデフォルトでlocalになりました。"local"とは、ネストされたコントロールフローブロック(each/if/await/key)内にあり、直接の親ブロックではなく、その上のブロックが生成/破棄された場合にはトランジションが再生されないことを意味します。次の例では、slideのイントロアニメーションは、successfalseからtrueになったときだけ再生されますが、showfalseからtrueになったときは再生されません:

{#if show}
	...
	{#if success}
		<p in:slide>Success</p>
	{/each}
{/if}

トランジションをグローバルにするには、|globalモディファイアを追加してください。そうすると、上記のいずれのコントロールフローブロックが作成/破棄されたときにもトランジションが再生されます。移行スクリプトは自動的にこれを行います。(#6686)

デフォルトのスロットバインディング

デフォルトのスロットバインディングが名前付きスロットに公開されることはなくなりました:

<script>
	import Nested from './Nested.svelte';
</script>

<Nested let:count>
	<p>
		count in default slot - is available: {count}
	</p>
	<p slot="bar">
		count in bar slot - is not available: {count}
	</p>
</Nested>

例えば、デフォルトのスロットがリストにあって、指定されたスロットがそうでない場合、動作は未定義なので、これはスロットバインディングをより一貫性のあるものにします。(#6049)

プリプロセッサ

プリプロセッサの適用順序が変更されました。現在、プリプロセッサはマークアップ、スクリプト、スタイルの順に実行されます。

ts
import { preprocess } from 'svelte/compiler';
const { code } = await preprocess(
source,
[
{
markup: () => {
console.log('markup-1');
},
script: () => {
console.log('script-1');
},
style: () => {
console.log('style-1');
}
},
{
markup: () => {
console.log('markup-2');
},
script: () => {
console.log('script-2');
},
style: () => {
console.log('style-2');
}
}
],
{
filename: 'App.svelte'
}
);
// Svelte 3 logs:
// markup-1
// markup-2
// script-1
// script-2
// style-1
// style-2
// Svelte 4 logs:
// markup-1
// script-1
// style-1
// markup-2
// script-2
// style-2

これは、例えばMDsveXを使用している場合に影響する可能性があります。もし使用している場合は、他のスクリプトやスタイルプリプロセッサよりも前に実行するように変更してください。

preprocess: [
	vitePreprocess(),
	mdsvex(mdsvexConfig)
	mdsvex(mdsvexConfig),
	vitePreprocess()
]

各プリプロセッサにもnameが必要です。(#8618)

新しいeslintパッケージ

eslint-plugin-svelte3は非推奨です。Svelte4ではまだ動くかもしれませんが、保証はしません。新しいパッケージeslint-plugin-svelteに切り替えることをお勧めします。移行方法はこのGithubの投稿を参照してください。あるいは、npm create svelte@latestを使って新しいプロジェクトを作成し、eslint (場合によってはTypeScriptも) オプションを選択して、関連ファイルを既存のプロジェクトにコピーすることもできます。

その他の変更点

  • outroing要素にinert属性が適用されるようになり、支援技術から見えなくなり、インタラクションを防ぐことができるようになりました。(#8628)
  • ランタイムがclassList.toggle(name, boolean)を使うようになりました。これらのブラウザをサポートする必要がある場合は、polyfill を使うことを検討してください。(#8629)
  • ランタイムがCustomEventコンストラクタを使用するようになりました。これらのブラウザをサポートする必要がある場合は、polyfill の使用を検討してください。(#8775)
  • svelte/storeからStartStopNotifierインターフェース(writableなどのcreate関数に渡される)を使ってスクラッチから独自のストアを実装する場合、set関数に加えてupdate関数を渡す必要があります。これはストアを使用している人や、既存のSvelteストアを使用してストアを作成している人には影響しません。(#6750)
  • derivedに渡されるストアの代わりに、不正な値に対してエラーを投げるようになりました。(#7947)
  • svelte/internalの型定義が削除され、パブリックAPIではない内部メソッドの使用を推奨しないようにしました。これらのほとんどはSvelte5で変更されると思われます。
  • DOMノードの削除がバッチ処理されるようになり、順序が若干変更されました。このため、これらの要素でMutationObserverを使用している場合、イベントの発生順序に影響を与える可能性があります。 (#8763)
  • svelte.JSX名前空間を使用してグローバルタイピングを拡張していた場合はsvelteHTML名前空間を使用するように移行する必要があります。同様にsvelte.JSX名前空間から型定義を使用していた場合は、代わりにsvelte/elementsから型定義を使用するように移行する必要があります。何をすべきかについての詳細はこちらを参照してください。