Use Cases (Diperbarui: 2/6/2026)

Pengembangan Svelte dan SvelteKit dengan Claude Code

Panduan praktis Claude Code untuk Svelte/SvelteKit: setup, runes, routing, form actions, testing, dan edit yang aman.

Pengembangan Svelte dan SvelteKit dengan Claude Code

Mengapa Claude Code cocok untuk SvelteKit

Svelte adalah framework UI yang mengompilasi komponen deklaratif menjadi JavaScript ringan. SvelteKit menambahkan lapisan aplikasi: routing berbasis file, server rendering, fungsi load, form actions, endpoint, dan adapter deployment. Dalam aplikasi nyata, satu fitur kecil sering menyentuh src/routes, src/lib/components, $lib/server, tipe yang dihasilkan, dan test.

Claude Code adalah alat agentic coding yang dapat membaca repository, mengedit file, dan menjalankan command. Pada proyek SvelteKit, nilainya paling terasa ketika tugasnya dibatasi: minta Claude Code membaca file terkait, menjelaskan data flow, mengusulkan rencana, lalu mengubah scope kecil. Prompt seperti “buatkan SaaS SvelteKit” terlalu lebar karena mencampur UI, database, auth, security, dan deployment.

Untuk pemula, bagian terpenting adalah Svelte 5. Runes adalah cara reaktif saat ini: $props menerima input komponen, $state menyimpan state yang berubah, $derived menghitung nilai dari state, dan $effect dipakai untuk side effect browser. Artikel ini memakai contoh aplikasi task kecil untuk membahas setup, komponen, shared state, routing, form actions, test, prompt yang aman, use case, dan jebakan umum.

flowchart LR
  A["Tulis kebutuhan kecil"] --> B["Claude Code membaca file terkait"]
  B --> C["Edit komponen Svelte"]
  C --> D["Cek load/actions"]
  D --> E["Jalankan check dan test"]
  E --> F["Review git diff manual"]

Setup proyek

Untuk membuat proyek SvelteKit baru, jalur resmi saat ini dimulai dari Svelte CLI: npx sv create my-app. Jika hanya butuh aplikasi Svelte standalone di atas Vite, template svelte-ts dari Vite juga bisa dipakai. Panduan Vite saat ini mensyaratkan Node.js 20.19+ atau 22.12+ untuk Vite, jadi perbarui Node sebelum mengejar error build yang tidak jelas.

npx sv create claude-svelte-demo
cd claude-svelte-demo
npm install
npm run dev

claude

Pada repository baru, mulai dengan plan mode. Mode ini membuat Claude Code membaca file dan menyusun rencana tanpa mengedit source code.

/plan
Saya ingin menambahkan fitur daftar task ke proyek SvelteKit ini.
Pertama baca src/routes dan src/lib, lalu usulkan file yang perlu diubah, alur data, dan rencana test.
Jangan edit file dulu.
claude --permission-mode plan

Aturan proyek sebaiknya ditulis di CLAUDE.md atau .claude/CLAUDE.md: package manager, command validasi, preferensi Svelte 5 runes, konvensi form actions, batasan security, dan “jangan commit kecuali diminta”. Aturan konkret lebih berguna daripada instruksi umum seperti “rapikan kode”.

Komponen kecil dengan Svelte 5

Contoh berikut bisa langsung ditempatkan di src/lib/components/TaskCard.svelte. Komponen ini menerima task dan callback onToggle, menghitung label dengan $derived, dan mempertahankan aria-pressed untuk aksesibilitas.

<!-- src/lib/components/TaskCard.svelte -->
<script lang="ts">
  type Task = {
    id: string;
    title: string;
    done: boolean;
    estimateMinutes: number;
    tags: string[];
  };

  let {
    task,
    onToggle
  }: {
    task: Task;
    onToggle: (id: string) => void;
  } = $props();

  let statusLabel = $derived(task.done ? 'Selesai' : 'Terbuka');
  let estimateLabel = $derived(`${Math.ceil(task.estimateMinutes / 15) * 15} menit`);
</script>

<article class:done={task.done} class="task-card">
  <div>
    <p class="status">{statusLabel}</p>
    <h3>{task.title}</h3>
    <p>{estimateLabel}</p>
  </div>

  <ul aria-label="Tag">
    {#each task.tags as tag}
      <li>{tag}</li>
    {/each}
  </ul>

  <button type="button" aria-pressed={task.done} onclick={() => onToggle(task.id)}>
    {task.done ? 'Buka kembali' : 'Tandai selesai'}
  </button>
</article>

<style>
  .task-card {
    display: grid;
    gap: 0.75rem;
    border: 1px solid #ddd;
    border-radius: 0.5rem;
    padding: 1rem;
  }

  .done {
    background: #f2fff5;
  }

  .status {
    font-size: 0.875rem;
    font-weight: 700;
  }

  ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    list-style: none;
    padding: 0;
  }

  li {
    border-radius: 999px;
    background: #eef2ff;
    padding: 0.2rem 0.6rem;
  }
</style>

Prompt yang aman harus menjaga kontrak publik komponen:

