跳到正文
cccskills
免费在 GitHub 公开

svelte-sveltekit-expert

Expert guide for Svelte 5 (Runes) and SvelteKit 2+ — fine-grained reactivity, snippets, server-first architecture, form actions, and SSR/SSG / Panduan ahli Svelte 5 (Runes) dan SvelteKit 2+ — reaktivitas fine-grained, snippets, arsitektur server-first, form actions, dan SSR/SSG.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md15.7 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Svelte 5 & SvelteKit 2 Expert (Runes Standard 2026)

English | Bahasa Indonesia


<a name="english"></a>

English

Orchestration & Integration

  • Upstream System Design: brainstorming, zero-to-prod-orchestrator (Phase 3 & Phase 4).
  • Styling & Web Standards: modern-web-guidance, tailwind-expert, modern-css-native-expert, design-system-architect.
  • Quality & Performance: performance-web-vitals, e2e-testing-expert, anti-slop, visual-ui-auditor.
  • Backend & APIs: js-backend-expert, database-orm-expert, typescript-expert.

Description

Production-grade guide for building high-performance web applications using Svelte 5 and SvelteKit 2+. Covers the complete Runes reactivity paradigm ($state, $derived, $derived.by, $effect, $props, $bindable), snippet composition replacing legacy slots, progressive enhancement form actions (use:enhance), streaming server promises in +page.server.ts, and shallow routing (pushState) for modal overlays.

Trigger Conditions

  • Scaffolding new applications with Svelte 5 and SvelteKit 2.
  • Refactoring legacy Svelte 3/4 reactive declarations (let x = 0; $: doubled = x * 2;) to Svelte 5 Runes.
  • Composing modular UI components using Svelte 5 Snippets instead of legacy <slot>.
  • Implementing form submissions with atomic server actions and zero-JS progressive enhancement.
  • Streaming large asynchronous datasets to the client without blocking the initial SSR HTML payload.

Core Architectural Patterns

1. Complete Svelte 5 Runes Reference

RunePurposeSvelte 4 Legacy Syntax
$state(val)Deeply reactive state proxylet val = ...
$state.raw(val)Shallow reactive state (ideal for immutable/large payloads)N/A
$derived(expr)Cached reactive derivation$: val = expr
$derived.by(() => {})Complex multi-line derived computation$: { ... }
$effect(() => {})Post-DOM mount & update side-effect with cleanuponMount, afterUpdate, $: { ... }
$effect.pre(() => {})Pre-DOM update effect (e.g. scroll position capture)beforeUpdate
$props()Type-safe destructured component propsexport let prop
$bindable()Explicit two-way prop binding allowanceDirect two-way binding
$inspect(val)Automatic dev-mode deep state inspectorconsole.log(val) in $:

2. Component Composition with Svelte 5 Snippets (No Slots)

In Svelte 5, <slot> is deprecated. Components accept Snippets as typed functions:

<!-- src/lib/components/DataTable.svelte -->
<script lang="ts" generics="T">
  import type { Snippet } from 'svelte';

  interface Props {
    items: T[];
    header: Snippet;
    row: Snippet<[T]>;
    empty?: Snippet;
  }

  let { items, header, row, empty }: Props = $props();
</script>

