mcpField
S
svelte-misc

svelte-misc

github.com/full-stack-skillsDevelopment468 installsUpdated 5w ago
Repository

About svelte-misc

A reference skill for Svelte 5 developers, covering TypeScript, custom elements, browser support, recommended practices, and migration from Svelte 4. It brings practical guidance together for implementation and upgrade questions.

Key features

  1. 01Advanced TypeScript and component patterns
  2. 02Custom element and lifecycle guidance
  3. 03Browser compatibility and feature exceptions
  4. 04Svelte 5 reactivity practices
  5. 05Svelte 4-to-5 migration guidance

Use cases

  1. 01Typing generic or wrapper components
  2. 02Building Web Components
  3. 03Checking feature support in target browsers
  4. 04Migrating a Svelte 4 project incrementally

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/full-stack-skills/svelte-skills --skill svelte-misc

After installing, type/svelte-miscin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

agents/
openai.yaml
examples/
best-practices.md
browser-support.md
custom-elements.md
debug-html.md
dynamic-components.md
migration-v4.md
README.md
typescript-advanced.md
typescript.md
references/
best-practices.md
browser-support.md
custom-elements.md
dynamic-reference.md
README.md
typescript-advanced.md
typescript-reference.md

Details

From the project README

Svelte Misc Reference (Svelte 5)

本技能覆盖 Svelte 5 的 TypeScript 高级支持、自定义元素(Web Components)、浏览器兼容性矩阵、Svelte 4→5 迁移指南、官方最佳实践与常见问答。

When to use this skill

当用户需要 TypeScript 类型标注(泛型、包装组件、DOM 类型增强)、创建自定义 Web 组件并使用 $host() / $bindable / extend、查看浏览器兼容性矩阵与功能例外、从 Svelte 4 迁移到 Svelte 5,或遵循 Svelte 5 推荐的 $state / $derived / $effect 模式时使用本技能。


Critical: TypeScript 高级

Svelte 原生支持 TypeScript(Vite 项目无需配置)。用 <script lang="ts"> 启用类型注解;需要枚举 / 参数属性等运行时特性则需要预处理器。

<script lang="ts">
  let name: string = 'world';
  function greet(name: string) { alert(`Hello, ${name}!`); }
</script>
<button onclick={(e: Event) => greet((e.target as HTMLElement).innerText)}>
  {name}
</button>

lang="ts" 默认只支持「类型只消失」的特性(注解、接口、泛型)。运行时代码特性(enum、private foo = 1 形式的参数属性)需配置 vitePreprocess({ script: true })。

类型 Props + 透传
<script lang="ts">
  import type { Snippet } from 'svelte';
  interface Props {
    requiredProperty: number;
    optionalProperty?: boolean;
    snippetWithStringArgument: Snippet<[string]>;
    eventHandler: (arg: string) => void;
    [key: string]: unknown; // 配合 ...rest 透传其他属性
  }
  let { requiredProperty, optionalProperty, snippetWithStringArgument,
        eventHandler, ...rest }: Props = $props();
</script>
泛型组件

<script> 的 generics 属性接受与函数泛型同样的语法:

<script lang="ts" generics="Item extends { text: string }">
  interface Props { items: Item[]; select(item: Item): void; }
  let { items, select }: Props = $props();