Tingkatkan src/lib/components/TaskCard.svelte tetapi pertahankan sintaks Svelte 5 runes.
Syarat:
- Jangan ubah tipe Task atau signature onToggle.
- Pertahankan onclick dan jangan kembali ke on:click.
- Pertahankan aria-pressed pada tombol.
- Perbaiki hanya layout dan empty state.
- Setelah edit, sarankan satu component test.

Dengan cara ini, Claude Code tidak mengubah API komponen atau menyentuh file lain tanpa alasan. Review diff juga menjadi lebih mudah.

Shared state: runes dulu, stores jika perlu

Svelte 5 mendukung runes di file .svelte.ts. File seperti ini cocok untuk shared reactive state dan logic yang dipakai ulang. svelte/store tetap berguna untuk stream async kompleks, manual subscription, atau integrasi dengan library yang sudah memakai store contract.

// src/lib/state/taskFilters.svelte.ts
export type TaskStatus = 'all' | 'open' | 'done';

export const taskFilters = $state({
  query: '',
  status: 'all' as TaskStatus,
  tag: ''
});

export function resetTaskFilters() {
  taskFilters.query = '';
  taskFilters.status = 'all';
  taskFilters.tag = '';
}
<!-- src/lib/components/TaskFilterPanel.svelte -->
<script lang="ts">
  import { resetTaskFilters, taskFilters } from '$lib/state/taskFilters.svelte';
</script>

<section aria-label="Filter task">
  <label>
    Kata kunci
    <input bind:value={taskFilters.query} placeholder="Invoice, artikel, review..." />
  </label>

  <label>
    Status
    <select bind:value={taskFilters.status}>
      <option value="all">Semua</option>
      <option value="open">Terbuka</option>
      <option value="done">Selesai</option>
    </select>
  </label>

  <button type="button" onclick={resetTaskFilters}>Reset</button>
</section>

Jebakan umum adalah melupakan SSR. window, document, dan localStorage tidak ada di server. Jika perlu menyimpan preferensi di browser, gunakan browser dari $app/environment.

// src/lib/state/theme.svelte.ts
import { browser } from '$app/environment';

export const themeState = $state({
  theme: 'system' as 'system' | 'light' | 'dark'
});

export function loadTheme() {
  if (!browser) return;
  const saved = localStorage.getItem('theme');
  if (saved === 'light' || saved === 'dark' || saved === 'system') {
    themeState.theme = saved;
  }
}

export function saveTheme(nextTheme: typeof themeState.theme) {
  themeState.theme = nextTheme;
  if (browser) localStorage.setItem('theme', nextTheme);
}

Routing, load, dan batas server

SvelteKit memakai routing berbasis file. src/routes/about menjadi /about, dan src/routes/tasks/[slug] menjadi route dinamis dengan parameter slug. Jika halaman perlu data sebelum render, gunakan +page.server.ts. Database, private key, dan API privileged harus tetap di $lib/server.

// src/lib/server/tasks.ts
export type Task = {
  id: string;
  slug: string;
  title: string;
  done: boolean;
  estimateMinutes: number;
  tags: string[];
};

const tasks: Task[] = [
  {
    id: 'task-1',
    slug: 'write-svelte-guide',
    title: 'Membuat draft artikel SvelteKit',
    done: false,
    estimateMinutes: 45,
    tags: ['writing', 'svelte']
  }
];

export async function getTaskBySlug(slug: string) {
  return tasks.find((task) => task.slug === slug) ?? null;
}
// src/routes/tasks/[slug]/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
import { getTaskBySlug } from '$lib/server/tasks';

export const load: PageServerLoad = async ({ params }) => {
  const task = await getTaskBySlug(params.slug);

  if (!task) {
    error(404, 'Task not found');
  }

  return { task };
};
<!-- src/routes/tasks/[slug]/+page.svelte -->
<script lang="ts">
  import type { PageProps } from './$types';

  let { data }: PageProps = $props();
</script>

<svelte:head>
  <title>{data.task.title} | Tasks</title>
</svelte:head>

<article>
  <p>{data.task.done ? 'Selesai' : 'Terbuka'}</p>
  <h1>{data.task.title}</h1>
  <p>Estimasi: {data.task.estimateMinutes} menit</p>
</article>

Prompt untuk routing:

Baca src/routes/tasks/[slug] dan src/lib/server/tasks.ts.
Tambahkan field dueDate ke Task dan tampilkan di halaman detail.
Pertahankan akses data server di $lib/server.
Jangan rename folder route [slug].
Jalankan npm run check di akhir.

Form actions dan progressive enhancement

SvelteKit form actions memungkinkan +page.server.ts mengekspor actions, lalu <form method="POST"> mengirim data ke server. Form tetap berjalan tanpa JavaScript; use:enhance hanya memperbaiki pengalaman saat JavaScript tersedia.

// src/routes/contact/+page.server.ts
import { fail } from '@sveltejs/kit';
import type { Actions } from './$types';