<div class="overflow-x-auto rounded-xl border border-border bg-card">
  <table class="w-full text-left text-sm">
    <thead class="border-b border-border bg-muted/50 text-xs uppercase font-semibold text-muted-foreground">
      {@render header()}
    </thead>
    <tbody class="divide-y divide-border">
      {#each items as item}
        <tr class="hover:bg-muted/30 transition-colors">
          {@render row(item)}
        </tr>
      {:else}
        {#if empty}
          <tr>
            <td colspan="100%" class="p-8 text-center text-muted-foreground">
              {@render empty()}
            </td>
          </tr>
        {/if}
      {/each}
    </tbody>
  </table>
</div>
<!-- Usage in consumer page -->
<script lang="ts">
  import DataTable from '$lib/components/DataTable.svelte';

  interface User {
    id: string;
    name: string;
    email: string;
    role: string;
  }

  let users = $state<User[]>([
    { id: '1', name: 'Alice Smith', email: 'alice@example.com', role: 'Admin' },
    { id: '2', name: 'Bob Jones', email: 'bob@example.com', role: 'Developer' },
  ]);
</script>

{#snippet tableHeader()}
  <tr>
    <th class="p-3">Name</th>
    <th class="p-3">Email</th>
    <th class="p-3">Role</th>
  </tr>
{/snippet}

{#snippet tableRow(user: User)}
  <td class="p-3 font-medium">{user.name}</td>
  <td class="p-3 text-muted-foreground font-mono">{user.email}</td>
  <td class="p-3"><span class="px-2 py-0.5 rounded text-xs bg-primary/10 text-primary">{user.role}</span></td>
{/snippet}

<DataTable items={users} header={tableHeader} row={tableRow} />

3. Two-Way Binding with $bindable()

<!-- src/lib/components/SearchInput.svelte -->
<script lang="ts">
  interface Props {
    value: string;
    placeholder?: string;
  }

  let { value = $bindable(''), placeholder = 'Search...' }: Props = $props();
</script>

<input
  type="text"
  bind:value
  {placeholder}
  class="px-3 py-2 border rounded-md bg-background text-sm w-full focus:outline-none focus:ring-1 focus:ring-primary"
/>

4. SvelteKit 2 Server Actions with Progressive Enhancement

Atomic server mutation with optimistic state and zero-JS fallback:

// src/routes/tasks/+page.server.ts
import { fail } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types';
import { db } from '$lib/server/db';

export const load: PageServerLoad = async ({ locals }) => {
  // Non-blocking streaming promise: do not await slow telemetry data
  return {
    tasks: await db.tasks.findMany({ orderBy: { createdAt: 'desc' } }),
    streamedMetrics: fetchLiveMetrics(), // Streamed as Promise without blocking HTML
  };
};

export const actions: Actions = {
  createTask: async ({ request }) => {
    const data = await request.formData();
    const title = data.get('title')?.toString().trim();

    if (!title || title.length < 3) {
      return fail(400, { title, error: 'Title must contain at least 3 characters.' });
    }

    const newTask = await db.tasks.create({ data: { title, completed: false } });
    return { success: true, task: newTask };
  },
};

async function fetchLiveMetrics() {
  await new Promise((r) => setTimeout(r, 400));
  return { activeNodes: 12, uptime: '99.99%' };
}
<!-- src/routes/tasks/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  let { data, form } = $props();

  let isSubmitting = $state(false);
  let optimisticTasks = $state([...data.tasks]);

  $effect(() => {
    optimisticTasks = [...data.tasks];
  });
</script>

<div class="max-w-xl mx-auto py-8 space-y-6">
  <h1 class="text-2xl font-bold">Project Tasks</h1>

  <form
    method="POST"
    action="?/createTask"
    use:enhance={({ formData, cancel }) => {
      const title = formData.get('title')?.toString().trim();
      if (!title) {
        cancel();
        return;
      }

      isSubmitting = true;
      // Optimistic update
      optimisticTasks = [{ id: `temp-${Date.now()}`, title, completed: false }, ...optimisticTasks];

      return async ({ update }) => {
        isSubmitting = false;
        await update();
      };
    }}
    class="flex gap-2"
  >
    <input
      name="title"
      type="text"
      placeholder="What needs to be done?"
      required
      class="flex-1 px-3 py-2 border rounded-md bg-background text-sm"
    />
    <button
      type="submit"
      disabled={isSubmitting}
      class="px-4 py-2 bg-primary text-primary-foreground font-medium rounded-md disabled:opacity-50 text-sm"
    >
      {isSubmitting ? 'Saving...' : 'Add Task'}
    </button>
  </form>

  {#if form?.error}
    <p class="text-sm font-semibold text-destructive">{form.error}</p>
  {/if}

  <ul class="divide-y divide-border border rounded-xl bg-card">
    {#each optimisticTasks as task (task.id)}
      <li class="p-3 text-sm flex items-center justify-between">
        <span>{task.title}</span>
        {#if task.id.startsWith('temp-')}
          <span class="text-xs text-muted-foreground font-mono">Syncing...</span>
        {/if}
      </li>
    {/each}
  </ul>

  <!-- Await streamed non-blocking metrics -->
  {#await data.streamedMetrics}
    <div class="p-4 border rounded-lg bg-muted/40 text-xs animate-pulse text-muted-foreground">
      Loading cluster metrics...
    </div>
  {:then metrics}
    <div class="p-4 border rounded-lg bg-card text-xs flex justify-between font-mono">
      <span>Active Nodes: {metrics.activeNodes}</span>
      <span>Uptime: {metrics.uptime}</span>
    </div>
  {/await}
</div>

<a name="bahasa-indonesia"></a>

Bahasa Indonesia

Integrasi Orkestrasi

  • Ideasi & Desain Sistem: brainstorming, zero-to-prod-orchestrator (Fase 3 & Fase 4).
  • Styling & Standar Web: modern-web-guidance, tailwind-expert, modern-css-native-expert, design-system-architect.
  • Kualitas & Performa: performance-web-vitals, e2e-testing-expert, anti-slop, visual-ui-auditor.
  • Backend & APIs: js-backend-expert, database-orm-expert, typescript-expert.

Deskripsi

Panduan produksi untuk membangun aplikasi web performa tinggi menggunakan Svelte 5 dan SvelteKit 2+. Berfokus pada paradigma reaktivitas Runes secara menyeluruh ($state, $derived, $derived.by, $effect, $props, $bindable), komposisi Snippets pengganti slot lawas, progressive enhancement form actions (use:enhance), streaming promise server pada +page.server.ts, dan routing shallow (pushState) untuk modal URL-preserving.

Kondisi Pemicu

  • Membangun aplikasi baru menggunakan Svelte 5 dan SvelteKit 2.
  • Merefaktor kode lama Svelte 3/4 (let x = 0; $: doubled = x * 2;) ke sistem Runes Svelte 5.
  • Menggubah komponen UI modular menggunakan Snippets Svelte 5 alih-alih <slot> lawas.
  • Mengimplementasikan pengiriman data formulir atomik via Server Actions dengan fallback zero-JS.
  • Mengalirkan (streaming) data asinkron lambat ke klien tanpa memblokir rendering HTML SSR awal.

Implementasi Pola Kunci

1. Referensi Lengkap Runes Svelte 5

RuneFungsi & TujuanSintaks Lama Svelte 4
$state(nilai)State reaktif mendalam (deep reactive proxy)let nilai = ...
$state.raw(nilai)State reaktif dangkal (shallow untuk objek besar/imutable)Tidak tersedia
$derived(ekspresi)Nilai turunan ter-cache otomatis$: nilai = ekspresi
$derived.by(() => {})Kalkulasi turunan kompleks multi-baris$: { ... }
$effect(() => {})Efek samping pasca render DOM dengan siklus cleanuponMount, afterUpdate, $: { ... }
$effect.pre(() => {})Efek samping sebelum DOM di-updatebeforeUpdate
$props()Menerima props komponen secara terstruktur & type-safeexport let prop
$bindable()Memberi izin binding dua arah eksplisitBinding dua arah otomatis
$inspect(nilai)Inspeksi state mendalam saat mode pengembanganconsole.log(nilai) di $:

2. Komposisi Komponen dengan Svelte 5 Snippets (Tanpa Slot)

Pada Svelte 5, <slot> digantikan oleh Snippets bertipe (typed snippets):

<!-- src/lib/components/TabelData.svelte -->
<script lang="ts" generics="T">
  import type { Snippet } from 'svelte';

  interface Props {
    data: T[];
    kepala: Snippet;
    baris: Snippet<[T]>;
    kosong?: Snippet;
  }

  let { data, kepala, baris, kosong }: Props = $props();
</script>

<div class="overflow-x-auto rounded-xl border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900">
  <table class="w-full text-left text-sm">
    <thead class="border-b border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-slate-800/50 text-xs uppercase font-semibold text-slate-500">
      {@render kepala()}
    </thead>
    <tbody class="divide-y divide-slate-100 dark:divide-slate-800">
      {#each data as item}
        <tr class="hover:bg-slate-50 dark:hover:bg-slate-800/30 transition-colors">
          {@render baris(item)}
        </tr>
      {:else}
        {#if kosong}
          <tr>
            <td colspan="100%" class="p-8 text-center text-slate-400">
              {@render kosong()}
            </td>
          </tr>
        {/if}
      {/each}
    </tbody>
  </table>
</div>

3. Form Action SvelteKit 2 dengan Progressive Enhancement & State Optimistik

// src/routes/tugas/+page.server.ts
import { fail } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types';
import { db } from '$lib/server/db';

export const load: PageServerLoad = async () => {
  return {
    daftarTugas: await db.tasks.findMany({ orderBy: { createdAt: 'desc' } }),
    metrikServer: ambilMetrikServer(), // Streamed Promise tanpa menunda payload HTML awal
  };
};

export const actions: Actions = {
  tambahTugas: async ({ request }) => {
    const data = await request.formData();
    const judul = data.get('judul')?.toString().trim();

    if (!judul || judul.length < 3) {
      return fail(400, { judul, error: 'Judul tugas minimal terdiri dari 3 karakter.' });
    }

    const tugasBaru = await db.tasks.create({ data: { title: judul, completed: false } });
    return { success: true, tugas: tugasBaru };
  },
};

async function ambilMetrikServer() {
  await new Promise((r) => setTimeout(r, 400));
  return { nodeAktif: 12, uptime: '99.99%' };
}
<!-- src/routes/tugas/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  let { data, form } = $props();

  let sedangMenyimpan = $state(false);
  let daftarTugasOptimistik = $state([...data.daftarTugas]);

  $effect(() => {
    daftarTugasOptimistik = [...data.daftarTugas];
  });
</script>

<div class="max-w-xl mx-auto py-8 space-y-6">
  <h1 class="text-2xl font-bold">Daftar Tugas Proyek</h1>

  <form
    method="POST"
    action="?/tambahTugas"
    use:enhance={({ formData, cancel }) => {
      const judul = formData.get('judul')?.toString().trim();
      if (!judul) {
        cancel();
        return;
      }

      sedangMenyimpan = true;
      // Pembaruan UI Optimistik instan
      daftarTugasOptimistik = [{ id: `temp-${Date.now()}`, title: judul, completed: false }, ...daftarTugasOptimistik];

      return async ({ update }) => {
        sedangMenyimpan = false;
        await update();
      };
    }}
    class="flex gap-2"
  >
    <input
      name="judul"
      type="text"
      placeholder="Apa yang perlu dikerjakan?"
      required
      class="flex-1 px-3 py-2 border border-slate-300 dark:border-slate-700 rounded-md bg-transparent text-sm"
    />
    <button
      type="submit"
      disabled={sedangMenyimpan}
      class="px-4 py-2 bg-emerald-600 text-white font-medium rounded-md disabled:opacity-50 text-sm hover:bg-emerald-500 transition"
    >
      {sedangMenyimpan ? 'Menyimpan...' : 'Tambah Tugas'}
    </button>
  </form>

  {#if form?.error}
    <p class="text-sm font-semibold text-rose-600">{form.error}</p>
  {/if}

  <ul class="divide-y divide-slate-200 dark:divide-slate-800 border rounded-xl bg-white dark:bg-slate-900">
    {#each daftarTugasOptimistik as tugas (tugas.id)}
      <li class="p-3 text-sm flex items-center justify-between">
        <span>{tugas.title}</span>
        {#if tugas.id.startsWith('temp-')}
          <span class="text-xs text-slate-400 font-mono">Menyinkronkan...</span>
        {/if}
      </li>
    {/each}
  </ul>

  <!-- Menunggu data streaming metrik asinkron -->
  {#await data.metrikServer}
    <div class="p-4 border rounded-lg bg-slate-50 dark:bg-slate-800/40 text-xs animate-pulse text-slate-400">
      Memuat telemetri klaster server...
    </div>
  {:then metrik}
    <div class="p-4 border rounded-lg bg-white dark:bg-slate-900 text-xs flex justify-between font-mono">
      <span>Node Aktif: {metrik.nodeAktif}</span>
      <span>Tingkat Uptime: {metrik.uptime}</span>
    </div>
  {/await}
</div>

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Expert guide for automated and manual Web Accessibility (a11y) testing — axe-core, Pa11y, Playwright a11y, screen reader testing, and WCAG 2.2 Level AA/AAA compliance / Panduan ahli pengujian aksesibilitas web.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

Expert guide for intelligent model cascading and routing — complexity-scored task routing from Fast (Composer 2.5, Grok 4.7/4.6) to Medium (Gemini 4 Argon, GPT-5.6 Sol, Claude Opus 5.5) and High (Claude Sonnet 5.5, Claude Fable 5.1, Muse Wonder) / Panduan ahli untuk kaskade dan routing model cerdas.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

Expert guide for intelligent model cascading and routing — complexity-scored task routing from Flash/Haiku to Sonnet/Opus/Astra, dynamic escalation with quality gates, 40-60% token cost reduction while maintaining output quality / Panduan ahli untuk kaskade dan routing model cerdas — routing tugas berbasis skor kompleksitas dari Flash/Haiku ke Sonnet/Opus/Astra, eskalasi dinamis dengan gerbang kualitas, pengurangan biaya token 40-60% dengan kualitas output terjaga.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

Master guide for Affective Computing, emotional AI, and real-time sentiment analysis through native multimodal tokens (voice intonation and facial micro-expressions) / Panduan utama komputasi afektif, AI emosional, dan analisis sentimen real-time melalui token multimodal native.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

Expert guide for Affective Computing, emotional AI, and real-time sentiment analysis through native multimodal tokens (voice intonation and facial micro-expressions) / Panduan ahli komputasi afektif, AI emosional, dan analisis sentimen real-time melalui token multimodal native.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

Expert guide for AI-assisted coding workflows — agentic code generation, multi-agent code swarms, self-healing CI/CD, automated PR review, spec-to-code pipelines, codebase knowledge graphs, and human-in-the-loop approval gates / Panduan ahli untuk workflow pengkodean berbasis AI — generasi kode agentic, code swarm multi-agen, CI/CD self-healing, review PR otomatis, pipeline spec-to-code, knowledge graph codebase, dan gate persetujuan human-in-the-loop.

中文简介正在准备中。当前显示原文说明。

roedyrustam/vibes-plug1122026年10月22日 更新

查看 roedyrustam 的全部技能

报告此技能的问题