Cleanup: Remove old modes, add Svelte 5 reference library, update orchestrator
- 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
This commit is contained in:
@@ -0,0 +1,343 @@
|
||||
# Svelte 5 Quick Reference Card
|
||||
|
||||
## Runes Cheat Sheet
|
||||
|
||||
```svelte
|
||||
<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
|
||||
|
||||
```svelte
|
||||
<!-- 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
|
||||
|
||||
```svelte
|
||||
<!-- 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// +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
|
||||
|
||||
```svelte
|
||||
<!-- ❌ 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user