svelte5 について
svelte5は、Svelte 5のコンポーネントを開発・レビューするためのスキルです。状態の所有者、明示的なデータフロー、セマンティックなマークアップを重視し、旧構文やアンチパターンの発見を支援します。
主な機能
- 01Svelte 5のリアクティビティ原則
- 02コンポーネントの状態とプロパティ設計
- 03APIとHTMLセマンティクスのレビュー
- 04コードの問題点と修正案の提示
- 05Svelte 4とSvelte 5の判別
活用シーン
- 01Svelte 5コンポーネントのデータフローレビュー
- 02エフェクトを派生状態やイベント処理に置き換え
- 03アクセシビリティとSSR状態のリスク確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ joshuadavidthomas/ agent-skills --skill svelte5インストール後、Claude Code で/svelte5を入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdreferences/actions-vs-components.mdactions.mdattachments.mdbindable-by-default.mdbindings-and-directives.mdclass-state-common-mistakes.mdclass-state-patterns.mdclass-state-ssr-safety.mdcomponent-patterns.mdcontext-identity.mdcontext-vs-scoped-state.mddebugging.mddeep-state-without-immutable-ceremony.mdeffect-driven-state.mdimperative-api.mdprop-mirroring.mdread-tracked-reactivity.mdrunes-common-mistakes.mdrunes-component-api.mdrunes-reactivity-patterns.mdsemantic-html-first.mdshadcn-svelte-forms.mdsnippets-as-render-functions.mdsnippets-vs-slots.mdspecial-elements.mdssr-state-leaks.mdstate-ownership.mdstatic-runes.mdstores.md詳細
Svelte 5 で考える
Svelte の構文はすでにご存じでしょう。このスキルでは、コンポーネントの設計、状態の配置、リアクティビティのモデル化、UI コードのレビューで最初に選ぶ方法、つまりデフォルトの考え方を変えます。
よくある根本的な問題は、コンパイルは通るものの、React、Vue、または Svelte 4 のように考えてしまう Svelte コードです。派生値やイベントの代わりにエフェクトを使う、props を状態にコピーする、反射的にグローバルストアを使う、双方向バインディングをデフォルトにする、クリック可能な div を使う、新しいコードで Svelte 4 のコンポーネント API を使う、といったものです。
コンポーネントは、依存関係が見える小さなリアクティブプログラムです。データフローを直接的にし、状態の所有者を明確にし、セマンティックなマークアップを使いましょう。処理はコンパイラーと DOM に任せてください。
このスキルは、Svelte コンポーネントのレビューに使う汎用的な入口です。SvelteKit レベルの内容については、相互参照を参照し、sveltekit も使用してください。
これらは厳格な規則ではなく、強く推奨されるデフォルトとして捉えてください。迷ったときは、状態の所有者、依存関係、ユーザーにとっての意味がより明確になる方法を選びましょう。
Svelte の考え方
リアクティビティを見える形にする
1. リアクティビティは読み取りに基づいて追跡されます。 $derived/$effect は、実行中に読み取った値に依存します。予期せず再実行される場合は、依存配列ではなく、読み取り内容を調べてください。references/read-tracked-reactivity.md を参照してください。
2. 派生状態には $effect ではなく $derived を使います。 他の状態から求められる純粋な値には derived を使い、変数を同期させるためではなく、副作用に対してエフェクトを使います。references/effect-driven-state.md を参照してください。
let doubled = $state(0);
$effect(() => { doubled = count * 2; });
let doubled = $derived(count * 2);
3. エフェクトは最後の手段です。 $effect を使う前に、派生値、イベントハンドラー、または bind: のゲッター/セッターで対応できないか確認してください。エフェクトを使うのは、サブスクリプション、タイマー、オブザーバー、命令型 API、ログ記録など、外部のものに作用する場合に限り、クリーンアップを返してください。
4. ルーンは静的解析できます。 ルーンはランタイムフックではなく、コンパイラー構文です。再利用可能な状態にはカスタムフックではなく、.svelte.ts のクラスやファクトリーを使います。references/static-runes.md を参照してください。
5. $state は深いプロキシであり、React の state ではありません。 ローカルの配列やオブジェクトでは、変更された部分を直接ミューテートし、イミュータブルな更新のための余分な手続きを省きましょう。references/deep-state-without-immutable-ceremony.md を参照してください。
状態は所有者が明確な場所に置く
6. 状態には所有者がいます。 ローカルなインタラクション状態はコンポーネントに、再利用可能な振る舞いは .svelte.ts のクラスに、子孫間で共有する状態はコンテキストに置きます。ストアは、変化する値すべてに使うのではなく、ストアの契約が必要な場合にのみ使います。references/state-ownership.md を参照してください。
7. 「下書き」にする意図がない限り、props をコピーしないでください。 props を $state にコピーすると、信頼できる情報源が二つになります。props から派生させるか、リセット/確定ができる名前付きの編集用下書きを作成してください。references/prop-mirroring.md を参照してください。
let { value } = $props();
let local = $state(value); // stale if parent changes
let { value } = $props();
let display = $derived(value.toUpperCase());
8. コンテキストで共有するのは同一性であり、プロバイダーの再レンダリングではありません。 リアクティブなオブジェクトやクラスをコンテキストに入れ、そのプロパティを変更してください。通常の値を置き換えても、React の Provider 更新のようには動作しません。references/context-identity.md を参照してください。
9. SSR アプリでは、モジュールレベルの可変状態に注意が必要です。 SvelteKit では、エクスポートされた可変インスタンスがリクエスト間で共有されます。ファクトリー、コンテキスト、またはリクエストごとのデータを使用してください。references/ssr-state-leaks.md を参照してください。
所有権を軸にコンポーネント API を設計する
10. Props は入力を記述し、コールバックはイベントを記述します。 コンポーネントのイベントはコールバック Props です。古い公開 API を維持する場合を除き、新しいコードでは createEventDispatcher を避けてください。references/component-patterns.md を参照してください。
const dispatch = createEventDispatcher();
function handleClick() { dispatch('select', item); }
let { onSelect } = $props();
function handleClick() { onSelect?.(item); }
11. 双方向バインディングは API 上のコミットメントです。 $bindable は、子が親所有の状態を変更できることを意味します。フォームコントロールや、意図的に制御するコンポーネントには使用しますが、デフォルトでは使用しないでください。references/bindable-by-default.md を参照してください。
12. スニペットはレンダー関数であり、名前を変えただけのスロットではありません。 親が UI を提供する場合に使用し、パラメーターに型を付け、役割に応じた名前を付けてください。references/snippets-as-render-functions.md を参照してください。
13. ラッパーコンポーネントはプラットフォームの機能を維持する必要があります。 button をラップする場合は、ボタンの属性を受け入れ、type、disabled、フォーカス、ARIA をそのまま保ってください。references/wrapper-components-preserve-html.md を参照してください。
HTML とコンパイラーに任せる
14. カスタム動作よりネイティブ要素を優先します。 button はキーボード操作、フォーカス、無効状態、アクセシビリティに標準で対応しています。クリック可能な div では、プラットフォームの機能を不適切に作り直すことになります。references/semantic-html-first.md を参照してください。
15. デザインシステムのフィールドではフォームのセマンティクスを維持します。 shadcn-svelte または bits-ui のフォームでは、ラベル、グループ、説明、エラーに Field.* を使用してください。生の div、個別の Label インポート、クリック可能なオプション行は使用しないでください。references/shadcn-svelte-forms.md を参照してください。
16. マークアップはコンポーネントが担当し、DOM の動作はアクション/アタッチメントが担当します。 UI をレンダリングするもの → コンポーネント。要素に再利用可能な命令型の動作を付与するもの → アクションまたはアタッチメント。references/actions-vs-components.md を参照してください。
17. Svelte 5 の構文は一貫させます。 新しいコードでは $props、onclick 形式の属性、スニペット、コールバック Props を使用します。レガシーコードの保守以外では、古い構文と混在させないでください。references/svelte5-syntax-discipline.md を参照してください。
18. あらゆるものに型を付けるのではなく、境界に型を付けます。 複雑なコンポーネントには Props 型を定義し、スニペットとコールバックに型を付け、ラッパーには svelte/elements を使用し、境界で広範な any を避けてください。references/typescript.md を参照してください。
レビューの実施
- まずバージョンを特定します。
package.jsonでsvelteのメジャーバージョンを確認し、svelte.config.*を確認します。Svelte 5 プロジェクトでは、Svelte 4 のパターン(export let、on:event、<slot>、createEventDispatcher)を指摘します。Svelte 4 プロジェクトでは、タスクが移行でない限り、Svelte 5 専用の構文を推奨しないでください。 - 上記の原則を適用し、以下の問題点一覧を確認します。 書き換えを提案する前に、リンク先のリファレンスを開いてください。
- パフォーマンスの判断は、根拠がある場合や明らかに規模が大きい場合に限ります。 キー付きの
{#each}を識別し、重い処理はマークアップから$derivedに移し、不要な双方向バインディングを避けてください。ほとんどのコードでは手動での最適化は必要ありません。 - 出力を構成します。 影響の大きいもの(正確性、リアクティビティ、アクセシビリティ、SSR のリーク)を最初にし、次に書き換え案(役立つ範囲で最小の変更)、最後にあれば望ましい改善を示します。すべての指摘を、単なるスタイル上の細かな問題ではなく、動作、保守性、またはユーザーへの影響に結び付けてください。
コードスメル一覧
該当するスメルを確認してください。修正方法は上記の原則に従います。
| コードスメル | 参照 |
|---|---|
| 新しいコードで古い Svelte 構文を使用している | svelte5-syntax-discipline |
| エフェクトで派生値を代入している | effect-driven-state |
| コントロールの変更にエフェクトで対応している | effect-driven-state |
| エフェクトでバインドされた値を変換している | bindings-and-directives |
| エフェクトが原因不明で再実行される | read-tracked-reactivity |
| ヘルパーやフックの内部でルーンを呼び出している | static-runes |
| ローカル状態の更新に不変性のための儀式的なコードが必要 | deep-state-without-immutable-ceremony |
| プロパティをローカル状態にコピーしている | prop-mirroring |
| デフォルトでグローバルストアを使用している/所有者が不明確 | state-ownership |
| コンテキスト値を変更せずに置き換えている | context-identity |
| SvelteKit で変更可能なシングルトンをエクスポートしている | ssr-state-leaks |
イベントの発行に createEventDispatcher を使用している | component-patterns |
習慣的に $bindable を使用している | bindable-by-default |
スロット形式の API(export let、<slot>) | snippets-as-render-functions |
クリック可能な div/span | semantic-html-first |
| shadcn-svelte フォームを生のラッパーで再構築している | shadcn-svelte-forms |
| ネイティブの動作を隠すラッパー | wrapper-components-preserve-html |
| マークアップ/状態を所有するアクション | actions-vs-components |
| 動的リストにキーを指定していない | bindings-and-directives |
コンポーネント境界で広範な any を使用している | typescript |
ユーザーコンテンツに {@html} を使用している | template-tags |
| コンポーネントの動作をテストしていない | testing |
相互参照
- sveltekit — ルート、レイアウト、
load、フォームアクション、リモート関数、Cookie、認証、エンドポイント、リダイレクト、サーバーエラー、アプリケーションレベルの SSR/データフロー