0b76a4b119
- Delete Mode1Test, Mode2Test, Mode3Test, Mode5Test (keep only Mode6Test) - Delete old documentation, Docker files, and k8s configs - Add comprehensive Svelte 5 reference library (svelte-reference/) - Update ModeSwitch orchestrator: - Fix port to 3005 (never use 3000/3001) - Add API endpoints for mode switching - Add bun-types and proper tsconfig - Clean up mode folder mappings
9.0 KiB
9.0 KiB
Svelte 5 Quick Reference Card
Runes Cheat Sheet
<script>
// ═══════════════════════════════════════════════════════════
// $state - Reactive state declaration
// ═══════════════════════════════════════════════════════════
let count = $state(0); // Primitive
let user = $state({ name: '', age: 0 }); // Object (deep reactive)
let items = $state<string[]>([]); // Array (deep reactive)
// Direct mutations work with $state!
items.push('item'); // ✅ Reactive
user.name = 'John'; // ✅ Reactive
count++; // ✅ Reactive
// ═══════════════════════════════════════════════════════════
// $derived - Computed values (auto-tracks dependencies)
// ═══════════════════════════════════════════════════════════
let doubled = $derived(count * 2); // Simple expression
let filtered = $derived.by(() => { // Complex computation
return items.filter(i => i.includes(filter));
});
// ═══════════════════════════════════════════════════════════
// $effect - Side effects (auto-tracks, auto-cleanup)
// ═══════════════════════════════════════════════════════════
$effect(() => {
console.log('Count is:', count); // Runs when count changes
return () => { // Optional cleanup
console.log('Cleaning up');
};
});
$effect.pre(() => {
// Runs BEFORE DOM updates
});
// ═══════════════════════════════════════════════════════════
// $props - Component props
// ═══════════════════════════════════════════════════════════
let {
name, // Required prop
count = 0, // With default
children, // Snippet (replaces default slot)
header, // Named snippet
onclick, // Event callback
...rest // Rest props
} = $props();
// ═══════════════════════════════════════════════════════════
// $bindable - Two-way bindable props
// ═══════════════════════════════════════════════════════════
let { value = $bindable('') } = $props();
// Parent: <Input bind:value />
// ═══════════════════════════════════════════════════════════
// $inspect - Debug reactive values (dev only)
// ═══════════════════════════════════════════════════════════
$inspect(count); // Logs on change
$inspect(count).with(console.trace); // Custom logger
</script>
Template Syntax
<!-- Rendering Snippets (replaces slots) -->
{@render children?.()}
{@render header?.()}
{@render row({ item, index })}
<!-- Conditionals -->
{#if condition}
...
{:else if other}
...
{:else}
...
{/if}
<!-- Loops -->
{#each items as item, index (item.id)}
...
{/each}
<!-- Await -->
{#await promise}
<Loading />
{:then data}
<Result {data} />
{:catch error}
<Error {error} />
{/await}
<!-- Key block (force re-render) -->
{#key value}
<Component />
{/key}
<!-- HTML (dangerous) -->
{@html content}
<!-- Debug -->
{@debug variable}
<!-- Define snippets -->
{#snippet name(param1, param2)}
<div>{param1}</div>
{/snippet}
Component Patterns
<!-- Basic Component -->
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
title: string;
variant?: 'primary' | 'secondary';
disabled?: boolean;
onclick?: () => void;
children: Snippet;
}
let {
title,
variant = 'primary',
disabled = false,
onclick,
children
}: Props = $props();
</script>
<button
class="btn btn-{variant}"
{disabled}
{onclick}
>
{@render children()}
</button>
<!-- With Named Snippets -->
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
header?: Snippet;
children?: Snippet;
footer?: Snippet<[{ close: () => void }]>;
}
let { header, children, footer }: Props = $props();
function close() {
// close logic
}
</script>
{@render header?.()}
{@render children?.()}
{@render footer?.({ close })}
State Management
// stores/counter.svelte.ts
export class CounterStore {
count = $state(0);
doubled = $derived(this.count * 2);
increment = () => { this.count++; }
decrement = () => { this.count--; }
reset = () => { this.count = 0; }
}
export const counter = new CounterStore();
// Usage in component
import { counter } from '$lib/stores/counter.svelte';
// Read: counter.count, counter.doubled
// Write: counter.increment()
SvelteKit Essentials
// +page.ts (Universal load)
export async function load({ params, fetch }) {
const data = await fetch(`/api/items/${params.id}`);
return { item: await data.json() };
}
// +page.server.ts (Server-only load)
export async function load({ params, locals }) {
return { user: locals.user };
}
// Form Actions
export const actions = {
default: async ({ request }) => {
const data = await request.formData();
// Process form
return { success: true };
},
named: async ({ request }) => {
// Named action: <form action="?/named">
}
};
// API Routes (+server.ts)
export async function GET({ params }) {
return json({ data: 'value' });
}
export async function POST({ request }) {
const body = await request.json();
return json({ created: true }, { status: 201 });
}
File Structure
src/
├── app.html # HTML template
├── app.d.ts # Type declarations
├── lib/
│ ├── components/ # Reusable components
│ ├── stores/ # State (.svelte.ts files)
│ ├── utils/ # Utility functions
│ ├── hooks/ # Custom hooks
│ └── server/ # Server-only code
├── routes/
│ ├── +page.svelte # Page component
│ ├── +page.ts # Page load (universal)
│ ├── +page.server.ts # Page load (server) + actions
│ ├── +layout.svelte # Layout component
│ ├── +layout.ts # Layout load
│ ├── +error.svelte # Error page
│ └── api/
│ └── +server.ts # API endpoint
└── hooks.server.ts # Server hooks
Common Anti-Patterns
<!-- ❌ DON'T: Destructure reactive state -->
let { name } = user; // Loses reactivity!
<!-- ✅ DO: Access properties directly -->
{user.name}
<!-- ❌ DON'T: Use $effect for derived values -->
$effect(() => {
doubled = count * 2; // Use $derived instead!
});
<!-- ✅ DO: Use $derived -->
let doubled = $derived(count * 2);
<!-- ❌ DON'T: Forget optional chaining for snippets -->
{@render children()} // May error if undefined
<!-- ✅ DO: Use optional chaining -->
{@render children?.()}
<!-- ❌ DON'T: Modify state in $derived -->
let bad = $derived(count++); // Side effect!
<!-- ✅ DO: Keep $derived pure -->
let good = $derived(count + 1);
TypeScript Quick Types
import type {
Snippet, // Snippet type
Component, // Component type
ComponentProps // Extract props from component
} from 'svelte';
import type {
PageData, // From +page.ts load
PageServerData, // From +page.server.ts load
Actions, // Form actions type
RequestHandler // API route handler
} from './$types';
// Snippet with params
type ItemSnippet = Snippet<[{ item: Item; index: number }]>;
// Component props
type ButtonProps = ComponentProps<typeof Button>;
Key Commands
# Create new project
npx sv create my-app
# Development
npm run dev
# Build
npm run build
# Preview production build
npm run preview
# Type checking
npm run check
# Run migration
npx sv migrate svelte-5