--- name: svelte-frontend description: Svelte coding guidelines for the Windmill frontend. MUST use when writing or modifying code in the frontend directory. --- # Svelte 5 Best Practices This guide outlines best practices for developing with Svelte 5, incorporating the new Runes API and other modern Svelte features. These rules MUST NOT be applied on svelte 4 files unless explicitly asked to do so. ## Reactivity with Runes Svelte 5 introduces Runes for more explicit and flexible reactivity. 1. **Embrace Runes for State Management**: * Use `$state` for reactive local component state. ```svelte ``` * Use `$derived` for computed values based on other reactive state. ```svelte

{count} * 2 = {doubled}

``` * Use `$effect` for side effects that need to run when reactive values change (e.g., logging, manual DOM manipulation, data fetching). Remember `$effect` does not run on the server. ```svelte ``` 2. **Props with `$props`**: * Declare component props using `$props()`. This offers better clarity and flexibility compared to `export let`. ```svelte

Name: {name}

Age: {age}

``` * For bindable props, use `$bindable`. ```svelte ``` ## Event Handling * **Use direct event attributes**: Svelte 5 moves away from `on:` directives for DOM events. * **Do**: `` * **Don't**: `` * **For component events, prefer callback props**: Instead of `createEventDispatcher`, pass functions as props. ```svelte

Message from child: {message}

``` ## Snippets for Content Projection * **Use `{#snippet ...}` and `{@render ...}` instead of slots**: Snippets are more powerful and flexible. ```svelte {#snippet title()} My Awesome Title {/snippet} {#snippet content()}

Some interesting content here.

{/snippet}
{@render title()}
{@render content()}
``` * Default content is passed via the `children` prop (which is a snippet). ```svelte
{@render children?.()}
``` ## Component Design 1. **Create Small, Reusable Components**: Break down complex UIs into smaller, focused components. Each component should have a single responsibility. This also aids performance by limiting the scope of reactivity updates. 2. **Descriptive Naming**: Use clear and descriptive names for variables, functions, and components. 3. **Minimize Logic in Components**: Move complex business logic to utility functions or services. Keep components focused on presentation and interaction. ## State Management (Stores) 1. **Segment Stores**: Avoid a single global store. Create multiple stores, each responsible for a specific piece of global state (e.g., `userStore.js`, `themeStore.js`). This can help limit reactivity updates to only the parts of the UI that depend on specific state segments. 2. **Use Custom Stores for Complex Logic**: For stores with related methods, create custom stores. ```javascript // counterStore.js import { writable } from 'svelte/store'; function createCounter() { const { subscribe, set, update } = writable(0); return { subscribe, increment: () => update(n => n + 1), decrement: () => update(n => n - 1), reset: () => set(0) }; } export const counter = createCounter(); ``` 3. **Use Context API for Localized State**: For state shared within a component subtree, consider Svelte's context API (`setContext`, `getContext`) instead of global stores when the state doesn't need to be truly global. ## Performance Optimizations (Svelte 5) When generating Svelte 5 code, prioritize frontend performance by applying the following principles: ### General Svelte 5 Principles - **Leverage the Compiler:** Trust Svelte's compiler to generate optimized JavaScript. Avoid manual DOM manipulation (`document.querySelector`, etc.) unless absolutely necessary for integrating third-party libraries that lack Svelte adapters. - **Keep Components Small and Focused:** Reinforcing from Component Design, smaller components lead to less complex reactivity graphs and more targeted, efficient updates. ### Reactivity & State Management - **Optimize Computations with `$derived`:** Always use `$derived` for computed values that depend on other state. This ensures the computation only runs when its specific dependencies change, avoiding unnecessary work compared to recomputing derived values in `$effect` or less efficient methods. - **Minimize `$effect` Usage:** Use `$effect` sparingly and only for true side effects that interact with the outside world or non-Svelte state. Avoid putting complex logic or state updates *within* an `$effect` unless those updates are explicitly intended as a reaction to external changes or non-Svelte state. Excessive or complex effects can impact rendering performance. - **Structure State for Fine-Grained Updates:** Design your `$state` objects or variables such that updates affect only the necessary parts of the UI. Avoid putting too much unrelated state into a single large object that gets frequently updated, as this can potentially trigger broader updates than necessary. Consider normalizing complex, nested state. ### List Rendering (`{#each}`) - **Mandate `key` Attribute:** Always use a `key` attribute (`{#each items as item (item.id)}`) that refers to a unique, stable identifier for each item in a list. This is critical for allowing Svelte to efficiently update, reorder, add, or remove list items without destroying and re-creating unnecessary DOM elements and component instances. ### Component Loading & Bundling - **Implement Lazy Loading/Code Splitting:** For routes, components, or modules that are not immediately needed on page load, use dynamic imports (`import(...)`) to split the code bundle. SvelteKit handles this automatically for routes, but it can be applied manually to components using helper patterns if needed. - **Be Mindful of Third-Party Libraries:** When incorporating external libraries, import only the necessary functions or components to minimize the final bundle size. Prefer libraries designed to be tree-shakeable. ### Rendering & DOM - **Use CSS for Animations/Transitions:** Prefer CSS animations or transitions where possible for performance. Svelte's built-in `transition:` directive is also highly optimized and should be used for complex state-driven transitions, but simple cases can often use plain CSS. - **Optimize Image Loading:** Implement best practices for images: use optimized formats (WebP, AVIF), lazy loading (`loading="lazy"`), and responsive images (``, `srcset`) to avoid loading unnecessarily large images. ### Server-Side Rendering (SSR) & Hydration - **Ensure SSR Compatibility:** Write components that can be rendered on the server for faster initial page loads. Avoid relying on browser-specific APIs (like `window` or `document`) in the main `
Hello
``` 5. **Stay Updated**: Keep Svelte and its related packages up to date to benefit from the latest features, performance improvements, and security fixes.