Svelte igration の経験と注意点

Barbara Streisand
リリース: 2024-11-04 10:46:30
オリジナル
836 人が閲覧しました

Experiences and Caveats of Svelte igration

私は最近、かなり複雑な 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 コマンド パレットを使用します。そうすることで、より細かく制御できるようになります。

非推奨の run() サプライズ

このスクリプトでは奇跡を起こすことはできません。通常、リアクティブ変数宣言を $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 を避けてください

ここからは最も重要なポイントに移ります。これは、クライアント側でのみ実行される $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 のストアの使用を思いとどまったときの話と全く同じです。

SvelteKit の $effect と onMount() の比較

Svelte 5 の登場時に提供された例のおかげで、SvelteKit の onMount() を $effect() に置き換えたくなるかもしれません。すでに述べた理由により、当面はこれをお勧めしません。 onMount は依然として Svelte ライフサイクル フックの中核です。

$bindable $props サプライズ

もう 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>
ログイン後にコピー
ログイン後にコピー

:global { } ブロック

移行中に見つけた非常に優れた機能は、ブロックで 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 サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート