sveltekit-advanced について
sveltekit-advancedは、SvelteKitの高度な機能を扱う開発者向けリファレンススキルです。サーバーとクライアントの状態管理、リモート関数、フック、環境変数、エラー処理、ルーティング状態などを解説します。
主な機能
- 01サーバー/クライアント状態の指針
- 02リモート関数APIのリファレンス
- 03環境変数とフックの設定
- 04エラー処理パターン
- 05Service Workerとサーバー専用モジュール
- 06スナップショットと浅いルーティング
活用シーン
- 01アプリケーション状態の配置先を選ぶ
- 02型安全なクライアント/サーバー呼び出しを構築
- 03リクエストフックとエラーレスポンスを設定
- 04ブラウザー側への秘密情報の流出を防ぐ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ full-stack-skills/ svelte-skills --skill sveltekit-advancedインストール後、Claude Code で/sveltekit-advancedを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlexamples/app-modules.mdenv-vars.mderrors.mdhooks.mdlink-options.mdREADME.mdremote-functions.mdservice-worker.mdshallow-snapshots.mdstate-management.mdreferences/app-modules.mdenv-vars.mderrors.mdhooks.mdlink-options.mdREADME.mdremote-functions.mdserver-only.mdservice-worker.mdshallow-snapshots.mdstate-management.md詳細
SvelteKit Advanced
SvelteKit の高度な機能に関するリファレンスです。サーバー/クライアント間の状態管理、リモート関数 API、環境変数(旧式と明示的な方法)、フック(サーバー/共有/ユニバーサル)、エラー処理、リンクオプション、サービスワーカー、サーバー専用モジュール、スナップショット、浅いルーティング、$app/* モジュールを扱います。
出典:SvelteKit の公式 llms.txt ドキュメント。
このスキルを使う場面
次のような場合にこのスキルを使います。
- 状態をどこに置くか(サーバーコンテキスト、URL、スナップショット、ストア)を選ぶ。
query/form/command/prerenderを使って、型安全なクライアント/サーバー RPC を構築する。- 環境変数を安全に読み取る(プライベートとパブリック、静的と動的)。
- フック(
handle、handleFetch、handleError、handleValidationError、reroute、transport、init)を使ってリクエスト処理をカスタマイズする。 - 予期されるエラー/予期しないエラーをスローし、フォールバックのエラーページをカスタマイズし、
App.Errorでエラーの形式を型定義する。 data-sveltekit-*属性を使ってリンクの動作を設定する。- オフライン対応や事前キャッシュのためにサービスワーカーを追加する。
.server.*または$lib/server/を使って、シークレットの漏えいを防ぐ。- スナップショットで一時的な DOM 状態を保持するか、浅いルーティングでルート履歴エントリを保持する。
$app/*モジュール(forms、navigation、state、paths、server、environment、types)を使う。
ルーティング、フォームアクション(旧式)、load、基本的なセットアップ、環境変数以外のアダプター設定、CSS/スタイリングには、このスキルを使わないでください。
重要なセクション
1. 状態管理
- 共有サーバー状態は禁止 — モジュールレベルの変数(
let user;)はリクエスト間で漏えいします。Cookie を使って認証し、DB に保存してください。 - 純粋な
load関数 — 副作用(グローバルストアなど)を含めないでください。代わりにデータを返します。 - リクエストごとの状態にはコンテキストを使用 —
setContext('user', () => data.user)(関数を渡すことで、境界を越えてリアクティビティが維持されます)。SSR 中に子で更新されたコンテキストを読み取っても、親には伝播しません(親はすでにレンダリング済みです)。 - コンポーネントの状態はナビゲーション後も保持される —
dataから導出したconstは一度しか計算されません。データの変更時に再計算する値には$derived(...)を使います。 - URL の状態 — フィルターや並べ替えには検索パラメーターを使います。再読み込み後も保持され、SSR に反映されます。
- スナップショット — 履歴エントリにひも付けられた破棄可能な UI 状態(例:「アコーディオンが開いているか」)。
2. リモート関数(2.27 以降、実験的機能)
svelte.config.js でオプトインします。
kit: { experimental: { remoteFunctions: true } },
compilerOptions: { experimental: { async: true } }
*.remote.js からエクスポートする種類:
| 種類 | 用途 | 主な機能 |
|---|---|---|
query | 動的なサーバーデータを読み取る | 重複排除、refresh()、loading/error/current |
query.batch | 複数のクエリを 1 回の呼び出しにまとめる | (input, idx) => Output を返す |
query.live | リアルタイムの非同期イテラブル | connected、reconnect()。最初の値は SSR 用にシリアライズされます |
form | プログレッシブエンハンスメント対応の <form> | <form {...createPost}>、createPost.fields.x.as('text')、validate()、enhance()、for(id)、preflight(schema) |
command | イベントハンドラーから命令的に変更する | レンダリング中には呼び出せません |
prerender | ビルド時のデータ | inputs、dynamic: true |
- 任意の Standard Schema(Zod/Valibot)で検証します。
- 引数と戻り値は devalue でシリアライズされます。
- リモート関数内では Cookie 用に
getRequestEvent()を使用できます。 redirect(...)はquery/form/prerenderでは使用できますが、commandでは使用できません。- 単一実行のミューテーション:サーバーハンドラーでは
getPosts().refresh()またはgetPost(id).set(...)を使います。クライアントが要求した更新にはrequested(getPosts, 1).refreshAll()を使います(上限は DoS 対策です)。
3. 環境変数
レガシーの $env/*(SvelteKit 2.63 より前のデフォルト):
| モジュール | スコープ | タイミング |
|---|---|---|
$env/dynamic/private | サーバーのみ | 実行時(process.env に類似) |
$env/dynamic/public | パブリック(PUBLIC_*) | 実行時 |
$env/static/private | サーバーのみ | ビルド時(インライン化) |
$env/static/public | パブリック | ビルド時(インライン化) |
明示的な環境変数(オプトイン、v3 でデフォルト):
svelte.config.js で有効にします:kit.experimental.explicitEnvironmentVariables = true。次に src/env.ts を作成します:
import { defineEnvVars } from '@sveltejs/kit/hooks';
import * as v from 'valibot';
import { building } from '$app/env';
export const variables = defineEnvVars({
API_KEY: {}, // private
GOOGLE_ANALYTICS_ID: { public: true }, // public
SHOW_DEBUG_OVERLAY: { public: true, static: true }, // inlined, dead-code-eliminated
SECRET: { schema: building ? v.optional(v.string()) : v.string() },
CACHE_TTL_SECONDS: { description: 'How long...' }
});
$app/env/private または $app/env/public からインポートします。$app/environment は $app/env に名称変更されました。
4. フック
任意のファイルが 3 つあります:src/hooks.server.js、src/hooks.client.js、src/hooks.js。
サーバー(hooks.server.js):
handle({ event, resolve })— すべてのリクエストで実行されます。Response を返すか、resolve(event, opts)を呼び出します。resolveのopts:transformPageChunk、filterSerializedResponseHeaders、preload。複数の場合はsequence(...)を使用します。handleFetch({ request, fetch, event })— クロスオリジンリクエストを内部 API に書き換えます。兄弟サブドメイン間で Cookie を転送します。handleValidationError({ event, issues })— リモート関数の引数が不正な場合の 400 レスポンスをカスタマイズします。
共通(hooks.server.js と hooks.client.js):
handleError({ error, event, status, message })— 予期しないエラーのみを対象とします。{ message, ... }を返すと、page.errorになります。例外をスローしてはいけません。サーバーの型:HandleServerError。クライアントの型:HandleClientError。クライアントのeventはNavigationEventです。init()— 起動時に 1 回実行されます。DB 接続などに便利です。
ユニバーサル(hooks.js):
reroute({ url, fetch })— URL を別のルートに変換します(例:i18n)。純粋で冪等な処理です。2.18 以降は非同期にできます。transport— サーバーとクライアントの境界を越える型(例:Vector)用のカスタムエンコーダー/デコーダーです。
5. エラー
- 予期されるエラー —
@sveltejs/kitのerror(404, 'Not found')(またはerror(404, { message, code }))です。最も近い+error.svelteをレンダリングし、ステータスコードを設定します。page.errorは渡されたオブジェクトです。 - 予期しないエラー — その他すべての例外です。公開されず(一般的な
Internal Error)、handleErrorを経由します。 - レンダリングエラー —
experimental.handleRenderingErrorsでオプトインします。エラーはpage.error経由ではなく、errorprop として直接+error.svelteに渡されます。 - レスポンス —
%sveltekit.status%と%sveltekit.error.message%を含むカスタムのsrc/error.htmlを使用します。ルートの+layout.server.jsで発生したエラーにはフォールバックページが使用されます(ルートに+error.svelteがある場合)。 - 型安全性 —
src/app.d.tsでApp.Errorインターフェースを宣言します:
declare global {
namespace App {
interface Error { message: string; code: string; id: string; }
}
}
6. リンクオプション
<a>(または親要素)に data-sveltekit-* 属性を設定します。<form method="GET"> にも適用されます。
| 属性 | 値 | 効果 |
|---|---|---|
preload-data | hover(デフォルト)、tap | ホバー/タップ時に load データをプリロード |
preload-code | eager、viewport、hover、tap | ルートコードのみをプリロード |
reload | boolean | ページ全体のナビゲーションを強制(rel="external" も同様) |
replacestate | boolean | 履歴エントリーを追加せず置き換え |
keepfocus | boolean | ナビゲーション後も同じ要素にフォーカスを維持 |
noscroll | boolean | ナビゲーション後にページ先頭へスクロールする動作を無効化 |
data-sveltekit-preload-data="false" を使用すると、サブツリー内で無効にできます。navigator.connection.saveData の設定が尊重されます。
7. サービスワーカー
src/service-worker.js(または src/service-worker/index.js)を配置します。バンドルされ、自動登録されます。設定で無効にすると、手動で登録できます。
$service-worker から利用できるもの:base、build、files、prerendered、version。
標準的なパターンは、インストール時に build + files をキャッシュし、フェッチ時にネットワーク優先で、失敗した場合はキャッシュにフォールバックする方法です。Cache-Control: no-store を含むレスポンス(ライブクエリ)はスキップします。開発時、build/prerendered は空の配列です。
8. サーバー専用モジュール
$env/static/privateと$env/dynamic/private— サーバー専用です。$app/server— サーバー専用です。- 独自のモジュール —
.server.jsサフィックスを付けるか、$lib/server/の下に配置します。
ブラウザーコードから不正にインポートすると、ビルド時にエラーになります。型のみの場合は import type を使用します。テストでは検出が無効になります(process.env.TEST === 'true')。
9. スナップショットと浅いルーティング
スナップショット — +page.svelte または +layout.svelte から snapshot = { capture, restore } をエクスポートします。ページ更新前に sessionStorage にキャプチャされ、履歴ナビゲーション時に復元されます。JSON でシリアライズ可能である必要があります。巨大なオブジェクトは返さないでください。
浅いルーティング — pushState(url, state) / replaceState(url, state) は、ナビゲーションせずに履歴エントリーを作成します。page.state から読み取ります。preloadData(href) を使って load データを取得し、その後 pushState(href, { selected: result.data }) を実行すると、モーダル内に別の +page.svelte を表示できます。最初の SSR 時と初回描画時、page.state は常に {} です。
すぐにできる修正
| 症状 | 修正 |
|---|---|
| リクエスト間でユーザーデータが漏れる | モジュールレベルの変数を使わず、Cookie と DB を使用します |
ナビゲーション時に load データが更新されない | data から導出した値には const ではなく $derived(...) を使用します |
Cannot import $lib/server/... | 共有型を import type に移します |
| ライブクエリストリームが停止する | .reconnect() で再接続します。SW で no-store レスポンスをキャッシュしないでください |
error(404, ...) で空白ページが表示される | ルートに最も近い場所に +error.svelte を追加します |
| サーバー専用の環境変数がクライアントに漏れる | $env/static/private または .server 命名を使用します |
| バリデーションの 400 エラーが汎用メッセージになる | handleValidationError を実装します |
| ナビゲーション時にコンポーネントの状態が失われる | {#key page.url.pathname}<X/>{/key} で囲み、強制的に再マウントします |
注意点
loadは純粋である必要があります — グローバルストアへの書き込みは行わず、代わりにデータを返します。- SSR 中のコンテキスト更新は上位に伝播しません — ハイドレーション時のちらつきを避けるため、状態を下位に渡します。
query.batchは個々の入力を出力にマッピングする単一の関数を返します。結果の配列を直接返すわけではありません。- SSR での
query.liveは最初に yield された値のみを返し、その後終了します。 commandはレンダリング中に呼び出せません — イベントハンドラーから呼び出します。requestedにはlimitが必要です — DoS 対策のためです。明示的に安全な場合に限り、Infinityを渡してください。- SvelteKit 2.x では
error()にthrowは不要です。 - SSR と初回描画時、
page.stateは{}です — 重要な描画でこれに依存しないでください。 rerouteは純粋かつ冪等である必要があります — クライアントでは結果が URL ごとにキャッシュされます。- 開発環境では Service Worker の
build/prerenderedは空です — 本番ビルドでテストしてください。 - 兄弟サブドメインへの Cookie 転送には、手動での
handleFetchが必要です — SvelteKit は、どの親ドメインの Cookie がどのサブドメインに属するかを判別できません。 handleErrorは例外をスローしてはいけません — リスクのある処理は try/catch で囲みます。
よくある質問
Q: $app/state と $app/stores の違いは何ですか?
A: $app/state(2.12 以降)はルーンベースで、リアクティブです。$app/stores は従来のストアベースのバージョンです。Svelte 5 では $app/state を使用してください。
Q: query と prerender の違いは何ですか?
A: 動的データには query、ビルド時に固定され、CDN から配信できるデータには prerender を使用します。完全にプリレンダリングされたページでは query を使用できません。
Q: form と command の違いは何ですか?
A: form はプログレッシブエンハンスメントに対応しており、JS なしでも動作し、<form> に展開されます。command は JS 専用で、イベントハンドラーから呼び出します。form を優先してください。
Q: $env/dynamic と $env/static の違いは何ですか?
A: dynamic は実行時に読み取ります(例:process.env)。static はビルド時にインライン化されます(デッドコードの削除が可能になります)。ビルド時に値が判明している場合は static を使用してください。
Q: $env/static/private と $env/dynamic/private の違いは何ですか?
A: アクセス制限は同じで、違いは値を読み取るタイミングです。Static では DCE が可能になり、dynamic では実行時の上書きが可能です(例:MY_FLAG=1 npm run dev)。
Q: +page.svelte から $lib/server モジュールを使用できますか? A: いいえ。サーバー専用モジュールは、間接的な場合も含めてクライアントコードからインポートできません。SvelteKit はビルド時にエラーを出します。
Q: 送信後も検索入力欄にフォーカスを維持するにはどうすればよいですか?
A: <form> に data-sveltekit-keepfocus を追加してください。
Q: load から 404 をスローするにはどうすればよいですか?
A: import { error } from '@sveltejs/kit'; error(404, 'Not found'); を使用してください(SvelteKit 2 では throw を使わないでください)。
Q: Sentry を使用すべきですか?
A: はい。hooks.server.js と hooks.client.js の両方の handleError で初期化してください。サーバーでは HandleServerError、クライアントでは NavigationEvent を含む HandleClientError を使用します。
例
| トピック | ファイル |
|---|---|
| context + URL + derived による状態管理 | examples/state-management.md |
| リモート query/form/command/batch/live | examples/remote-functions.md |
| 環境変数(従来の方法 + 明示的な方法) | examples/env-vars.md |
| サーバー + ユニバーサルフック | examples/hooks.md |
| 想定内/想定外のエラー + App.Error | examples/errors.md |
| data-sveltekit-* リンクオプション | examples/link-options.md |
| サービスワーカーのプリキャッシュ + オフライン | examples/service-worker.md |
| $app/* モジュール(forms、navigation、state、paths、server) | examples/app-modules.md |
| スナップショット + 浅いルーティング | examples/shallow-snapshots.md |
参考資料
| トピック | ファイル |
|---|---|
| 状態管理 | references/state-management.md |
| リモート関数 | references/remote-functions.md |
| 環境変数 | references/env-vars.md |
| フック | references/hooks.md |
| エラー | references/errors.md |
| リンクオプション | references/link-options.md |
| サービスワーカー | references/service-worker.md |
| サーバー専用モジュール | references/server-only.md |
| $app/* モジュール | references/app-modules.md |
| スナップショットと浅いルーティング | references/shallow-snapshots.md |