</script>
{#each items as item}
  <button onclick={() => select(item)}>{item.text}</button>
{/each}
包装组件(转发原生属性)
<script lang="ts">
  import type { HTMLButtonAttributes } from 'svelte/elements';
  let { children, ...rest }: HTMLButtonAttributes = $props();
</script>
<button {...rest}>{@render children?.()}</button>

无专用接口的元素用 SvelteHTMLElements['div'] 形式。Component / ComponentProps<T> 用于约束动态组件与提取现有组件的 props。

类中 $state
class Counter {
  count = $state() as number; // 无初值类型会扩为 undefined
  constructor(initial: number) { this.count = initial; }
  increment() { this.count += 1; }
}
增强 svelte/elements
/// file: additional-svelte-typings.d.ts
declare module 'svelte/elements' {
  export interface SvelteHTMLElements { 'custom-button': HTMLButtonAttributes; }
  export interface HTMLAttributes<T> { globalattribute?: string; }
}
export {}; // 必须——否则会覆盖原模块

Critical: Custom Elements(Web Components)

基础用法
<svelte:options customElement="my-element" />
<script>
  let { name = 'world' } = $props();
</script>
<h1>Hello {name}!</h1>
<slot />

导入即自动 customElements.define() 注册。消费者可读写 DOM 属性:

const el = document.querySelector('my-element');
el.name = 'everybody'; // 触发 shadow DOM 更新

必须显式声明 props(不能只写 let props = $props()),否则 Svelte 不知道要暴露哪些键。

customElement 选项
<svelte:options customElement={{
  tag: 'my-counter',
  shadow: 'open',
  props: { count: { type: 'Number', reflect: true, attribute: 'start' } },
  extend: (Ctor) => class extends Ctor { /* ... */ }
}} />
字段取值默认作用
tagstring—标签名;设置后自动注册
shadow'none' | 'open' | 'closed' | ShadowRootInit'open'Shadow root 配置
props.<name>.attributestring小写 prop 名自定义属性名
props.<name>.reflectbooleanfalse将 prop 值镜像到 HTML 属性
props.<name>.type'String' | 'Boolean' | 'Number' | 'Array' | 'Object''String'属性 ↔ prop 类型转换
extend(Ctor) => class—包装生成的类(可注入 lifecycle / ElementInternals)
$host() Rune + 生命周期
<svelte:options customElement="tooltip" />
<script>
  import { $host } from 'svelte';
  let { text = 'hi' } = $props();
  function focus() { $host().focus(); }
</script>
<button onclick={focus}>{text}</button>
  • 内部组件在 connectedCallback 之后的下一个 tick 创建;插入前设置的属性被缓冲并应用。
  • Shadow DOM 更新批处理到下一个 tick;DOM 移动不会触发不必要的卸载。
  • disconnectedCallback 后下一个 tick 销毁。组件方法 mount 后才可用;要更早暴露请在 extend 类里声明。
重要注意事项
  • 样式封装而非「作用域」——全局 CSS 无法穿透 shadow root。
  • CSS 内联为 JS 字符串而非单独 .css 文件。
  • 不适合 SSR(shadow DOM 在 JS 加载前不可见)。
  • 插槽内容积极渲染(不像 Svelte 默认懒渲染),<slot> 在 {#each} 里不会复制内容。
  • let: 指令对自定义元素无效。Svelte context 不能跨自定义元素边界。
  • 不要命名 on* 属性(被解释为事件监听器)。

Critical: Browser Support

Svelte 5 目标是 Baseline 2020。

浏览器最低版本
Chrome / Edge87
Firefox83
Safari14
Opera73
Opera (Android)62
Samsung Internet14.0
Android WebView87
Internet Explorer不支持
例外情况
功能Chrome/EdgeFirefoxSafari
$state.snapshot989415.4
bind:devicePixelContentBoxSize—93不支持
flip(来自 svelte/animate)—126—
SSR 浏览器 API 保护
<script>
  import { onMount } from 'svelte';
  onMount(() => {
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  });
</script>

优先用 <svelte:window> / <svelte:document>;Svelte 自动处理 SSR 与卸载。


Critical: Best Practices

$state — 只在需要时声明

只把会触发更新($effect / $derived / 模板)的值声明为 $state。大型只重赋值对象(API 响应)用 $state.raw 避免 Proxy 开销:

let user = $state.raw<User | null>(null);
$derived > $effect 用于纯计算
let square = $derived(num * num); // 好
// let square; $effect(() => { square = num * num; }); // 差

复杂逻辑用 $derived.by(() => { ... })。Derived 可写;对象/数组结果不会被深层代理。

$effect 是 escape hatch

优先工具:同步外部库 → {@attach ...};响应用户输入 → 处理器;调试日志 → $inspect / $inspect.trace;观察外部源 → createSubscriber。永远不要 if (browser) { ... } 包 effect——effect 本就不在服务端运行。

Props 当作会变化、事件用属性语法
let { type } = $props();
let color = $derived(type === 'danger' ? 'red' : 'green');

<svelte:window> / <svelte:document> 用于全局监听;不要 onMount 手动绑。Snippets 替代 Slots,{#each ... (item.id)} 用稳定 key(不可用 index)。style:-- 把 JS 变量透到 CSS 自定义属性;用 CSS 变量(而非 :global)穿透子组件样式;用 createContext 替代模块级共享状态(提供类型安全 + 防止 SSR 用户间泄漏)。

新代码避免 Legacy

on:click → onclick;export let → $props();$: → $derived / $effect;<slot> → snippet;use:action → {@attach ...}。


Critical: Svelte 4 Migration Guide

最小版本
依赖要求
Node16+
SvelteKit1.20.4+(如使用)
vite-plugin-svelte2.4.1+
TypeScript5+
核心迁移对照
Svelte 4Svelte 5
let x = 0(顶层响应式)let x = $state(0)
$: x = a + blet x = $derived(a + b)
$: { ... }$effect(() => { ... })
export let proplet { prop } = $props()
<slot />{@render children()}
createEventDispatchercallback props
on:click={fn}onclick={fn}
自动迁移工具
npx svelte-migrate@latest svelte-5 my-project
重要行为变化
  • 转换默认 local(外层控制流不影响子 transition)。
  • 默认插槽绑定不会进入具名插槽。
  • 预处理器顺序:markup → script → style(按声明顺序逐个执行)。
  • createEventDispatcher 严格模式下检查可选 / 必传 / 无参类型(之后用 callback props 替代)。
  • Action / ActionReturn 默认参数类型为 undefined,需要参数时显式声明。
  • SvelteComponentTyped 已弃用,统一用 SvelteComponent。
  • CJS 输出与 svelte/register 被移除。
  • 删除 svelte.JSX,改用 svelteHTML / svelte/elements。
  • 打包器必须指定 browser 条件(SvelteKit / Vite 自动;Rollup 用 @rollup/plugin-node-resolve 设 browser: true;Webpack 在 conditionNames 加 "browser")。

Critical: Svelte 5 Migration Guide (Concept Summary)

Runes 系统:$state / $derived / $effect 替代隐式响应式;Snippets 替代 Slots;事件属性替代 on:;$effect 显式追踪依赖;$state 对对象/数组做深层 Proxy。

移除替代
let 顶层隐式响应式$state
$: 语句$derived / $effect
export let / $$props / $$restProps$props()
createEventDispatchercallback props / $bindable
SlotsSnippets
on:eventonevent
beforeUpdate / afterUpdate$effect.pre / $effect

新增:$state.eager、$effect.pre、$effect.tracking、$state.snapshot、hydratable、fork()、{#key} 过渡触发、<svelte:boundary>、createContext。


FAQ

Q: Svelte 和 Vue/React 的核心区别? A: Svelte 无虚拟 DOM——编译时生成精确 DOM 更新代码,运行时零框架开销。

Q: Svelte 5 和 Svelte 4 可以共存吗? A: 可以。Svelte 5 仍支持 Legacy Mode,Svelte 4 的 $: 与 export let 可继续用;可在同一项目渐进迁移。

Q: 如何升级到 Svelte 5? A: ① 升级 svelte + sveltekit / vite-plugin-svelte;② 跑 npx svelte-migrate@latest svelte-5;③ 逐步迁到 Runes Mode。

Q: Svelte 支持 SSR / TypeScript 吗? A: 都原生支持。SSR 用 render() 或 SvelteKit;TS 直接用 <script lang="ts">,CI 跑 svelte-check。

Q: Svelte 有虚拟 DOM 吗? A: 没有。Svelte 编译器生成精确 DOM 操作代码(element.textContent = ...),而非通过 vDOM diffing。

Q: 哪些浏览器支持 Svelte 5? A: Baseline 2020(Chrome / Edge 87+、Firefox 83+、Safari 14+)。不支持 IE;少数功能需更高版本(见上表)。

Q: 自定义元素的样式如何控制? A: 默认 shadow root 模式 'open',全局 CSS 不会穿透。可用 shadow: 'none' 继承全局样式;用 CSS 变量穿透 scoped 样式。


Quick Fixes

问题解决方案
Svelte 4 代码报错确认组件未使用 $state(进入 Runes Mode)
$: 不生效升级到 Svelte 5,Legacy Mode 仍支持
TypeScript 报错确认 <script lang="ts"> 和 TypeScript 5+
迁移后打包变大检查 tree-shaking 配置
属性以 on 开头被监听重命名避免 on* 前缀
自定义元素 SSR 没内容预渲染不支持 shadow DOM;等 JS 加载
generic component 类型报错检查 generics 字符串(与函数泛型同语法)

Gotchas

  1. Svelte 5 自动进入 Runes Mode — 只要使用了任何 Rune($state 等)即为 Runes Mode。
  2. Legacy Mode — 可通过 <svelte:options runes={false}> 强制启用。
  3. on:click 已废弃 — Legacy Mode 仍可用,但会警告。
  4. createEventDispatcher 已弃用 — 新代码用 callback props。
  5. $bindable(default) — 仅在父组件未传 prop 时作 fallback;父组件传 undefined 会保留 undefined。
  6. bind:this 泛型组件 — 实例类型为 Component<Props> | null,需要断言。
  7. 自定义元素 inline CSS — 没有可被外部样式表链接的 .css 文件。
  8. 服务端 effect 不运行 — 不要用 if (browser) 包 effect 主体。

Examples

Practical examples for Svelte 5 features.

  • Dynamic Components: svelte:element and {#key} blocks
  • Debug and HTML: @html, @debug, @const
  • TypeScript:
    • TypeScript Basics — Typed props, generics, event handlers, component refs
    • TypeScript Advanced — 14 patterns: preprocessors, generic constraints, wrapper components, Component type, $state in classes, svelte/elements augmentation, svelte-check, $bindable, form state
  • Custom Elements: Custom Elements — 12 patterns: customElement option, $host(), type coercion, reflection, extend, ElementInternals, slot semantics
  • Best Practices: Svelte 5 Best Practices — 14 patterns: $state.raw, $derived.by, keyed each blocks, CSS variables, createContext, async Svelte, legacy replacements
  • Migration: Svelte 3→4 Migration — 10 patterns: tag → customElement, stricter types, transition scope, preprocessor order, CJS removal
  • Browser Support: Browser Support — 7 patterns: feature detection, polyfills, bundler target, SSR guards, $state.snapshot fallback, Playwright pinning

References

In-depth reference documentation.

  • Dynamic Components: Dynamic Components Reference — svelte:element, {#key}, {@html}, @debug, @const
  • TypeScript:
  • Custom Elements: Custom Elements — customElement surface, $host() rune, lifecycle, caveats, ElementInternals
  • Best Practices: Best Practices — $state / $derived / $effect, props, events, snippets, each blocks, CSS variables, context, async
  • Browser Support: Browser Support — Minimum versions matrix, feature exceptions, polyfills, SSR safety, bundler config
Quick Links
FeatureReference
svelte:elementDynamic Components
{#key}Dynamic Components
{@html} / @debug / @constDynamic Components
TS basicsTypeScript Basics
TS advancedTypeScript Advanced
Generic componentsTypeScript Advanced
Wrapper componentsTypeScript Advanced
Component typeTypeScript Advanced
DOM augmentationTypeScript Advanced
customElement optionsCustom Elements
$host() runeCustom Elements
Web Component lifecycleCustom Elements
$state / $derived / $effect patternsBest Practices
Async SvelteBest Practices
Browser matrixBrowser Support
Feature exceptionsBrowser Support
PolyfillsBrowser Support

Comments

Markdown supported