svelte-frontend
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSvelte 5 Best Practices
Svelte 5 最佳实践
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.
本指南概述了使用Svelte 5开发的最佳实践,涵盖了新的Runes API及其他现代Svelte特性。除非明确要求,否则这些规则不得应用于Svelte 4文件。
Reactivity with Runes
基于Runes的响应式处理
Svelte 5 introduces Runes for more explicit and flexible reactivity.
-
Embrace Runes for State Management:
- Use for reactive local component state.
$statesvelte<script> let count = $state(0); function increment() { count += 1; } </script> <button onclick={increment}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> - Use for computed values based on other reactive state.
$derivedsvelte<script> let count = $state(0); const doubled = $derived(count * 2); </script> <p>{count} * 2 = {doubled}</p> - Use for 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.$effectsvelte<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 . This offers better clarity and flexibility compared to
$props().export letsvelte<script> // ChildComponent.svelte let { name, age = $state(30) } = $props(); </script> <p>Name: {name}</p> <p>Age: {age}</p> - For bindable props, use .
$bindablesvelte<script> // MyInput.svelte let { value = $bindable() } = $props(); </script> <input bind:value />
- Declare component props using
Svelte 5引入了Runes,实现更明确、更灵活的响应式机制。
-
使用Runes进行状态管理:
- 使用定义组件的响应式本地状态。
$statesvelte<script> let count = $state(0); function increment() { count += 1; } </script> <button onclick={increment}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> - 使用基于其他响应式状态计算衍生值。
$derivedsvelte<script> let count = $state(0); const doubled = $derived(count * 2); </script> <p>{count} * 2 = {doubled}</p> - 使用处理响应式值变化时需要执行的副作用(例如日志记录、手动DOM操作、数据获取)。注意
$effect不会在服务器端运行。$effectsvelte<script> let count = $state(0); $effect(() => { console.log('The count is now', count); if (count > 5) { alert('Count is too high!'); } }); </script>
- 使用
-
使用定义属性:
$props- 使用声明组件属性,相比
$props(),它更清晰、灵活。export letsvelte<script> // ChildComponent.svelte let { name, age = $state(30) } = $props(); </script> <p>Name: {name}</p> <p>Age: {age}</p> - 对于可绑定的属性,使用。
$bindablesvelte<script> // MyInput.svelte let { value = $bindable() } = $props(); </script> <input bind:value />
- 使用
Event Handling
事件处理
- Use direct event attributes: Svelte 5 moves away from directives for DOM events.
on:- Do:
<button onclick={handleClick}>...</button> - Don't:
<button on:click={handleClick}>...</button>
- Do:
- For component events, prefer callback props: Instead of , pass functions as props.
createEventDispatchersvelte<!-- 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>
- 使用直接事件属性:Svelte 5不再推荐对DOM事件使用指令。
on:- 推荐:
<button onclick={handleClick}>...</button> - 不推荐:
<button on:click={handleClick}>...</button>
- 推荐:
- 组件事件优先使用回调属性:替代,将函数作为属性传递。
createEventDispatchersvelte<!-- 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
内容投影使用Snippets
- Use and
{#snippet ...}instead of slots: Snippets are more powerful and flexible.{@render ...}svelte<!-- 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 prop (which is a snippet).
childrensvelte<!-- Wrapper.svelte --> <script> let { children } = $props(); </script> <div> {@render children?.()} </div>
- 使用和
{#snippet ...}替代插槽:Snippets更强大、灵活。{@render ...}svelte<!-- 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> - 默认内容通过属性传递(它是一个snippet)。
childrensvelte<!-- 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.
- 创建小巧、可复用的组件:将复杂UI拆分为更小、专注单一职责的组件。这也有助于通过限制响应式更新的范围来提升性能。
- 命名清晰描述性:为变量、函数和组件使用清晰、具有描述性的名称。
- 减少组件内的逻辑:将复杂的业务逻辑移至工具函数或服务中,让组件专注于展示和交互。
State Management (Stores)
状态管理(Stores)
- Segment Stores: Avoid a single global store. Create multiple stores, each responsible for a specific piece of global state (e.g., ,
userStore.js). This can help limit reactivity updates to only the parts of the UI that depend on specific state segments.themeStore.js - 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(); - Use Context API for Localized State: For state shared within a component subtree, consider Svelte's context API (,
setContext) instead of global stores when the state doesn't need to be truly global.getContext
- 拆分Store:避免单一全局Store,创建多个Store,每个Store负责特定的全局状态(例如、
userStore.js)。这有助于将响应式更新限制在仅依赖特定状态的UI部分。themeStore.js - 复杂逻辑使用自定义Store:对于包含相关方法的Store,创建自定义Store。
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(); - 局部状态使用Context API:对于组件子树内共享的状态,当状态不需要真正全局时,考虑使用Svelte的Context API(、
setContext)替代全局Store。getContext
Performance Optimizations (Svelte 5)
性能优化(Svelte 5)
When generating Svelte 5 code, prioritize frontend performance by applying the following principles:
在编写Svelte 5代码时,应遵循以下原则优先提升前端性能:
General Svelte 5 Principles
通用Svelte 5原则
- Leverage the Compiler: Trust Svelte's compiler to generate optimized JavaScript. Avoid manual DOM manipulation (, etc.) unless absolutely necessary for integrating third-party libraries that lack Svelte adapters.
document.querySelector - Keep Components Small and Focused: Reinforcing from Component Design, smaller components lead to less complex reactivity graphs and more targeted, efficient updates.
- 利用编译器优化:信任Svelte编译器生成优化后的JavaScript。除非绝对必要(例如集成缺乏Svelte适配器的第三方库),否则避免手动DOM操作(等)。
document.querySelector - 保持组件小巧专注:与组件设计部分的建议一致,更小的组件会减少响应式图的复杂度,实现更精准、高效的更新。
Reactivity & State Management
响应式与状态管理
- Optimize Computations with : 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$derivedor less efficient methods.$effect - Minimize Usage: 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.$effect - Structure State for Fine-Grained Updates: Design your 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.
$state
- 使用优化计算:对于依赖其他状态的衍生值,始终使用
$derived。这确保计算仅在其特定依赖项变化时执行,相比在$derived中重新计算衍生值或其他低效方法,避免了不必要的工作。$effect - 减少的使用:谨慎使用
$effect,仅将其用于与外部世界或非Svelte状态交互的真正副作用。避免在$effect中放置复杂逻辑或状态更新,除非这些更新是为了响应外部变化或非Svelte状态而明确设计的。过多或复杂的effect会影响渲染性能。$effect - 设计细粒度更新的状态:设计对象或变量时,确保更新仅影响UI的必要部分。避免将过多不相关的状态放入一个频繁更新的大对象中,因为这可能会触发超出必要范围的更新。考虑对复杂的嵌套状态进行规范化。
$state
List Rendering ({#each}
)
{#each}列表渲染({#each}
)
{#each}- Mandate Attribute: Always use a
keyattribute (key) 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.{#each items as item (item.id)}
- 必须使用属性:始终为列表中的每个项使用
key属性(例如key),该属性指向每个项唯一、稳定的标识符。这对于Svelte高效更新、重排、添加或删除列表项至关重要,无需销毁和重新创建不必要的DOM元素和组件实例。{#each items as item (item.id)}
Component Loading & Bundling
组件加载与打包
- Implement Lazy Loading/Code Splitting: For routes, components, or modules that are not immediately needed on page load, use dynamic imports () to split the code bundle. SvelteKit handles this automatically for routes, but it can be applied manually to components using helper patterns if needed.
import(...) - 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.
- 实现懒加载/代码分割:对于页面加载时不需要的路由、组件或模块,使用动态导入()拆分代码包。SvelteKit会自动为路由处理此操作,但也可以根据需要通过辅助模式手动应用于组件。
import(...) - 谨慎引入第三方库:集成外部库时,仅导入必要的函数或组件,以最小化最终包的大小。优先选择支持tree-shaking的库。
Rendering & DOM
渲染与DOM
- Use CSS for Animations/Transitions: Prefer CSS animations or transitions where possible for performance. Svelte's built-in directive is also highly optimized and should be used for complex state-driven transitions, but simple cases can often use plain CSS.
transition: - Optimize Image Loading: Implement best practices for images: use optimized formats (WebP, AVIF), lazy loading (), and responsive images (
loading="lazy",<picture>) to avoid loading unnecessarily large images.srcset
- 使用CSS实现动画/过渡:尽可能使用CSS动画或过渡以提升性能。对于复杂的状态驱动过渡,应使用Svelte内置的指令,它经过高度优化,但简单场景通常可以使用纯CSS实现。
transition: - 优化图片加载:遵循图片最佳实践:使用优化格式(WebP、AVIF)、懒加载()和响应式图片(
loading="lazy"、<picture>),避免加载不必要的大尺寸图片。srcset
Server-Side Rendering (SSR) & Hydration
服务器端渲染(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 or
window) in the maindocumentcontext. If necessary, use<script>or check$effectinside effects to run browser-specific code only on the client.if (browser) - 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.
- 确保SSR兼容性:编写可在服务器端渲染的组件,以加快初始页面加载速度。避免在主上下文依赖浏览器特定API(如
<script>或window)。如有必要,使用document或在effect内检查$effect,仅在客户端运行浏览器特定代码。if (browser) - 减少hydration期间的工作:设计组件和数据获取逻辑,使得客户端Svelte代码接管服务器渲染的HTML时所需的复杂设置或计算最少。hydration期间的大量同步工作会阻塞主线程。
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 where possible.
:global - Immutability: With Svelte 5 and , direct assignments to properties of
$stateobjects ($state) 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.obj.prop = value; - Use and
class:directives: For dynamic classes and styles, use Svelte's built-in directives for cleaner templates and potentially optimized updates.style:svelte<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.
- 有序的文件结构:将相关文件分组。常见结构如下:
/src |-- /routes // 页面组件(如果使用SvelteKit等路由) |-- /lib // 工具函数、服务、常量(SvelteKit通常使用此目录) | |-- /stores | |-- /utils | |-- /services | |-- /components // 可复用UI组件 |-- App.svelte |-- main.js (or main.ts) - 作用域样式:将CSS限定在组件范围内,避免意外副作用并提升可维护性。尽可能避免使用。
:global - 不可变性:在Svelte 5和中,直接赋值给
$state对象的属性($state)通常是可行的,因为Svelte的响应式系统会处理更新。然而,对于非Rune状态或与其他系统交互时,理解并有时优先选择不可变更新(创建新对象/数组)仍然是有意义的。obj.prop = value; - 使用和
class:指令:对于动态类和样式,使用Svelte的内置指令,以获得更简洁的模板和可能的优化更新。style:svelte<script> let isActive = $state(true); let color = $state('blue'); </script> <div class:active={isActive} style:color={color}> Hello </div> - 保持更新:及时更新Svelte及其相关包,以受益于最新的特性、性能改进和安全修复。