export const actions = {
  default: async ({ request }) => {
    const formData = await request.formData();
    const values = {
      name: String(formData.get('name') ?? '').trim(),
      email: String(formData.get('email') ?? '').trim(),
      message: String(formData.get('message') ?? '').trim()
    };

    const errors: Record<string, string> = {};
    if (values.name.length < 2) errors.name = 'Masukkan minimal 2 karakter.';
    if (!values.email.includes('@')) errors.email = 'Periksa alamat email.';
    if (values.message.length < 10) errors.message = 'Masukkan minimal 10 karakter.';

    if (Object.keys(errors).length > 0) {
      return fail(400, { values, errors });
    }

    console.log('New inquiry', values);
    return { success: true };
  }
} satisfies Actions;
<!-- src/routes/contact/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  import type { PageProps } from './$types';

  let { form }: PageProps = $props();
</script>

{#if form?.success}
  <p role="status">Terkirim. Kami akan membalas dalam 1 sampai 3 hari kerja.</p>
{/if}

<form method="POST" use:enhance>
  <label>
    Nama
    <input name="name" value={form?.values?.name ?? ''} aria-invalid={!!form?.errors?.name} />
  </label>
  {#if form?.errors?.name}<p>{form.errors.name}</p>{/if}

  <label>
    Email
    <input name="email" type="email" value={form?.values?.email ?? ''} aria-invalid={!!form?.errors?.email} />
  </label>
  {#if form?.errors?.email}<p>{form.errors.email}</p>{/if}

  <label>
    Pesan
    <textarea name="message" rows="5" aria-invalid={!!form?.errors?.message}>{form?.values?.message ?? ''}</textarea>
  </label>
  {#if form?.errors?.message}<p>{form.errors.message}</p>{/if}

  <button type="submit">Kirim</button>
</form>

Jangan memakai GET untuk side effect, jangan mengekspos private key ke browser, dan jangan render HTML tidak tepercaya dengan {@html} tanpa sanitasi. Pada prompt, sebutkan “pertahankan validasi server”, “tetap berjalan tanpa JavaScript”, dan “jangan hapus atribut aksesibilitas”.

Testing, use case, dan jebakan

Dokumentasi testing Svelte menyebut Vitest sebagai pilihan yang cocok untuk proyek Vite dan SvelteKit. Testing Library membantu menguji perilaku yang terlihat oleh user; Playwright cocok untuk flow end-to-end.

// src/lib/components/TaskCard.test.ts
import { fireEvent, render, screen } from '@testing-library/svelte';
import { describe, expect, it } from 'vitest';
import TaskCard from './TaskCard.svelte';

describe('TaskCard', () => {
  it('toggles the task when the button is clicked', async () => {
    let toggledId = '';

    render(TaskCard, {
      task: {
        id: 'task-1',
        title: 'Menulis artikel SvelteKit',
        done: false,
        estimateMinutes: 45,
        tags: ['writing']
      },
      onToggle: (id) => {
        toggledId = id;
      }
    });

    await fireEvent.click(screen.getByRole('button', { name: 'Tandai selesai' }));
    expect(toggledId).toBe('task-1');
  });
});
npm run check
npm run test
npm run build
git diff -- src/lib src/routes
Use caseCocok untuk Claude CodeReview manusia
Filter adminPisahkan filter dengan $state dan $derivedQuery URL dan field berdasarkan permission
Blog atau CMSHubungkan [slug], load, SEO, dan 404Sanitasi HTML, draft, preview
Form leadActions, validasi, use:enhance, testPrivasi, spam, target notifikasi
Migrasi Svelte 4 ke 5Ubah komponen tertentu ke runesJangan ubah perilaku secara massal

Kesalahan yang sering terjadi: prompt terlalu besar, sintaks Svelte 4 dan 5 tercampur, komponen mengimpor $lib/server, $effect dipakai untuk kalkulasi biasa, dan test terlalu lemah. Dari sisi monetisasi, SvelteKit mudah menghubungkan artikel teknis ke form konsultasi atau produk. Untuk rollout tim, lihat Claude Code consultation page. Lanjutkan dengan getting started guide, TypeScript tips, dan testing strategies.

Referensi resmi dan hasil uji

Saat perilaku framework penting, gunakan sumber resmi: Svelte docs, SvelteKit docs, SvelteKit form actions, Vite guide, dan Claude Code docs.

Baca struktur SvelteKit saat ini, lalu ubah hanya scope berikut.
File: src/routes/contact/+page.svelte dan src/routes/contact/+page.server.ts
Tujuan: tambahkan field company ke form inquiry.
Syarat:
- Pertahankan Svelte 5 runes.
- Jangan hapus use:enhance.
- Tambahkan validasi server-side.
- Jangan ubah copy CTA atau class layout.
- Jalankan npm run check sebelum selesai.
Akhiri dengan 3 baris: perubahan, risiko, test yang masih kurang.

Masa mencoba workflow ini pada aplikasi task kecil berbasis SvelteKit. Hasil terbaik muncul ketika dimulai dari plan mode. Instruksi “pertahankan runes”, “jalankan npm run check”, dan “jangan commit” membuat diff lebih kecil dan lebih mudah direview oleh pemula Svelte.

#Claude Code #Svelte #SvelteKit #frontend #TypeScript
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.