svelte-frontend
0
总安装量
1
周安装量
安装命令
npx skills add https://github.com/windmill-labs/windmill --skill svelte-frontend
Agent 安装分布
amp
1
opencode
1
kimi-cli
1
codex
1
github-copilot
1
antigravity
1
Skill 文档
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.
-
Embrace Runes for State Management:
- Use
$statefor reactive local component state.<script> let count = $state(0); function increment() { count += 1; } </script> <button onclick={increment}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> - Use
$derivedfor computed values based on other reactive state.<script> let count = $state(0); const doubled = $derived(count * 2); </script> <p>{count} * 2 = {doubled}</p> - Use
$effectfor side effects that need to run when reactive values change (e.g., logging, manual DOM manipulation, data fetching). Remember$effectdoes not run on the server.<script> let count = $state(0); $effect(() => { console.log('The count is now', count); if (count > 5) { alert('Count is too high!'); } }); </script>
- Use
-
Props with
$props:- Declare component props using
$props(). This offers better clarity and flexibility compared toexport let.<script> // ChildComponent.svelte let { name, age = $state(30) } = $props(); </script> <p>Name: {name}</p> <p>Age: {age}</p> - For bindable props, use
$bindable.<script> // MyInput.svelte let { value = $bindable() } = $props(); </script> <input bind:value />
- Declare component props using
Event Handling
- Use direct event attributes: Svelte 5 moves away from
on:directives for DOM events.- Do:
<button onclick={handleClick}>...</button> - Don’t:
<button on:click={handleClick}>...</button>
- Do:
- For component events, prefer callback props: Instead of
createEventDispatcher, pass functions as props.<!-- Parent.svelte --> <script> import Child from './Child.svelte'; let message = $state(''); function handleChildEvent(detail) { message = detail; } </script> <Child onCustomEvent={handleChildEvent} /> <p>Message from child: {message}</p> <!-- Child.svelte --> <script> let { onCustomEvent } = $props(); function emitEvent() { onCustomEvent('Hello from child!'); } </script> <button onclick={emitEvent}>Send Event</button>
Snippets for Content Projection
- Use
{#snippet ...}and{@render ...}instead of slots: Snippets are more powerful and flexible.<!-- Parent.svelte --> <script> import Card from './Card.svelte'; </script> <Card> {#snippet title()} My Awesome Title {/snippet} {#snippet content()} <p>Some interesting content here.</p> {/snippet} </Card> <!-- Card.svelte --> <script> let { title, content } = $props(); </script> <article> <header>{@render title()}</header> <div>{@render content()}</div> </article> - Default content is passed via the
childrenprop (which is a snippet).<!-- Wrapper.svelte --> <script> let { children } = $props(); </script> <div> {@render children?.()} </div>
Component Design
- 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.
- Descriptive Naming: Use clear and descriptive names for variables, functions, and components.
- Minimize Logic in Components: Move complex business logic to utility functions or services. Keep components focused on presentation and interaction.
State Management (Stores)
- 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. - Use Custom Stores for Complex Logic: For stores with related methods, create custom stores.
// 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(); - 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$derivedfor 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$effector less efficient methods. - Minimize
$effectUsage: Use$effectsparingly 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$effectunless 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
$stateobjects 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
keyAttribute: Always use akeyattribute ({#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 (<picture>,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
windowordocument) in the main<script>context. If necessary, use$effector checkif (browser)inside effects to run browser-specific code only on the client. - Minimize Work During Hydration: Structure components and data fetching such that minimal complex setup or computation is required when the client-side Svelte code takes over from the server-rendered HTML. Heavy synchronous work during hydration can block the main thread.
General Clean Code Practices
- Organized File Structure: Group related files together. A common structure:
/src |-- /routes // Page components (if using a router like SvelteKit) |-- /lib // Utility functions, services, constants (SvelteKit often uses this) | |-- /stores | |-- /utils | |-- /services | |-- /components // Reusable UI components |-- App.svelte |-- main.js (or main.ts) - Scoped Styles: Keep CSS scoped to components to avoid unintended side effects and improve maintainability. Avoid
:globalwhere possible. - Immutability: With Svelte 5 and
$state, direct assignments to properties of$stateobjects (obj.prop = value;) are generally fine as Svelte’s reactivity system handles updates. However, for non-rune state or when interacting with other systems, understanding and sometimes preferring immutable updates (creating new objects/arrays) can still be relevant. - Use
class:andstyle:directives: For dynamic classes and styles, use Svelte’s built-in directives for cleaner templates and potentially optimized updates.<script> let isActive = $state(true); let color = $state('blue'); </script> <div class:active={isActive} style:color={color}> Hello </div> - Stay Updated: Keep Svelte and its related packages up to date to benefit from the latest features, performance improvements, and security fixes.