はじめに
Claude CodeにSvelteKitのコンポーネントを書かせると、export letや$:記法が出てくることがある。Svelte 4の記法だ。2024年にSvelte 5がリリースされてrunes($state・$derived・$effect)が導入されたが、学習データの影響で旧パターンが優先されやすい。CLAUDE.mdに明示しなければ、このミスマッチが続く。
Claude CodeがSvelteKit開発でよく間違えるパターン
Svelte 4の旧記法(export let・$:)を生成する
+page.tsと+page.server.tsの混同
DB接続や秘密キーを扱うコードが+page.ts(クライアントでも動く)に入ると、シークレットが漏れる。
// ❌ +page.ts にDB接続(クライアントにも渡る)
import { db } from '$lib/server/db'; // buildエラー
// ✅ +page.server.ts(サーバーのみで実行)
import { db } from '$lib/server/db';
export const load = async () => {
return { users: await db.query.users.findMany() };
};form actionsの型定義省略
form actionsはSvelteKitが型を自動生成するが、Claude Codeがimportを省略することがある。
// ✅ 型安全なform actions(+page.server.ts)
import type { Actions, PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals }) => {
return { user: locals.user };
};
export const actions: Actions = {
create: async ({ request, locals }) => {
const data = await request.formData();
await db.insert(todos).values({ title: data.get('title') as string });
return { success: true };
}
};CLAUDE.mdでSvelte 5 runesを正しく指示する
# SvelteKit プロジェクト
技術スタック
SvelteKit 2 + Svelte 5 + TypeScript strict / Tailwind CSS v4 / Drizzle ORM + PostgreSQL
状態管理(Svelte 5 runes)
$state: リアクティブ変数(export letは使わない)
$derived: 計算値($:記法は使わない)
$effect: 副作用($:ブロックは使わない)
グローバル状態: .svelte.tsファイルで$stateを使う(サーバー側では使用禁止)
ファイルの役割分離
DB・認証・秘密キー → +page.server.tsのみ
外部公開APIのfetch → +page.ts(必要な場合のみ)
型は ./$types から必ずimportする(PageServerLoad・Actions・PageProps)
データ取得・更新
データ取得: load関数(+page.server.ts)
ミューテーション: form actions(JSなしでも動くことを前提に設計)
APIルート(/api/): Webhook・外部連携のみ
Svelte最新仕様参照
コード生成前に https://svelte.dev/docs/svelte/llms.txt を参照すること
SSR注意
モジュールレベルの$stateをサーバー側のグローバル状態に使わない(リクエスト間リーク)
サーバー側のリクエスト固有データはload関数のreturnかcontextAPIで渡す SvelteはLLM向けにllms.txtを公式公開している(svelte.dev/docs/svelte/llms.txt)。CLAUDE.mdにURLを書いておくと、Svelte 5 runesを含む最新仕様を参照した上でコードを生成してくれる。
コミュニティ製のSkillsも公開されている。claude-skills/sveltekit-svelte5-tailwind-skill(SvelteKit 2 + Svelte 5 + Tailwind v4統合)やsplinesreticulating/claude-svelte5-skill(SvelteKit全般)がコミュニティから報告されているが、公式確認は取れていないため導入時はリポジトリの最新状況を確認してほしい。
PostToolUseフック──Svelte・TypeScriptのフォーマット自動化
.svelteファイルへの書き込み時にprettierを自動実行する設定だ。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/svelte_format.sh" }]
}
]
}
}#!/usr/bin/env bash
FILE_PATH=$(python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('tool_input', {}).get('file_path', ''))")
if [[ "$FILE_PATH" == *.svelte ]] || [[ "$FILE_PATH" == *.ts ]]; then
npx prettier --write "$FILE_PATH" 2>/dev/null || true
fi型チェックはStopフックで実行する。
"Stop": [{ "hooks": [{ "type": "command", "command": "npx svelte-check --tsconfig ./tsconfig.json 2>&1 | tail -5" }] }]EM視点──Next.jsとの使い分けとCLAUDE.md標準化
SvelteKitとNext.jsの選び方はシンプルだ。SvelteKitはコンパイル時最適化でランタイム不要、form actionsでProgressive Enhancementもデフォルト対応しており、小〜中規模でシンプルさを優先するプロジェクトとの相性がいい。Reactエコシステムを活かしたいチームや大規模プロジェクトはNext.jsを選ぶことになる。
CLAUDE.mdをリポジトリにコミットすることで、チーム全員が同じルールでClaude Codeを使える。export letと$:を禁止パターンとして明記しておけば、コードレビューで旧記法を指摘する機会が減る。新メンバーが「Svelte 5 runesとは何か」を独自調査する手間も省ける。
まとめ
export letと$:が出てくる根本原因は、Svelte 5 runesのルールをCLAUDE.mdで伝えていないことだ。「$state・$derived・$effectを使う」「export letと$:は使わない」の2行を追記し、svelte.dev/docs/svelte/llms.txtの参照URLも加えてほしい。それだけで次のセッションから変わる。

コメント