svelte-frontend

📁 windmill-labs/windmill 📅 Today
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.

  1. Embrace Runes for State Management:

    • Use $state for 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 $derived for computed values based on other reactive state.
      <script>
        let count = $state(0);
        const doubled = $derived(count * 2);
      </script>
      
      <p>{count} * 2 = {doubled}</p>
      
    • 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.
      <script>
        let count = $state(0);
      
        $effect(() => {
          console.log('The count is now', count);
          if (count > 5) {
            alert('Count is too high!');
          }
        });
      </script>
      
  2. Props with $props:

    • Declare component props using $props(). This offers better clarity and flexibility compared to export 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 />
      

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>
  • 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 children prop (which is a snippet).
    <!-- Wrapper.svelte -->
    <script>
      let { children } = $props();
    </script>
    <div>
      {@render children?.()}
    </div>
    

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.
    // 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 (<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 window or document) in the main <script> context. If necessary, use $effect or check if (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

  1. 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)
    
  2. Scoped Styles: Keep CSS scoped to components to avoid unintended side effects and improve maintainability. Avoid :global where possible.
  3. Immutability: With Svelte 5 and $state, direct assignments to properties of $state objects (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.
  4. Use class: and style: 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>
    
  5. Stay Updated: Keep Svelte and its related packages up to date to benefit from the latest features, performance improvements, and security fixes.