bun-sveltekit について
Bun で SvelteKit アプリを実行、デプロイするための開発スキルです。初期設定、Bun API の例、デプロイ方法、依存関係のインストール時のセキュリティ対策を扱います。
主な機能
- 01Bun を使った SvelteKit の設定
- 02Bun アダプターの設定
- 03Bun API の使用例
- 04ビルドと Docker デプロイの指針
- 05依存関係インストールのセキュリティ
活用シーン
- 01Bun での SvelteKit プロジェクト開始
- 02サーバーロード関数での SQLite 利用
- 03Bun によるビルドとデプロイ
- 04依存関係のセキュリティチェック設定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill bun-sveltekitインストール後、Claude Code で/bun-sveltekitを入力して読み込まれたか確認します。
詳細
Bun SvelteKit
Bun を使用して SvelteKit アプリケーションを実行し、開発とビルドを高速化します。
クイックスタート
# Create new SvelteKit project
bunx sv create my-app
cd my-app
# Install dependencies
bun install
# Development
bun run dev
# Build
bun run build
# Preview
bun run preview
安全なインストール
bunx sv create のようなスキャフォールディングツールは、リモートコードをダウンロードして実行します。実行する前に、サプライチェーンセキュリティのベストプラクティスに従ってください。
- インストール後スクリプトをブロックする — Bun はデフォルトでこれらを無効にします。
package.jsonのtrustedDependenciesで特定のパッケージを許可できます - クールダウン期間 —
bunfig.tomlでminimumReleaseAgeを設定し、新しいバージョンを 7 日間待ってから使用します - インストール前に監査する —
socket package score npm <pkg>を実行するか、socket npm install <pkg>を使用してパッケージを確認します
Socket CLI の統合、クールダウンの設定、ロックファイルの検証、CI による適用を含むセキュリティ設定の全容については、dependency-upgrade スキルを読み込んでください。
プロジェクトのセットアップ
package.json
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/kit": "^2.0.0",
"svelte": "^5.0.0",
"vite": "^7.3.0"
}
}
Bun アダプターを使用する
bun add -D svelte-adapter-bun
// svelte.config.js
import adapter from "svelte-adapter-bun";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
export default {
preprocess: vitePreprocess(),
kit: {
adapter: adapter(),
},
};
Bun API の使用
サーバーロード関数
// src/routes/users/+page.server.ts
import { Database } from "bun:sqlite";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async () => {
const db = new Database("data.sqlite");
const users = db.query("SELECT * FROM users").all();
db.close();
return { users };
};
フォームアクション
// src/routes/users/+page.server.ts
import { Database } from "bun:sqlite";
import type { Actions } from "./$types";
import { fail } from "@sveltejs/kit";
export const actions: Actions = {
create: async ({ request }) => {
const data = await request.formData();
const name = data.get("name") as string;
if (!name) {
return fail(400, { error: "Name required" });
}
const db = new Database("data.sqlite");
db.run("INSERT INTO users (name) VALUES (?)", [name]);
db.close();
return { success: true };
},
delete: async ({ request }) => {
const data = await request.formData();
const id = data.get("id") as string;
const db = new Database("data.sqlite");
db.run("DELETE FROM users WHERE id = ?", [id]);
db.close();
return { success: true };
},
};
API ルート
// src/routes/api/users/+server.ts
import { Database } from "bun:sqlite";
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
const db = new Database("data.sqlite");
const users = db.query("SELECT * FROM users").all();
db.close();
return json(users);
};
export const POST: RequestHandler = async ({ request }) => {
const { name } = await request.json();
const db = new Database("data.sqlite");
const result = db.run("INSERT INTO users (name) VALUES (?)", [name]);
db.close();
return json({ id: result.lastInsertRowid });
};
ファイル操作
// src/routes/api/files/[name]/+server.ts
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async ({ params }) => {
const file = Bun.file(`./data/${params.name}`);
if (!(await file.exists())) {
return new Response("Not found", { status: 404 });
}
return new Response(file);
};
export const PUT: RequestHandler = async ({ params, request }) => {
const content = await request.text();
await Bun.write(`./data/${params.name}`, content);
return new Response("Saved");
};
サーバーフック
// src/hooks.server.ts
import type { Handle } from "@sveltejs/kit";
import { Database } from "bun:sqlite";
// Initialize database on startup
const db = new Database("data.sqlite");
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)
`);
export const handle: Handle = async ({ event, resolve }) => {
// Add database to locals
event.locals.db = db;
// Auth check
const session = event.cookies.get("session");
if (session) {
event.locals.user = await getUser(session);
}
return resolve(event);
};
// src/app.d.ts
import type { Database } from "bun:sqlite";
declare global {
namespace App {
interface Locals {
db: Database;
user?: { id: number; name: string };
}
}
}
Svelte 5 コンポーネント
<script lang="ts">
import type { PageData } from "./$types";
let { data }: { data: PageData } = $props();
let { users } = $derived(data);
let name = $state("");
</script>
<h1>Users</h1>
<form method="POST" action="?/create">
<input type="text" name="name" bind:value={name} />
<button type="submit">Add User</button>
</form>
<ul>
{#each users as user}
<li>
{user.name}
<form method="POST" action="?/delete" style="display: inline">
<input type="hidden" name="id" value={user.id} />
<button type="submit">Delete</button>
</form>
</li>
{/each}
</ul>
デプロイ
Bun 用にビルドする
bun run build
bun ./build/index.js
Docker
FROM oven/bun:1 AS builder
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
FROM oven/bun:1
WORKDIR /app
COPY --from=builder /app/build ./build
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["bun", "./build/index.js"]
アダプターのオプション
// svelte.config.js
import adapter from "svelte-adapter-bun";
export default {
kit: {
adapter: adapter({
out: "build",
precompress: true, // Generate .gz and .br files
envPrefix: "", // Environment variable prefix
development: false,
dynamic_origin: true,
xff_depth: 1,
}),
},
};
環境変数
# .env
DATABASE_URL=./data.sqlite
PUBLIC_API_URL=https://api.example.com
// Access in server code
import { DATABASE_URL } from "$env/static/private";
import { PUBLIC_API_URL } from "$env/static/public";
// Or dynamic
import { env } from "$env/dynamic/private";
const dbUrl = env.DATABASE_URL;
よくあるエラー
| エラー | 原因 | 解決方法 |
|---|---|---|
Cannot find bun:sqlite | アダプターが正しくありません | svelte-adapter-bun を使用します |
Vite error | ビルドの問題 | .svelte-kit をクリアします |
Hydration failed | サーバーとクライアントの差異 | ロード関数を確認します |
404 on refresh | SPA フォールバック | アダプターを設定します |
参照資料を読み込むタイミング
次の場合は references/adapter-config.md を読み込みます:
- アダプターの高度なオプション
- 静的プリレンダリング
- エッジデプロイ
次の場合は references/performance.md を読み込みます:
- キャッシュ戦略
- 遅延読み込み
- ストリーミング SSR
コメント
Markdown 対応