私は最近、かなり複雑な Web アプリケーションを更新しました。このアプリケーションには、認証、Stripe、i18n、ダーク/ライト モード、PWA などの機能があります。全体として、約 30 ページとコンポーネントがあり、サードパーティの npm パッケージはほとんどありません。
アプリを Svelte 5 に移行するときに非常に難しいと感じた点を指摘したいと思います。
Svelte が提供する自動移行スクリプトは、ターミナルで次の「ワンライナー」コマンド npx sv merge svelte-5 を実行することでジョブを実行できます (必要な更新とインストールをすべて行った後: "@sveltejs/vite" -plugin-svelte": "^4.0.0" および "svelte": "^5")。しかし、私はこの「ハンマー」アプローチはお勧めしません。
Ctrl Shift P (Windows/Linux) / Shift Command P (Mac) を使用してファイルごと、コンポーネントごとに移動し、「コンポーネントを Svelte 5 構文に移行」コマンドを使用します。代わりに VS Code コマンド パレットを使用します。そうすることで、より細かく制御できるようになります。
このスクリプトでは奇跡を起こすことはできません。通常、リアクティブ変数宣言を $state() にアップグレードしても問題ありません。ただし、スクリプトは、$: を $derived()/$derived.by(() => {}) または $effect(() => {}) に変換する必要があるかどうかを検出するのに苦労する可能性があります。
それで、どうでしょうか?自動移行スクリプトを使用すると、大量の run(() => {}) が実行される可能性があります。
たとえば、次のようなものを使用した簡略化された例を想像してください:
<script> ... let notext = false; $: if (data.completeDoc == 'NoLangVersion') { notext = true; } $: if (data.completeDoc !== 'NoLangVersion') { notext = false; } </script> ... {#if notext} {data.userPrefferedLang.noTextWarning} {:else} ... {/if} ...
自動移行スクリプトにより次の結果が得られます:
<script> import { run } from 'svelte/legacy'; ... let notext = $state(false); run(() => { if (data.completeDoc == 'NoLangVersion') { notext = true; } }); run(() => { if (data.completeDoc !== 'NoLangVersion') { notext = false; } }); </script>
run 関数は非推奨であるというちょっとした警告が付いています。
Svelte 5 のより良いコードはこれだと思います:
<script> ... let notext = $derived.by(() => { if (data.completeDoc == 'NoLangVersion') { return true; } if (data.completeDoc !== 'NoLangVersion') { return false; } }); ... </script>
または、コードがそれほど複雑でない場合は、次のようなものでも構いません:
<script> ... let notext = $derived( data.completeDoc == 'NoLangVersion' ? true : false ) ... </script>
その理由は、スクリプトがコードを $derived.by(() => {}) に簡単に変換できないため、$effect() を使用したよりダーティなアプローチを使用したいためです。ただし、$effect() はクライアント側でのみ実行されるため、スクリプトは代わりに非推奨の run 関数を使用します。
ここからは最も重要なポイントに移ります。これは、クライアント側でのみ実行される $effect() です。したがって、ページと SSR を事前レンダリングするための $effect() はサーバー上にありません。
$effect() はサーバー上で実行できません!
これは Svelte 5 ドキュメントで特に強調されるべきです。
この 2 つの例を見てください:
<script> let a = 1 let b = 2 $: c = a + b </script> {c} // server responds with c == 3
<script> let a = $state(1) let b = $state(2) let c = $state(0) $effect(() => { c = a + b }) </script> {c} // server responds with c == 0
それらは同じではありません。これは多くの課題を引き起こします。クライアントは、ページをマウントするときに c 変数を再評価する必要があります。ページは、サーバーから送信されたときと、最終的にクライアントで DOM レンダリングされたときとで異なって見えます (SSR、SEO、ちらつきの問題など)。
したがって、$effect() ではなく、常に $derived または $derived.by(() => {}) を使用するようにしてください。多くの手間を省くことができます。
これは、SvelteKit と SSR のストアの使用を思いとどまったときの話と全く同じです。
Svelte 5 の登場時に提供された例のおかげで、SvelteKit の onMount() を $effect() に置き換えたくなるかもしれません。すでに述べた理由により、当面はこれをお勧めしません。 onMount は依然として Svelte ライフサイクル フックの中核です。
もう 1 つの嬉しい驚きは、Svelte 5 が変数値の一貫性を保つよう配慮していることです。変数をプロップとしてコンポーネントに渡し、後でコンポーネント内でこの変数を変更すると、スクリプトは $bindable $prop を使用してこの不一致を解決しようとします。アプリの状態が一貫しているように、親に通知する必要があります。
この例を見てください:
<script> ... let notext = false; $: if (data.completeDoc == 'NoLangVersion') { notext = true; } $: if (data.completeDoc !== 'NoLangVersion') { notext = false; } </script> ... {#if notext} {data.userPrefferedLang.noTextWarning} {:else} ... {/if} ...
autou-migration スクリプトでは、バインドされた値を持つコンポーネントを使用して、親が更新された値を確実に取得できるようにする必要があります。
<script> import { run } from 'svelte/legacy'; ... let notext = $state(false); run(() => { if (data.completeDoc == 'NoLangVersion') { notext = true; } }); run(() => { if (data.completeDoc !== 'NoLangVersion') { notext = false; } }); </script>
しかし、ご想像のとおり、$derived():
を使用する、より単純な方法も使用できるかもしれません。
<script> ... let notext = $derived.by(() => { if (data.completeDoc == 'NoLangVersion') { return true; } if (data.completeDoc !== 'NoLangVersion') { return false; } }); ... </script>
移行中に見つけた非常に優れた機能は、ブロックで CSS :global を使用できるようになったということです。たとえば、@html で HTML 要素のスタイルを設定したい場合は、:global によるスタイル設定が非常に必要です。
では、代わりに次のようにします。
<script> ... let notext = $derived( data.completeDoc == 'NoLangVersion' ? true : false ) ... </script>
これを使用できます:
<script> let a = 1 let b = 2 $: c = a + b </script> {c} // server responds with c == 3
Svelte 4 では、CSS クラスをプロパティとしてコンポーネントに提供したい場合は、{$$props.class}:
を使用します。
<script> let a = $state(1) let b = $state(2) let c = $state(0) $effect(() => { c = a + b }) </script> {c} // server responds with c == 0
Svelte 5 では、class={className}:
を使用できます。
// parent svelte file <script> import ComponentBinded from './ComponentBinded.svelte'; import ComponentWithDerived from './ComponentWithDerived.svelte'; let name = $state('John Wick'); </script> <p>Name value in parent: {name}</p> <ComponentBinded bind:name={name} /> <ComponentWithDerived {name} />
自動マージ スクリプトを使用したとき、アプリのパフォーマンスが低下したことにショックを受けました。 Svelte 4 ではほぼ 100% でした。手動で移行し、方法 (主に可能であれば $effect() を回避する方法) を慎重に検討した後でのみ、私の Lighthouse スコアは再び緑色に戻りました。
Svelte 5 への移行には予想よりも時間がかかりました。ただし、この新しいバージョンをまだ実稼働環境にプッシュしていません。 Svelte 5 へのアップデートは依然としてかなりの頻度で行われています。
私の経験が他の人にとって役立つことを願っています。
以上がSvelte igration の経験と注意点の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。