I'm using svelte 5 instead of svelte 4 here is an overview of the changes.
I'm using svelte 5 instead of svelte 4 here is an overview of the changes.
#### Overview
Svelte 5 introduces runes, a set of advanced primitives for controlling reactivity. The runes replace certain non-runes features and provide more explicit control over state and effects.
#### $state
- **Purpose:** Declare reactive state.
- **Usage:**
```javascript
<script>let count = $state(0);</script>
```
- **Replaces:** Top-level `let` declarations in non-runes mode.
- **Class Fields:**
```javascript
class Todo {
done = $state(false);
text = $state();
constructor(text) {
this.text = text;
}
}
```
- **Deep Reactivity:** Only plain objects and arrays become deeply reactive.
#### $state.raw
- **Purpose:** Declare state that cannot be mutated, only reassigned.
- **Usage:**
```javascript
<script>let numbers = $state.raw([1, 2, 3]);</script>
```
- **Performance:** Improves with large arrays and objects.
#### $state.snapshot
- **Purpose:** Take a static snapshot of $state.
- **Usage:**
```javascript
<script>
let counter = $state({ count: 0 });
function onClick() {
console.log($state.snapshot(counter));
}
</script>
```
#### $derived
- **Purpose:** Declare derived state.
- **Usage:**
```javascript
<script>let count = $state(0); let doubled = $derived(count * 2);</script>
```
- **Replaces:** Reactive variables computed using `$:` in non-runes mode.
#### $derived.by
- **Purpose:** Create complex derivations with a function.
- **Usage:**
```javascript
<script>
let numbers = $state([1, 2, 3]); let total = $derived.by(() => numbers.reduce((a, b) => a + b,
0));
</script>
```
#### $effect
- **Purpose:** Run side-effects when values change.
- **Usage:**
```javascript
<script>
let size = $state(50);
let color = $state('#ff3e00');
$effect(() => {
const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = color;
context.fillRect(0, 0, size, size);
});
</script>
```
- **Replacements:** $effect replaces a substantial part of `$: {}` blocks triggering side-effects.
#### $effect.pre
- **Purpose:** Run code before the DOM updates.
- **Usage:**
```javascript
<script>
$effect.pre(() =>{' '}
{
// logic here
}
);
</script>
```
- **Replaces:** beforeUpdate.
#### $effect.tracking
- **Purpose:** Check if code is running inside a tracking context.
- **Usage:**
```javascript
<script>console.log('tracking:', $effect.tracking());</script>
```
#### $props
- **Purpose:** Declare component props.
- **Usage:**
```javascript
<script>let {(prop1, prop2)} = $props();</script>
```
- **Replaces:** export let syntax for declaring props.
#### $bindable
- **Purpose:** Declare bindable props.
- **Usage:**
```javascript
<script>let {(bindableProp = $bindable('fallback'))} = $props();</script>
```
#### $inspect
- **Purpose:** Equivalent to `console.log` but re-runs when its argument changes.
- **Usage:**
```javascript
<script>let count = $state(0); $inspect(count);</script>
```
#### $host
- **Purpose:** Retrieve the this reference of the custom element.
- **Usage:**
```javascript
<script>
function greet(greeting) {
$host().dispatchEvent(new CustomEvent('greeting', { detail: greeting }));
}
</script>
```
- **Note:** Only available inside custom element components on the client-side.
#### Overview of snippets in svelte 5
Snippets, along with render tags, help create reusable chunks of markup inside your components, reducing duplication and enhancing maintainability.
#### Snippets Usage
- **Definition:** Use the `#snippet` syntax to define reusable markup sections.
- **Basic Example:**
```javascript
{#snippet figure(image)}
<figure>
<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
<figcaption>{image.caption}</figcaption>
</figure>
{/snippet}
```
- **Invocation:** Render predefined snippets with `@render`:
```javascript
{@render figure(image)}
```
- **Destructuring Parameters:** Parameters can be destructured for concise usage:
```javascript
{#snippet figure({ src, caption, width, height })}
<figure>
<img alt={caption} {src} {width} {height} />
<figcaption>{caption}</figcaption>
</figure>
{/snippet}
```
#### Snippet Scope
- **Scope Rules:** Snippets have lexical scoping rules; they are visible to everything in the same lexical scope:
```javascript
<div>
{#snippet x()}
{#snippet y()}...{/snippet}
<!-- valid usage -->
{@render y()}
{/snippet}
<!-- invalid usage -->
{@render y()}
</div>
<!-- invalid usage -->
{@render x()}
```
- **Recursive References:** Snippets can self-reference or reference other snippets:
```javascript
{#snippet blastoff()}
<span>🚀</span>
{/snippet}
{#snippet countdown(n)}
{#if n > 0}
<span>{n}...</span>
{@render countdown(n - 1)}
{:else}
{@render blastoff()}
{/if}
{/snippet}
{@render countdown(10)}
```
#### Passing Snippets to Components
- **Direct Passing as Props:**
```javascript
<script>
import Table from './Table.svelte';
const fruits = [{ name: 'apples', qty: 5, price: 2 }, ...];
</script>
{#snippet header()}
<th>fruit</th>
<th>qty</th>
<th>price</th>
<th>total</th>
{/snippet}
{#snippet row(fruit)}
<td>{fruit.name}</td>
<td>{fruit.qty}</td>
<td>{fruit.price}</td>
<td>{fruit.qty * fruit.price}</td>
{/snippet}
<Table data={fruits} {header} {row} />
```
- **Implicit Binding:**
```html
<table data="{fruits}">
{#snippet header()}
<th>fruit</th>
<th>qty</th>
<th>price</th>
<th>total</th>
{/snippet} {#snippet row(fruit)}
<td>{fruit.name}</td>
<td>{fruit.qty}</td>
<td>{fruit.price}</td>
<td>{fruit.qty * fruit.price}</td>
{/snippet}
</table>
```
- **Children Snippet:** Non-snippet content defaults to the `children` snippet:
```html
<table data="{fruits}">
<th>fruit</th>
<th>qty</th>
<th>price</th>
<th>total</th>
<!-- additional content -->
</table>
<script>
let { data, children, row } = $props();
</script>
<table>
<thead>
<tr>
{@render children()}
</tr>
</thead>
<!-- table body -->
</table>
```
- **Avoid Conflicts:** Do not use a prop named `children` if also providing content inside the component.
#### Typing Snippets
- **TypeScript Integration:**
```typescript
<script lang="ts">
import type { Snippet } from 'svelte';
let { data, children, row }: {
data: any[];
children: Snippet;
row: Snippet<[any]>;
} = $props();
</script>
```
- **Generics for Improved Typing:**
```typescript
<script lang="ts" generics="T">
import type { Snippet } from 'svelte';
let { data, children, row }: {
data: T[];
children: Snippet;
row: Snippet<[T]>;
} = $props();
</script>
```
#### Creating Snippets Programmatically
- **Advanced Use:** Create snippets programmatically using `createRawSnippet` where necessary.
#### Snippets and Slots
- **Mixing with Slots:** Slots are deprecated but still work. Snippets provide more flexibility and power.
- **Custom Elements:** Continue using `<slot />` for custom elements as usual.
Sure! Here are the succinct instructions for handling Event Handlers in Svelte 5, tailored for the AI-integrated code editor to help it understand and utilize these features effectively.
---
### Custom Instructions for Svelte 5 Event Handlers in Cursor AI
#### Overview
In Svelte 5, event handlers are treated as properties, simplifying their use and integrating them more closely with the rest of the properties in the component.
#### Basic Event Handlers
- **Declaration:** Use properties to attach event handlers.
```javascript
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
clicks: {count}
</button>
```
- **Shorthand Syntax:**
```javascript
<script>
let count = $state(0);
function handleClick() {
count++;
}
</script>
<button {handleClick}>
clicks: {count}
</button>
```
- **Deprecation:** The traditional `on:` directive is deprecated.
#### Component Events
- **Replacing createEventDispatcher:** Components should accept callback props instead of using `createEventDispatcher`.
```javascript
<script>
import Pump from './Pump.svelte';
let size = $state(15);
let burst = $state(false);
function reset() {
size = 15;
burst = false;
}
</script>
<Pump
inflate={(power) => { size += power; if (size > 75) burst = true; }}
deflate={(power) => { if (size > 0) size -= power; }}
/>
{#if burst}
<button onclick={reset}>new balloon</button>
<span class="boom">💥</span>
{:else}
<span class="balloon" style="scale: {0.01 * size}"> 🎈 </span>
{/if}
```
#### Bubbling Events
- **Accept Callback Props:**
```javascript
<script>
let { onclick, children } = $props();
</script>
<button {onclick}>
{@render children()}
</button>
```
- **Spreading Props:**
```javascript
<script>
let { children, ...props } = $props();
</script>
<button {...props}>
{@render children()}
</button>
```
#### Event Modifiers
- **Avoiding Modifiers:** Modifiers like `|once`, `|preventDefault`, etc., are not supported. Use wrapper functions instead.
- **Example Wrapper Functions:**
```javascript
<script>
function once(fn) {
return function (event) {
if (fn) fn.call(this, event);
fn = null;
};
}
function preventDefault(fn) {
return function (event) {
event.preventDefault();
fn.call(this, event);
};
}
</script>
<button onclick={once(preventDefault(handler))}>...</button>
```
- **Special Modifiers:** For `capture`:
```javascript
<button onclickcapture={...}>...</button>
```
#### Multiple Event Handlers
- **Combining Handlers:** Instead of using multiple handlers, combine them into one.
```javascript
<button
onclick={(e) => {
handlerOne(e);
handlerTwo(e);
}}
>
...
</button>
```
---
### examples old vs new
#### Counter Example
- **Svelte 4 vs. Svelte 5:**
- **Before:**
```html
<script>
let count = 0;
$: double = count * 2;
$: {
if (count > 10) alert('Too high!');
}
</script>
<button on:click="{()" ="">count++}> {count} / {double}</button>
```
- **After:**
```html
<script>
let count = $state(0);
let double = $derived(count * 2);
$effect(() => {
if (count > 10) alert('Too high!');
});
</script>
<button onclick="{()" ="">count++}> {count} / {double}</button>
```
#### Tracking Dependencies
- **Svelte 4 vs. Svelte 5:**
- **Before:**
```html
<script>
let a = 0;
let b = 0;
$: sum = add(a, b);
function add(x, y) {
return x + y;
}
</script>
<button on:click="{()" ="">a++}>a++</button>
<button on:click="{()" ="">b++}>b++</button>
<p>{a} + {b} = {sum}</p>
```
- **After:**
```html
<script>
let a = $state(0);
let b = $state(0);
let sum = $derived(add());
function add() {
return a + b;
}
</script>
<button onclick="{()" ="">a++}>a++</button>
<button onclick="{()" ="">b++}>b++</button>
<p>{a} + {b} = {sum}</p>
```
#### Untracking Dependencies
- **Svelte 4 vs. Svelte 5:**
- **Before:**
```html
<script>
let a = 0;
let b = 0;
$: sum = a + noTrack(b);
function noTrack(value) {
return value;
}
</script>
<button on:click="{()" ="">a++}>a++</button>
<button on:click="{()" ="">b++}>b++</button>
<p>{a} + {b} = {sum}</p>
```
- **After:**
```html
<script>
import { untrack } from 'svelte';
let a = $state(0);
let b = $state(0);
let sum = $derived(add());
function add() {
return a + untrack(() => b);
}
</script>
<button onclick="{()" ="">a++}>a++</button>
<button onclick="{()" ="">b++}>b++</button>
<p>{a} + {b} = {sum}</p>
```
#### Simple Component Props
- **Svelte 5:**
```html
<script>
let { count = 0 } = $props();
</script>
{count}
```
#### Advanced Component Props
- **Svelte 5:**
```html
<script>
let { class: classname, ...others } = $props();
</script>
<pre class="{classname}">
{JSON.stringify(others)}
</pre>
```
#### Autoscroll Example
- **Svelte 4 vs. Svelte 5:**
- **Before:**
```html
<script>
import { tick, beforeUpdate } from 'svelte';
let theme = 'dark';
let messages = [];
let viewport;
let updatingMessages = false;
beforeUpdate(() => {
if (updatingMessages) {
const autoscroll =
viewport && viewport.offsetHeight + viewport.scrollTop > viewport.scrollHeight - 50;
if (autoscroll) {
tick().then(() => viewport.scrollTo(0, viewport.scrollHeight));
}
}
});
function handleKeydown(event) {
if (event.key === 'Enter') {
const text = event.target.value;
if (text) {
messages = [...messages, text];
updatingMessages = true;
event.target.value = '';
}
}
}
function toggle() {
theme = theme === 'dark' ? 'light' : 'dark';
}
</script>
<div class:dark="{theme" ="" ="" ="dark" }>
<div bind:this="{viewport}">
{#each messages as message}
<p>{message}</p>
{/each}
</div>
<input on:keydown="{handleKeydown}" />
<button on:click="{toggle}">Toggle dark mode</button>
</div>
```
- **After:**
```html
<script>
import { tick } from 'svelte';
let theme = $state('dark');
let messages = $state([]);
let viewport;
$effect.pre(() => {
messages;
const autoscroll =
viewport && viewport.offsetHeight + viewport.scrollTop > viewport.scrollHeight - 50;
if (autoscroll) {
tick().then(() => viewport.scrollTo(0, viewport.scrollHeight));
}
});
function handleKeydown(event) {
if (event.key === 'Enter') {
const text = event.target.value;
if (text) {
messages = [...messages, text];
event.target.value = '';
}
}
}
function toggle() {
theme = theme === 'dark' ? 'light' : 'dark';
}
</script>
<div class:dark="{theme" ="" ="" ="dark" }>
<div bind:this="{viewport}">
{#each messages as message}
<p>{message}</p>
{/each}
</div>
<input onkeydown="{handleKeydown}" />
<button onclick="{toggle}">Toggle dark mode</button>
</div>
```
#### Forwarding Events
- **Svelte 5:**
```html
<script>
let { ...props } = $props();
</script>
<button {...props}>a button</button>
```
#### Passing UI Content to a Component
- **Passing content using snippets:**
```html
<!-- consumer -->
<script>
import Button from './Button.svelte';
</script>
<button>{#snippet children(prop)} click {prop} {/snippet}</button>
<!-- provider (Button.svelte) -->
<script>
let { children } = $props();
</script>
<button>{@render children("some value")}</button>
```
I'm also using sveltekit 2 which also has some changes I'd like you to keep in mind
### Redirect and Error Handling
In SvelteKit 2, it is no longer necessary to throw the results of `error(...)` and `redirect(...)`. Simply calling them is sufficient.
**SvelteKit 1:**
```javascript
import { error } from '@sveltejs/kit';
function load() {
throw error(500, 'something went wrong');
}
```
**SvelteKit 2:**
```javascript
import { error } from '@sveltejs/kit';
function load() {
error(500, 'something went wrong');
}
```
**Distinguish Errors:**
Use `isHttpError` and `isRedirect` to differentiate known errors from unexpected ones.
```javascript
import { isHttpError, isRedirect } from '@sveltejs/kit';
try {
// some code
} catch (err) {
if (isHttpError(err) || isRedirect(err)) {
// handle error
}
}
```
### Cookie Path Requirement
Cookies now require a specified path when set, deleted, or serialized.
**SvelteKit 1:**
```javascript
export function load({ cookies }) {
cookies.set(name, value);
return { response };
}
```
**SvelteKit 2:**
```javascript
export function load({ cookies }) {
cookies.set(name, value, { path: '/' });
return { response };
}
```
### Top-Level Promise Handling
Promises in `load` functions are no longer awaited automatically.
**Single Promise:**
**SvelteKit 1:**
```javascript
export function load({ fetch }) {
return {
response: fetch(...).then(r => r.json())
};
}
```
**SvelteKit 2:**
```javascript
export async function load({ fetch }) {
const response = await fetch(...).then(r => r.json());
return { response };
}
```
**Multiple Promises:**
**SvelteKit 1:**
```javascript
export function load({ fetch }) {
return {
a: fetch(...).then(r => r.json()),
b: fetch(...).then(r => r.json())
};
}
```
**SvelteKit 2:**
```javascript
export async function load({ fetch }) {
const [a, b] = await Promise.all([
fetch(...).then(r => r.json()),
fetch(...).then(r => r.json())
]);
return { a, b };
}
```
### `goto` Changes
`goto(...)` no longer accepts external URLs. Use `window.location.href = url` for external navigation.
### Relative Paths Default
Paths are now relative by default, ensuring portability across different environments. The `paths.relative` config option manages this behavior.
### Deprecated Settings and Functions
- **Server Fetches** are no longer trackable.
- **`preloadCode` Arguments:** Must be prefixed with the base path.
- **`resolvePath` Replacement:** Use `resolveRoute` instead.
```javascript
import { resolveRoute } from '$app/paths';
const path = resolveRoute('/blog/[slug]', { slug: 'hello' });
```
### Improved Error Handling
Errors trigger the `handleError` hook with `status` and `message` properties for better discernment.
### Dynamic Environment Variables
Dynamic environment variables cannot be used during prerendering. Use static modules instead.
### `use:enhance` Callback Changes
The properties `form` and `data` have been removed from `use:enhance` callbacks, replaced by `formElement` and `formData`.
### Forms with File Inputs
Forms containing `<input type="file">` must use `enctype="multipart/form-data"`.
With these adjusted guidelines, your AI can now generate SvelteKit 2 code accurately while considering the migration changes.Comprehensive .cursorrules file for Next.js 15 App Router projects with TypeScript, enforcing server components by default, proper use of "use client" directive, and App Router conventions.
Cursor rules for Python FastAPI projects enforcing async patterns, Pydantic v2 models, dependency injection, and proper error handling.
Rules for consistent React component development with TypeScript interfaces, proper hook patterns, and component composition.
Rules optimizing Cursor Agent mode behavior including multi-file editing context, session management, and autonomous task completion patterns.
Cursor rules for projects using Tailwind CSS with shadcn/ui component library, enforcing consistent utility class usage and component patterns.
Rules for Go backend services enforcing idiomatic Go patterns, proper error handling, and clean architecture conventions.