sv 0.16.6 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +1 -1
- package/dist/{engine-DbEL5s1q.mjs → engine-1Kj9XHT7.mjs} +1396 -2854
- package/dist/{engine-BhR6Vrxy.d.mts → engine-5Sg3lJiQ.d.mts} +1 -1
- package/dist/shared.json +96 -0
- package/dist/src/index.d.mts +1 -1
- package/dist/src/index.mjs +1 -1
- package/dist/src/testing.d.mts +3 -3
- package/dist/src/testing.mjs +1 -1
- package/dist/templates/addon/package.json +3 -3
- package/package.json +5 -6
package/dist/shared.json
CHANGED
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
"exclude": [],
|
|
23
23
|
"contents": "# [sv](https://svelte.dev/docs/cli/overview) community add-on: [~SV-NAME-TODO~](https://github.com/~SV-NAME-TODO~)\n\n> [!IMPORTANT]\n> Svelte maintainers have not reviewed community add-ons for malicious code! Use at your discretion.\n\n## Usage\n\nTo install the add-on, run:\n\n```shell\nnpx sv add ~SV-PROTOCOL-NAME-TODO~\n```\n\n## What you get [TO BE FILLED...]\n\n- A super cool stuff\n- Another one!\n\n## Options [TO BE FILLED...]\n\n### `who`\n\nThe name of the person to say hello to.\n\nDefault: `you`\n\n```shell\nnpx sv add ~SV-PROTOCOL-NAME-TODO~=\"who:your-name\"\n```\n"
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
"name": "svelte-file-editor.md",
|
|
27
|
+
"include": [
|
|
28
|
+
"agents"
|
|
29
|
+
],
|
|
30
|
+
"exclude": [],
|
|
31
|
+
"contents": "---\nname: svelte-file-editor\ndescription: Specialized Svelte 5 code editor. MUST BE USED PROACTIVELY when creating, editing, or reviewing any .svelte file or .svelte.ts/.svelte.js module and MUST use the tools from the MCP server or the `svelte-file-editor` skill if they are available. Fetches relevant documentation and validates code using the Svelte MCP server tools.\n---\n\nYou are a Svelte 5 expert responsible for writing, editing, and validating Svelte components and modules. You have access to the Svelte MCP server which provides documentation and code analysis tools. Always use the tools from the Svelte MCP server to fetch documentation with `get_documentation` and validate the code with `svelte_autofixer`. If the autofixer returns any issue or suggestions try to solve them.\n\nIf the MCP tools are not available you can use the `svelte-code-writer` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.\n\nIf the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.\n\n## Available MCP tools\n\n### 1. list-sections\n\nLists all available Svelte 5 and SvelteKit documentation sections with titles and paths. Use this first to discover what documentation is available.\n\n### 2. get-documentation\n\nRetrieves full documentation for specified sections. Accepts a single section name or an array of section names. Use after `list-sections` to fetch relevant docs for the task at hand.\n\n**Example sections:** `$state`, `$derived`, `$effect`, `$props`, `$bindable`, `snippets`, `routing`, `load functions`\n\n### 3. svelte-autofixer\n\nAnalyzes Svelte code and returns suggestions to fix issues. Pass the component code directly to this tool. It will detect common mistakes like:\n\n- Using `$effect` instead of `$derived` for computations\n- Missing cleanup in effects\n- Svelte 4 syntax (`on:click`, `export let`, `<slot>`)\n- Missing keys in `{#each}` blocks\n- And more\n\n## Workflow\n\nWhen invoked to work on a Svelte file:\n\n### 1. Gather context (if needed)\n\nIf you're uncertain about Svelte 5 syntax or patterns, use the MCP tools:\n\n1. Call `list-sections` to see available documentation\n2. Call `get-documentation` with relevant section names\n\n### 2. Read the target file\n\nRead the file to understand the current implementation.\n\n### 3. Make changes\n\nApply edits following Svelte 5 best practices:\n\n### 4. Validate changes\n\nAfter editing, ALWAYS call `svelte-autofixer` with the updated code to check for issues.\n\n### 5. Fix any issues\n\nIf the autofixer reports problems, fix them and re-validate until no issues remain.\n\n## Output format\n\nAfter completing your work, provide:\n\n1. Summary of changes made\n2. Any issues found and fixed by the autofixer\n3. Recommendations for further improvements (if any)\n"
|
|
32
|
+
},
|
|
25
33
|
{
|
|
26
34
|
"name": "jsconfig.json",
|
|
27
35
|
"include": [
|
|
@@ -70,6 +78,94 @@
|
|
|
70
78
|
"exclude": [],
|
|
71
79
|
"contents": "<script lang=\"ts\">\n\timport favicon from '$lib/assets/favicon.svg';\n\n\tlet { children } = $props();\n\n\tconst title = '$sv-title-$sv';\n\tconst href = '$sv-url-$sv';\n\n\tlet prefersDark = $state(true);\n\tlet isDark = $state(true);\n\n\tfunction switchTheme() {\n\t\tconst value = isDark ? 'light' : 'dark';\n\n\t\tisDark = value === 'dark';\n\t\tlocalStorage.setItem('sv:theme', isDark === prefersDark ? 'system' : value);\n\t}\n\n\t$effect(() => {\n\t\tdocument.documentElement.classList.remove('light', 'dark');\n\t\tprefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n\n\t\tconst theme = localStorage.getItem('sv:theme');\n\n\t\tisDark = !theme ? prefersDark : theme === 'dark' || (theme === 'system' && prefersDark);\n\t\tdocument.documentElement.classList.add(isDark ? 'dark' : 'light');\n\t});\n</script>\n\n<svelte:head>\n\t<title>--from-playground {title}</title>\n\t<script>\n\t\t{\n\t\t\tconst theme = localStorage.getItem('sv:theme');\n\n\t\t\tdocument.documentElement.classList.add(\n\t\t\t\t!theme || theme === 'system'\n\t\t\t\t\t? window.matchMedia('(prefers-color-scheme: dark)').matches\n\t\t\t\t\t\t? 'dark'\n\t\t\t\t\t\t: 'light'\n\t\t\t\t\t: theme\n\t\t\t);\n\t\t}\n\t</script>\n</svelte:head>\n\n<div class=\"layout\">\n\t<nav class=\"navbar\">\n\t\t<div class=\"nav-left\">\n\t\t\t<a href=\"/\" class=\"svelte-icon\">\n\t\t\t\t<img src={favicon} alt=\"Svelte\" width=\"32\" height=\"32\" />\n\t\t\t</a>\n\t\t\t<p class=\"title\">{title}</p>\n\t\t</div>\n\t\t<div class=\"nav-right\">\n\t\t\t<a {href} class=\"raised\" target=\"_blank\" rel=\"noopener noreferrer\">\n\t\t\t\t--to-playground\n\t\t\t\t<span aria-hidden=\"true\" style=\"margin-left:0.25em;\"> ↗</span>\n\t\t\t</a>\n\t\t\t<button class=\"raised theme-toggle\" onclick={switchTheme} aria-label=\"Toggle theme\">\n\t\t\t\t<span class=\"icon\"></span>\n\t\t\t</button>\n\t\t</div>\n\t</nav>\n\n\t<main class=\"content\">\n\t\t{@render children()}\n\t</main>\n</div>\n\n<style>\n\t:global(body) {\n\t\tmargin: 0;\n\t}\n\n\t:global(html) {\n\t\tmargin: 0;\n\t\t--bg-1: hsl(0, 0%, 100%);\n\t\t--bg-2: hsl(206, 20%, 90%);\n\t\t--bg-3: hsl(206, 20%, 80%);\n\t\t--navbar-bg: #fff;\n\t\t--fg-1: hsl(0, 0%, 13%);\n\t\t--fg-2: hsl(0, 0%, 50%);\n\t\t--fg-3: hsl(0, 0%, 60%);\n\t\t--link: hsl(208, 77%, 47%);\n\t\t--border-radius: 4px;\n\t\t--font:\n\t\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',\n\t\t\t'Helvetica Neue', sans-serif;\n\t\tcolor-scheme: light;\n\t\tbackground: var(--bg-1);\n\t\tcolor: var(--fg-1);\n\t\tfont-family: var(--font);\n\t\tline-height: 1.5;\n\t\theight: calc(100vh - 2rem);\n\t\taccent-color: var(--link) !important;\n\t\tmin-height: 100vh;\n\t\tbackground-color: var(--bg-1);\n\t}\n\n\t:global(html.dark) {\n\t\tcolor-scheme: dark;\n\t\t--bg-1: hsl(0, 0%, 18%);\n\t\t--bg-2: hsl(0, 0%, 30%);\n\t\t--bg-3: hsl(0, 0%, 40%);\n\t\t--navbar-bg: hsl(220, 14%, 16%);\n\t\t--fg-1: hsl(0, 0%, 75%);\n\t\t--fg-2: hsl(0, 0%, 40%);\n\t\t--fg-3: hsl(0, 0%, 30%);\n\t\t--link: hsl(206, 96%, 72%);\n\t}\n\n\t.navbar {\n\t\tcolor: var(--fg-1);\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t\talign-items: center;\n\t\tpadding: 0em 2.5rem;\n\t\theight: 3.7rem;\n\t\tbackground-color: var(--navbar-bg);\n\t\tbox-shadow:\n\t\t\t0 2px 8px 0 rgba(0, 0, 0, 0.08),\n\t\t\t0 1.5px 4px 0 rgba(0, 0, 0, 0.04);\n\t}\n\n\t.nav-left {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 0.5rem;\n\t}\n\n\t.svelte-icon {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\ttext-decoration: none;\n\t\ttransition: opacity 0.2s ease;\n\t}\n\n\t.svelte-icon:hover {\n\t\topacity: 0.8;\n\t}\n\n\t.title {\n\t\tfont-size: 1.5rem;\n\t\tfont-weight: 400;\n\t\tmargin: 0;\n\t}\n\n\t.nav-right {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 1rem;\n\t}\n\n\t.raised {\n\t\tbackground: var(--navbar-bg);\n\t\tborder-left: 0.5px solid var(--fg-3);\n\t\tborder-top: 0.5px solid var(--fg-3);\n\t\tborder-bottom: none;\n\t\tborder-right: none;\n\t\tborder-radius: var(--border-radius);\n\t\tcolor: var(--fg-1);\n\t\tcursor: pointer;\n\t\ttransition: all 0.2s ease;\n\t\tbox-shadow:\n\t\t\t0 2px 4px rgba(0, 0, 0, 0.1),\n\t\t\t0 1px 2px rgba(0, 0, 0, 0.06);\n\t\ttext-decoration: none;\n\t\tfont-weight: 500;\n\t\tpadding: 0.25rem 0.75rem;\n\t\tfont-size: 0.8rem;\n\t}\n\n\t.raised:hover {\n\t\tborder-left-color: var(--fg-2);\n\t\tborder-top-color: var(--fg-2);\n\t\tbox-shadow:\n\t\t\t0 4px 8px rgba(0, 0, 0, 0.15),\n\t\t\t0 2px 4px rgba(0, 0, 0, 0.1);\n\t\ttransform: translate(-1px, -1px);\n\t}\n\n\t.content {\n\t\tpadding: 1rem;\n\t\tcolor: var(--fg-1);\n\t}\n\n\t.theme-toggle {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 1.8rem;\n\t\theight: 1.8rem;\n\t\tpadding: 0;\n\t\tmin-width: 2rem;\n\t}\n\n\t.icon {\n\t\tdisplay: inline-block;\n\t\twidth: 1.5rem;\n\t\theight: 1.5rem;\n\t\t-webkit-mask-size: 1.5rem;\n\t\tmask-size: 1.5rem;\n\t\t-webkit-mask-repeat: no-repeat;\n\t\tmask-repeat: no-repeat;\n\t\t-webkit-mask-position: center;\n\t\tmask-position: center;\n\t\tbackground-color: var(--fg-1);\n\t}\n\n\t.icon {\n\t\tmask-image: url('data:image/svg+xml,%3csvg%20xmlns=\"http://www.w3.org/2000/svg\"%20viewBox=\"0%200%2024%2024\"%3e%3cpath%20fill=\"%23666\"%20d=\"M12%2021q-3.775%200-6.388-2.613T3%2012q0-3.45%202.25-5.988T11%203.05q.625-.075.975.45t-.025%201.1q-.425.65-.638%201.375T11.1%207.5q0%202.25%201.575%203.825T16.5%2012.9q.775%200%201.538-.225t1.362-.625q.525-.35%201.075-.037t.475.987q-.35%203.45-2.937%205.725T12%2021Zm0-2q2.2%200%203.95-1.213t2.55-3.162q-.5.125-1%20.2t-1%20.075q-3.075%200-5.238-2.163T9.1%207.5q0-.5.075-1t.2-1q-1.95.8-3.163%202.55T5%2012q0%202.9%202.05%204.95T12%2019Zm-.25-6.75Z\"/%3e%3c/svg%3e');\n\t}\n\n\t:global(html.dark) .icon {\n\t\tmask-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3e%3cpath%20fill='%23d4d4d4'%20d='M12%2019a1%201%200%200%201%20.993.883L13%2020v1a1%201%200%200%201-1.993.117L11%2021v-1a1%201%200%200%201%201-1zm6.313-2.09.094.083.7.7a1%201%200%200%201-1.32%201.497l-.094-.083-.7-.7a1%201%200%200%201%201.218-1.567l.102.07zm-11.306.083a1%201%200%200%201%20.083%201.32l-.083.094-.7.7a1%201%200%200%201-1.497-1.32l.083-.094.7-.7a1%201%200%200%201%201.414%200zM4%2011a1%201%200%200%201%20.117%201.993L4%2013H3a1%201%200%200%201-.117-1.993L3%2011h1zm17%200a1%201%200%200%201%20.117%201.993L21%2013h-1a1%201%200%200%201-.117-1.993L20%2011h1zM6.213%204.81l.094.083.7.7a1%201%200%200%201-1.32%201.497l-.094-.083-.7-.7A1%201%200%200%201%206.11%204.74l.102.07zm12.894.083a1%201%200%200%201%20.083%201.32l-.083.094-.7.7a1%201%200%200%201-1.497-1.32l.083-.094.7-.7a1%201%200%200%201%201.414%200zM12%202a1%201%200%200%201%20.993.883L13%203v1a1%201%200%200%201-1.993.117L11%204V3a1%201%200%200%201%201-1zm0%205a5%205%200%201%201-4.995%205.217L7%2012l.005-.217A5%205%200%200%201%2012%207z'/%3e%3c/svg%3e\");\n\t}\n</style>\n"
|
|
72
80
|
},
|
|
81
|
+
{
|
|
82
|
+
"name": "svelte-code-writer/SKILL.md",
|
|
83
|
+
"include": [
|
|
84
|
+
"skills"
|
|
85
|
+
],
|
|
86
|
+
"exclude": [],
|
|
87
|
+
"contents": "---\nname: svelte-code-writer\ndescription: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.\n---\n\n## CLI tools\n\nYou have access to `@sveltejs/mcp` CLI for Svelte-specific assistance. Use these commands via `npx`:\n\n### List documentation sections\n\n```bash\nnpx @sveltejs/mcp list-sections\n```\n\nLists all available Svelte 5 and SvelteKit documentation sections with titles and paths.\n\n### Get documentation\n\n```bash\nnpx @sveltejs/mcp get-documentation \"<section1>,<section2>,...\"\n```\n\nRetrieves full documentation for specified sections. Use after `list-sections` to fetch relevant docs.\n\n**Example:**\n\n```bash\nnpx @sveltejs/mcp get-documentation \"$state,$derived,$effect\"\n```\n\n### Svelte autofixer\n\n```bash\nnpx @sveltejs/mcp svelte-autofixer \"<code_or_path>\" [options]\n```\n\nAnalyzes Svelte code and suggests fixes for common issues.\n\n**Options:**\n\n- `--async` - Enable async Svelte mode (default: false)\n- `--svelte-version` - Target version: 4 or 5 (default: 5)\n\n**Examples:**\n\n```bash\n# Analyze inline code (escape $ as \\$)\nnpx @sveltejs/mcp svelte-autofixer '<script>let count = \\$state(0);</script>'\n\n# Analyze a file\nnpx @sveltejs/mcp svelte-autofixer ./src/lib/Component.svelte\n\n# Target Svelte 4\nnpx @sveltejs/mcp svelte-autofixer ./Component.svelte --svelte-version 4\n```\n\n**Important:** When passing code with runes (`$state`, `$derived`, etc.) via the terminal, escape the `$` character as `\\$` to prevent shell variable substitution.\n\n## Workflow\n\n1. **Uncertain about syntax?** Run `list-sections` then `get-documentation` for relevant topics\n2. **Reviewing/debugging?** Run `svelte-autofixer` on the code to detect issues\n3. **Always validate** - Run `svelte-autofixer` before finalizing any Svelte component\n"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "svelte-core-bestpractices/SKILL.md",
|
|
91
|
+
"include": [
|
|
92
|
+
"skills"
|
|
93
|
+
],
|
|
94
|
+
"exclude": [],
|
|
95
|
+
"contents": "---\nname: svelte-core-bestpractices\ndescription: Guidance on writing fast, robust, modern Svelte code. Load this skill whenever in a Svelte project and asked to write/edit or analyze a Svelte component or module. Covers reactivity, event handling, styling, integration with libraries and more.\n---\n\n## `$state`\n\nOnly use the `$state` rune for variables that should be _reactive_ — in other words, variables that cause an `$effect`, `$derived` or template expression to update. Everything else can be a normal variable.\n\nObjects and arrays (`$state({...})` or `$state([...])`) are made deeply reactive, meaning mutation will trigger updates. This has a trade-off: in exchange for fine-grained reactivity, the objects must be proxied, which has performance overhead. In cases where you're dealing with large objects that are only ever reassigned (rather than mutated), use `$state.raw` instead. This is often the case with API responses, for example.\n\n## `$derived`\n\nTo compute something from state, use `$derived` rather than `$effect`:\n\n```js\n// do this\nlet square = $derived(num * num);\n\n// don't do this\nlet square;\n\n$effect(() => {\n\tsquare = num * num;\n});\n```\n\n> [!NOTE] `$derived` is given an expression, _not_ a function. If you need to use a function (because the expression is complex, for example) use `$derived.by`.\n\nDeriveds are writable — you can assign to them, just like `$state`, except that they will re-evaluate when their expression changes.\n\nIf the derived expression is an object or array, it will be returned as-is — it is _not_ made deeply reactive. You can, however, use `$state` inside `$derived.by` in the rare cases that you need this.\n\n## `$effect`\n\nEffects are an escape hatch and should mostly be avoided. In particular, avoid updating state inside effects.\n\n- If you need to sync state to an external library such as D3, it is often neater to use [`{@attach ...}`](references/attach.md)\n- If you need to run some code in response to user interaction, put the code directly in an event handler or use a [function binding](references/bind.md) as appropriate\n- If you need to log values for debugging purposes, use [`$inspect`](references/inspect.md)\n- If you need to observe something external to Svelte, use [`createSubscriber`](references/svelte-reactivity.md)\n\nNever wrap the contents of an effect in `if (browser) {...}` or similar — effects do not run on the server.\n\n## `$props`\n\nTreat props as though they will change. For example, values that depend on props should usually use `$derived`:\n\n```js\n// @errors: 2451\nlet { type } = $props();\n\n// do this\nlet color = $derived(type === 'danger' ? 'red' : 'green');\n\n// don't do this — `color` will not update if `type` changes\nlet color = type === 'danger' ? 'red' : 'green';\n```\n\n## `$inspect.trace`\n\n`$inspect.trace` is a debugging tool for reactivity. If something is not updating properly or running more than it should you can add `$inspect.trace(label)` as the first line of an `$effect` or `$derived.by` (or any function they call) to trace their dependencies and discover which one triggered an update.\n\n## Events\n\nAny element attribute starting with `on` is treated as an event listener:\n\n```svelte\n<button onclick={() => {...}}>click me</button>\n\n<!-- attribute shorthand also works -->\n<button {onclick}>...</button>\n\n<!-- so do spread attributes -->\n<button {...props}>...</button>\n```\n\nIf you need to attach listeners to `window` or `document` you can use `<svelte:window>` and `<svelte:document>`:\n\n```svelte\n<svelte:window onkeydown={...} />\n<svelte:document onvisibilitychange={...} />\n```\n\nAvoid using `onMount` or `$effect` for this.\n\n## Snippets\n\n[Snippets](references/snippet.md) are a way to define reusable chunks of markup that can be instantiated with the [`{@render ...}`](references/render.md) tag, or passed to components as props. They must be declared within the template.\n\n```svelte\n{#snippet greeting(name)}\n\t<p>hello {name}!</p>\n{/snippet}\n\n{@render greeting('world')}\n```\n\n> [!NOTE] Snippets declared at the top level of a component (i.e. not inside elements or blocks) can be referenced inside `<script>`. A snippet that doesn't reference component state is also available in a `<script module>`, in which case it can be exported for use by other components.\n\n## Each blocks\n\nPrefer to use [keyed each blocks](references/each.md) — this improves performance by allowing Svelte to surgically insert or remove items rather than updating the DOM belonging to existing items.\n\n> [!NOTE] The key _must_ uniquely identify the object. Do not use the index as a key.\n\nAvoid destructuring if you need to mutate the item (with something like `bind:value={item.count}`, for example).\n\n## Using JavaScript variables in CSS\n\nIf you have a JS variable that you want to use inside CSS you can set a CSS custom property with the `style:` directive.\n\n```svelte\n<div style:--columns={columns}>...</div>\n```\n\nYou can then reference `var(--columns)` inside the component's `<style>`.\n\n## Styling child components\n\nThe CSS in a component's `<style>` is scoped to that component. If a parent component needs to control the child's styles, the preferred way is to use CSS custom properties:\n\n```svelte\n<!-- Parent.svelte -->\n<Child --color=\"red\" />\n\n<!-- Child.svelte -->\n<h1>Hello</h1>\n\n<style>\n\th1 {\n\t\tcolor: var(--color);\n\t}\n</style>\n```\n\nIf this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:\n\n```svelte\n<div>\n\t<Child />\n</div>\n\n<style>\n\tdiv :global {\n\t\th1 {\n\t\t\tcolor: red;\n\t\t}\n\t}\n</style>\n```\n\n## Context\n\nConsider using context instead of declaring state in a shared module. This will scope the state to the part of the app that needs it, and eliminate the possibility of it leaking between users when server-side rendering.\n\nUse `createContext` rather than `setContext` and `getContext`, as it provides type safety.\n\n## Async Svelte\n\nIf using version 5.36 or higher, you can use [await expressions](references/await-expressions.md) and [hydratable](references/hydratable.md) to use promises directly inside components. Note that these require the `experimental.async` option to be enabled in `svelte.config.js` as they are not yet considered fully stable.\n\n## Avoid legacy features\n\nAlways use runes mode for new code, and avoid features that have more modern replacements:\n\n- use `$state` instead of implicit reactivity (e.g. `let count = 0; count += 1`)\n- use `$derived` and `$effect` instead of `$:` assignments and statements (but only use effects when there is no better solution)\n- use `$props` instead of `export let`, `$$props` and `$$restProps`\n- use `onclick={...}` instead of `on:click={...}`\n- use `{#snippet ...}` and `{@render ...}` instead of `<slot>` and `$$slots` and `<svelte:fragment>`\n- use `<DynamicComponent>` instead of `<svelte:component this={DynamicComponent}>`\n- use `import Self from './ThisComponent.svelte'` and `<Self>` instead of `<svelte:self>`\n- use classes with `$state` fields to share reactivity between components, instead of using stores\n- use `{@attach ...}` instead of `use:action`\n- use clsx-style arrays and objects in `class` attributes, instead of the `class:` directive\n"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "svelte-core-bestpractices/references/attach.md",
|
|
99
|
+
"include": [
|
|
100
|
+
"skills"
|
|
101
|
+
],
|
|
102
|
+
"exclude": [],
|
|
103
|
+
"contents": "Attachments are functions that run in an [effect](https://svelte.dev/docs/svelte/$effect/llms.txt) when an element is mounted to the DOM or when [state](https://svelte.dev/docs/svelte/$state/llms.txt) read inside the function updates.\n\nOptionally, they can return a function that is called before the attachment re-runs, or after the element is later removed from the DOM.\n\n> [!NOTE]\n> Attachments are available in Svelte 5.29 and newer.\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\t/** @type {import('svelte/attachments').Attachment} */\n\tfunction myAttachment(element) {\n\t\tconsole.log(element.nodeName); // 'DIV'\n\n\t\treturn () => {\n\t\t\tconsole.log('cleaning up');\n\t\t};\n\t}\n</script>\n\n<div {@attach myAttachment}>...</div>\n```\n\nAn element can have any number of attachments.\n\n## Attachment factories\n\nA useful pattern is for a function, such as `tooltip` in this example, to _return_ an attachment (demo:\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport tippy from 'tippy.js';\n\n\tlet content = $state('Hello!');\n\n\t/**\n\t * @param {string} content\n\t * @returns {import('svelte/attachments').Attachment}\n\t */\n\tfunction tooltip(content) {\n\t\treturn (element) => {\n\t\t\tconst tooltip = tippy(element, { content });\n\t\t\treturn tooltip.destroy;\n\t\t};\n\t}\n</script>\n\n<input bind:value={content} />\n\n<button {@attach tooltip(content)}>\n\tHover me\n</button>\n```\n\nSince the `tooltip(content)` expression runs inside an [effect](https://svelte.dev/docs/svelte/$effect/llms.txt), the attachment will be destroyed and recreated whenever `content` changes. The same thing would happen for any state read _inside_ the attachment function when it first runs. (If this isn't what you want, see [Controlling when attachments re-run](#Controlling-when-attachments-re-run).)\n\n## Inline attachments\n\nAttachments can also be created inline (demo:\n\n```svelte\n<!--- file: App.svelte --->\n<canvas\n\twidth={32}\n\theight={32}\n\t{@attach (canvas) => {\n\t\tconst context = canvas.getContext('2d');\n\n\t\t$effect(() => {\n\t\t\tcontext.fillStyle = color;\n\t\t\tcontext.fillRect(0, 0, canvas.width, canvas.height);\n\t\t});\n\t}}\n></canvas>\n```\n\n> [!NOTE]\n> The nested effect runs whenever `color` changes, while the outer effect (where `canvas.getContext(...)` is called) only runs once, since it doesn't read any reactive state.\n\n## Conditional attachments\n\nFalsy values like `false` or `undefined` are treated as no attachment, enabling conditional usage:\n\n```svelte\n<div {@attach enabled && myAttachment}>...</div>\n```\n\n## Passing attachments to components\n\nWhen used on a component, `{@attach ...}` will create a prop whose key is a [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol). If the component then [spreads](https://svelte.dev/tutorial/svelte/spread-props/llms.txt) props onto an element, the element will receive those attachments.\n\nThis allows you to create _wrapper components_ that augment elements (demo:\n\n```svelte\n<!--- file: Button.svelte --->\n<script>\n\t/** @type {import('svelte/elements').HTMLButtonAttributes} */\n\tlet { children, ...props } = $props();\n</script>\n\n<!-- `props` includes attachments -->\n<button {...props}>\n\t{@render children?.()}\n</button>\n```\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport tippy from 'tippy.js';\n\timport Button from './Button.svelte';\n\n\tlet content = $state('Hello!');\n\n\t/**\n\t * @param {string} content\n\t * @returns {import('svelte/attachments').Attachment}\n\t */\n\tfunction tooltip(content) {\n\t\treturn (element) => {\n\t\t\tconst tooltip = tippy(element, { content });\n\t\t\treturn tooltip.destroy;\n\t\t};\n\t}\n</script>\n\n<input bind:value={content} />\n\n<Button {@attach tooltip(content)}>\n\tHover me\n</Button>\n```\n\n## Controlling when attachments re-run\n\nAttachments, unlike [actions](https://svelte.dev/docs/svelte/use/llms.txt), are fully reactive: `{@attach foo(bar)}` will re-run on changes to `foo` _or_ `bar` (or any state read inside `foo`):\n\n```js\n// @errors: 7006 2304 2552\nfunction foo(bar) {\n\treturn (node) => {\n\t\tveryExpensiveSetupWork(node);\n\t\tupdate(node, bar);\n\t};\n}\n```\n\nIn the rare case that this is a problem (for example, if `foo` does expensive and unavoidable setup work) consider passing the data inside a function and reading it in a child effect:\n\n```js\n// @errors: 7006 2304 2552\nfunction foo(+++getBar+++) {\n\treturn (node) => {\n\t\tveryExpensiveSetupWork(node);\n\n+++\t\t$effect(() => {\n\t\t\tupdate(node, getBar());\n\t\t});+++\n\t}\n}\n```\n\n## Creating attachments programmatically\n\nTo add attachments to an object that will be spread onto a component or element, use [`createAttachmentKey`](https://svelte.dev/docs/svelte/svelte-attachments/llms.txt#createAttachmentKey).\n\n## Converting actions to attachments\n\nIf you're using a library that only provides actions, you can convert them to attachments with [`fromAction`](https://svelte.dev/docs/svelte/svelte-attachments/llms.txt#fromAction), allowing you to (for example) use them with components.\n"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "svelte-core-bestpractices/references/await-expressions.md",
|
|
107
|
+
"include": [
|
|
108
|
+
"skills"
|
|
109
|
+
],
|
|
110
|
+
"exclude": [],
|
|
111
|
+
"contents": "As of Svelte 5.36, you can use the `await` keyword inside your components in three places where it was previously unavailable:\n\n- at the top level of your component's `<script>`\n- inside `$derived(...)` declarations\n- inside your markup\n\nThis feature is currently experimental, and you must opt in by adding the `experimental.async` option wherever you [configure](https://svelte.dev/docs/kit/configuration/llms.txt) Svelte, usually `svelte.config.js`:\n\n```js\n/// file: svelte.config.js\nexport default {\n\tcompilerOptions: {\n\t\texperimental: {\n\t\t\tasync: true\n\t\t}\n\t}\n};\n```\n\nThe experimental flag will be removed in Svelte 6.\n\n## Synchronized updates\n\nWhen an `await` expression depends on a particular piece of state, changes to that state will not be reflected in the UI until the asynchronous work has completed, so that the UI is not left in an inconsistent state. In other words, in an example like this...\n\n<!-- codeblock:start {\"title\":\"Synchronized updates\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\tlet a = $state(1);\n\tlet b = $state(2);\n\n\tasync function add(a, b) {\n\t\tawait new Promise((f) => setTimeout(f, 500)); // artificial delay\n\t\treturn a + b;\n\t}\n</script>\n\n<input type=\"number\" bind:value={a}>\n<input type=\"number\" bind:value={b}>\n\n<p>{a} + {b} = {await add(a, b)}</p>\n```\n\n<!-- codeblock:end -->\n\n...if you increment `a`, the contents of the `<p>` will _not_ immediately update to read this —\n\n```html\n<p>2 + 2 = 3</p>\n```\n\n— instead, the text will update to `2 + 2 = 4` when `add(a, b)` resolves.\n\nUpdates can overlap — a fast update will be reflected in the UI while an earlier slow update is still ongoing.\n\n## Concurrency\n\nSvelte will do as much asynchronous work as it can in parallel. For example if you have two `await` expressions in your markup...\n\n```svelte\n<p>{await one(x)}</p>\n<p>{await two(y)}</p>\n```\n\n...both functions will run at the same time, as they are independent expressions, even though they are _visually_ sequential.\n\nThis does not apply to sequential `await` expressions inside your `<script>` or inside async functions — these run like any other asynchronous JavaScript. An exception is that independent `$derived` expressions will update independently, even though they will run sequentially when they are first created:\n\n```js\n// `b` will not be created until `a` has resolved,\n// but once created they will update independently\n// even if `x` and `y` update simultaneously\nlet a = $derived(await one(x));\nlet b = $derived(await two(y));\n```\n\n> [!NOTE] If you write code like this, expect Svelte to give you an [`await_waterfall`](https://svelte.dev/docs/svelte/runtime-warnings/llms.txt#Client-warnings-await_waterfall) warning\n\n## Indicating loading states\n\nTo render placeholder UI, you can wrap content in a `<svelte:boundary>` with a [`pending`](https://svelte.dev/docs/svelte/svelte-boundary/llms.txt#Properties-pending) snippet. This will be shown when the boundary is first created, but not for subsequent updates, which are globally coordinated.\n\nAfter the contents of a boundary have resolved for the first time and have replaced the `pending` snippet, you can detect subsequent async work with [`$effect.pending()`](https://svelte.dev/docs/svelte/$effect/llms.txt#$effect.pending). This is what you would use to display a \"we're asynchronously validating your input\" spinner next to a form field, for example.\n\nYou can also use [`settled()`](https://svelte.dev/docs/svelte/svelte/llms.txt#settled) to get a promise that resolves when the current update is complete:\n\n```js\nimport { tick, settled } from 'svelte';\n\nasync function onclick() {\n\tupdating = true;\n\n\t// without this, the change to `updating` will be\n\t// grouped with the other changes, meaning it\n\t// won't be reflected in the UI\n\tawait tick();\n\n\tcolor = 'octarine';\n\tanswer = 42;\n\n\tawait settled();\n\n\t// any updates affected by `color` or `answer`\n\t// have now been applied\n\tupdating = false;\n}\n```\n\n## Error handling\n\nErrors in `await` expressions will bubble to the nearest [error boundary](https://svelte.dev/docs/svelte/svelte-boundary/llms.txt).\n\n## Server-side rendering\n\nSvelte supports asynchronous server-side rendering (SSR) with the `render(...)` API. To use it, simply await the return value:\n\n```js\n/// file: server.js\nimport { render } from 'svelte/server';\nimport App from './App.svelte';\n\nconst { head, body } = +++await+++ render(App);\n```\n\n> [!NOTE] If you're using a framework like SvelteKit, this is done on your behalf.\n\nIf a `<svelte:boundary>` with a `pending` snippet is encountered during SSR, that snippet will be rendered while the rest of the content is ignored. All `await` expressions encountered outside boundaries with `pending` snippets will resolve and render their contents prior to `await render(...)` returning.\n\n> [!NOTE] In the future, we plan to add a streaming implementation that renders the content in the background.\n\n## Forking\n\nThe [`fork(...)`](https://svelte.dev/docs/svelte/svelte/llms.txt#fork) API, added in 5.42, makes it possible to run `await` expressions that you _expect_ to happen in the near future. This is mainly intended for frameworks like SvelteKit to implement preloading when (for example) users signal an intent to navigate.\n\n```svelte\n<script>\n\timport { fork } from 'svelte';\n\timport Menu from './Menu.svelte';\n\n\tlet open = $state(false);\n\n\t/** @type {import('svelte').Fork | null} */\n\tlet pending = null;\n\n\tfunction preload() {\n\t\tpending ??= fork(() => {\n\t\t\topen = true;\n\t\t});\n\t}\n\n\tfunction discard() {\n\t\tpending?.discard();\n\t\tpending = null;\n\t}\n</script>\n\n<button\n\tonfocusin={preload}\n\tonfocusout={discard}\n\tonpointerenter={preload}\n\tonpointerleave={discard}\n\tonclick={() => {\n\t\tpending?.commit();\n\t\tpending = null;\n\n\t\t// in case `pending` didn't exist\n\t\t// (if it did, this is a no-op)\n\t\topen = true;\n\t}}\n>open menu</button>\n\n{#if open}\n\t<!-- any async work inside this component will start\n\t as soon as the fork is created -->\n\t<Menu onclose={() => open = false} />\n{/if}\n```\n\n## Caveats\n\nAs an experimental feature, the details of how `await` is handled (and related APIs like `$effect.pending()`) are subject to breaking changes outside of a semver major release, though we intend to keep such changes to a bare minimum.\n\n## Breaking changes\n\nEffects run in a slightly different order when the `experimental.async` option is `true`. Specifically, _block_ effects like `{#if ...}` and `{#each ...}` now run before an `$effect.pre` or `beforeUpdate` in the same component, which means that in very rare situations.\n"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "svelte-core-bestpractices/references/bind.md",
|
|
115
|
+
"include": [
|
|
116
|
+
"skills"
|
|
117
|
+
],
|
|
118
|
+
"exclude": [],
|
|
119
|
+
"contents": "## Function bindings\n\nYou can also use `bind:property={get, set}`, where `get` and `set` are functions, allowing you to perform validation and transformation:\n\n```svelte\n<input bind:value={\n\t() => value,\n\t(v) => value = v.toLowerCase()}\n/>\n```\n\nIn the case of readonly bindings like [dimension bindings](#Dimensions), the `get` value should be `null`:\n\n```svelte\n<div\n\tbind:clientWidth={null, redraw}\n\tbind:clientHeight={null, redraw}\n>...</div>\n```\n\n> [!NOTE]\n> Function bindings are available in Svelte 5.9.0 and newer.\n"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "svelte-core-bestpractices/references/each.md",
|
|
123
|
+
"include": [
|
|
124
|
+
"skills"
|
|
125
|
+
],
|
|
126
|
+
"exclude": [],
|
|
127
|
+
"contents": "## Keyed each blocks\n\n```svelte\n<!--- copy: false --->\n{#each expression as name (key)}...{/each}\n```\n\n```svelte\n<!--- copy: false --->\n{#each expression as name, index (key)}...{/each}\n```\n\nIf a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to intelligently update the list when data changes by inserting, moving and deleting items, rather than adding or removing items at the end and updating the state in the middle.\n\nThe key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.\n\n```svelte\n{#each items as item (item.id)}\n\t<li>{item.name} x {item.qty}</li>\n{/each}\n\n<!-- or with additional index value -->\n{#each items as item, i (item.id)}\n\t<li>{i + 1}: {item.name} x {item.qty}</li>\n{/each}\n```\n\nYou can freely use destructuring and rest patterns in each blocks.\n\n```svelte\n{#each items as { id, name, qty }, i (id)}\n\t<li>{i + 1}: {name} x {qty}</li>\n{/each}\n\n{#each objects as { id, ...rest }}\n\t<li><span>{id}</span><MyComponent {...rest} /></li>\n{/each}\n\n{#each items as [id, ...rest]}\n\t<li><span>{id}</span><MyComponent values={rest} /></li>\n{/each}\n```\n"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "svelte-core-bestpractices/references/hydratable.md",
|
|
131
|
+
"include": [
|
|
132
|
+
"skills"
|
|
133
|
+
],
|
|
134
|
+
"exclude": [],
|
|
135
|
+
"contents": "In Svelte, when you want to render asynchronous content data on the server, you can simply `await` it. This is great! However, it comes with a pitfall: when hydrating that content on the client, Svelte has to redo the asynchronous work, which blocks hydration for however long it takes:\n\n```svelte\n<script>\n import { getUser } from 'my-database-library';\n\n // This will get the user on the server, render the user's name into the h1,\n // and then, during hydration on the client, it will get the user _again_,\n // blocking hydration until it's done.\n const user = await getUser();\n</script>\n\n<h1>{user.name}</h1>\n```\n\nThat's silly, though. If we've already done the hard work of getting the data on the server, we don't want to get it again during hydration on the client. `hydratable` is a low-level API built to solve this problem. You probably won't need this very often — it will be used behind the scenes by whatever datafetching library you use. For example, it powers [remote functions in SvelteKit](https://svelte.dev/docs/kit/remote-functions/llms.txt).\n\nTo fix the example above:\n\n```svelte\n<script>\n import { hydratable } from 'svelte';\n import { getUser } from 'my-database-library';\n\n // During server rendering, this will serialize and stash the result of `getUser`, associating\n // it with the provided key and baking it into the `head` content. During hydration, it will\n // look for the serialized version, returning it instead of running `getUser`. After hydration\n // is done, if it's called again, it'll simply invoke `getUser`.\n const user = await hydratable('user', () => getUser());\n</script>\n\n<h1>{user.name}</h1>\n```\n\nThis API can also be used to provide access to random or time-based values that are stable between server rendering and hydration. For example, to get a random number that doesn't update on hydration:\n\n```ts\nimport { hydratable } from 'svelte';\nconst rand = hydratable('random', () => Math.random());\n```\n\nIf you're a library author, be sure to prefix the keys of your `hydratable` values with the name of your library so that your keys don't conflict with other libraries.\n\n## Serialization\n\nAll data returned from a `hydratable` function must be serializable. But this doesn't mean you're limited to JSON — Svelte uses [`devalue`](https://npmjs.com/package/devalue), which can serialize all sorts of things including `Map`, `Set`, `URL`, and `BigInt`. Check the documentation page for a full list. In addition to these, thanks to some Svelte magic, you can also fearlessly use promises:\n\n```svelte\n<script>\n import { hydratable } from 'svelte';\n const promises = hydratable('random', () => {\n return {\n one: Promise.resolve(1),\n two: Promise.resolve(2)\n }\n });\n</script>\n\n{await promises.one}\n{await promises.two}\n```\n\n## CSP\n\n`hydratable` adds an inline `<script>` block to the `head` returned from `render`. If you're using [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) (CSP), this script will likely fail to run. You can provide a `nonce` to `render`:\n\n```js\nconst nonce = crypto.randomUUID();\n\nconst { head, body } = await render(App, {\n\tcsp: { nonce }\n});\n```\n\nThis will add the `nonce` to the script block, on the assumption that you will later add the same nonce to the CSP header of the document that contains it:\n\n```js\nresponse.headers.set(\n 'Content-Security-Policy',\n `script-src 'nonce-${nonce}'`\n );\n```\n\nIt's essential that a `nonce` — which, British slang definition aside, means 'number used once' — is only used when dynamically server rendering an individual response.\n\nIf instead you are generating static HTML ahead of time, you must use hashes instead:\n\n```js\nconst { head, body, hashes } = await render(App, {\n\tcsp: { hash: true }\n});\n```\n\n`hashes.script` will be an array of strings like `[\"sha256-abcd123\"]`. As with `nonce`, the hashes should be used in your CSP header:\n\n```js\nresponse.headers.set(\n 'Content-Security-Policy',\n `script-src ${hashes.script.map((hash) => `'${hash}'`).join(' ')}`\n );\n```\n\nWe recommend using `nonce` over hash if you can, as `hash` will interfere with streaming SSR in the future.\n"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "svelte-core-bestpractices/references/inspect.md",
|
|
139
|
+
"include": [
|
|
140
|
+
"skills"
|
|
141
|
+
],
|
|
142
|
+
"exclude": [],
|
|
143
|
+
"contents": "> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop.\n\nThe `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire:\n\n<!-- codeblock:start {\"title\":\"$inspect(...)\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\tlet count = $state(0);\n\tlet message = $state('hello');\n\n\t$inspect(count, message); // will console.log when `count` or `message` change\n</script>\n\n<button onclick={() => count++}>Increment</button>\n<input bind:value={message} />\n```\n\n<!-- codeblock:end -->\n\nOn updates, a stack trace will be printed, making it easy to find the origin of a state change (unless you're in the playground, due to technical limitations).\n\n## $inspect(...).with\n\n`$inspect(...)` returns an object with a `with` method, which you can invoke with a callback that will then be invoked instead of `console.log`. The first argument to the callback is either `\"init\"` or `\"update\"`; subsequent arguments are the values passed to `$inspect`:\n\n<!-- codeblock:start {\"title\":\"$inspect(...).with(...)\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\tlet count = $state(0);\n\n\t$inspect(count).with((type, count) => {\n\t\tif (type === 'update') {\n\t\t\tdebugger; // or `console.trace`, or whatever you want\n\t\t}\n\t});\n</script>\n\n<button onclick={() => count++}>Increment</button>\n```\n\n<!-- codeblock:end -->\n\n## $inspect.trace(...)\n\nThis rune, added in 5.14, causes the surrounding function to be _traced_ in development. Any time the function re-runs as part of an [effect](https://svelte.dev/docs/svelte/$effect/llms.txt) or a [derived](https://svelte.dev/docs/svelte/$derived/llms.txt), information will be printed to the console about which pieces of reactive state caused the effect to fire.\n\n```svelte\n<script>\n\timport { doSomeWork } from './elsewhere';\n\n\t$effect(() => {\n\t\t+++// $inspect.trace must be the first statement of a function body+++\n\t\t+++$inspect.trace();+++\n\t\tdoSomeWork();\n\t});\n</script>\n```\n\n`$inspect.trace` takes an optional first argument which will be used as the label.\n"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "svelte-core-bestpractices/references/render.md",
|
|
147
|
+
"include": [
|
|
148
|
+
"skills"
|
|
149
|
+
],
|
|
150
|
+
"exclude": [],
|
|
151
|
+
"contents": "To render a [snippet](https://svelte.dev/docs/svelte/snippet/llms.txt), use a `{@render ...}` tag.\n\n```svelte\n{#snippet sum(a, b)}\n\t<p>{a} + {b} = {a + b}</p>\n{/snippet}\n\n{@render sum(1, 2)}\n{@render sum(3, 4)}\n{@render sum(5, 6)}\n```\n\nThe expression can be an identifier like `sum`, or an arbitrary JavaScript expression:\n\n```svelte\n{@render (cool ? coolSnippet : lameSnippet)()}\n```\n\n## Optional snippets\n\nIf the snippet is potentially undefined — for example, because it's an incoming prop — then you can use optional chaining to only render it when it _is_ defined:\n\n```svelte\n{@render children?.()}\n```\n\nAlternatively, use an [`{#if ...}`](https://svelte.dev/docs/svelte/if/llms.txt) block with an `:else` clause to render fallback content:\n\n```svelte\n{#if children}\n\t{@render children()}\n{:else}\n\t<p>fallback content</p>\n{/if}\n```\n"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "svelte-core-bestpractices/references/snippet.md",
|
|
155
|
+
"include": [
|
|
156
|
+
"skills"
|
|
157
|
+
],
|
|
158
|
+
"exclude": [],
|
|
159
|
+
"contents": "```svelte\n<!--- copy: false --->\n{#snippet name()}...{/snippet}\n```\n\n```svelte\n<!--- copy: false --->\n{#snippet name(param1, param2, paramN)}...{/snippet}\n```\n\nSnippets, and [render tags](https://svelte.dev/docs/svelte/@render/llms.txt), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like this...\n\n```svelte\n{#each images as image}\n\t{#if image.href}\n\t\t<a href={image.href}>\n\t\t\t<figure>\n\t\t\t\t<img src={image.src} alt={image.caption} width={image.width} height={image.height} />\n\t\t\t\t<figcaption>{image.caption}</figcaption>\n\t\t\t</figure>\n\t\t</a>\n\t{:else}\n\t\t<figure>\n\t\t\t<img src={image.src} alt={image.caption} width={image.width} height={image.height} />\n\t\t\t<figcaption>{image.caption}</figcaption>\n\t\t</figure>\n\t{/if}\n{/each}\n```\n\n...you can write this:\n\n```svelte\n{#snippet figure(image)}\n\t<figure>\n\t\t<img src={image.src} alt={image.caption} width={image.width} height={image.height} />\n\t\t<figcaption>{image.caption}</figcaption>\n\t</figure>\n{/snippet}\n\n{#each images as image}\n\t{#if image.href}\n\t\t<a href={image.href}>\n\t\t\t{@render figure(image)}\n\t\t</a>\n\t{:else}\n\t\t{@render figure(image)}\n\t{/if}\n{/each}\n```\n\nLike function declarations, snippets can have an arbitrary number of parameters, which can have default values, and you can destructure each parameter. You cannot use rest parameters, however.\n\n## Snippet scope\n\nSnippets can be declared anywhere inside your component. They can reference values declared outside themselves, for example in the `<script>` tag or in `{#each ...}` blocks...\n\n<!-- codeblock:start {\"title\":\"Snippets\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\tlet { message = `it's great to see you!` } = $props();\n</script>\n\n{#snippet hello(name)}\n\t<p>hello {name}! {message}!</p>\n{/snippet}\n\n{@render hello('alice')}\n{@render hello('bob')}\n```\n\n<!-- codeblock:end -->\n\n...and they are 'visible' to everything in the same lexical scope (i.e. siblings, and children of those siblings):\n\n```svelte\n<div>\n\t{#snippet x()}\n\t\t{#snippet y()}...{/snippet}\n\n\t\t<!-- this is fine -->\n\t\t{@render y()}\n\t{/snippet}\n\n\t<!-- this will error, as `y` is not in scope -->\n\t{@render y()}\n</div>\n\n<!-- this will also error, as `x` is not in scope -->\n{@render x()}\n```\n\nSnippets can reference themselves and each other:\n\n<!-- codeblock:start {\"title\":\"Self-referencing snippets\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n{#snippet blastoff()}\n\t<span>🚀</span>\n{/snippet}\n\n{#snippet countdown(n)}\n\t{#if n > 0}\n\t\t<span>{n}...</span>\n\t\t{@render countdown(n - 1)}\n\t{:else}\n\t\t{@render blastoff()}\n\t{/if}\n{/snippet}\n\n{@render countdown(10)}\n```\n\n<!-- codeblock:end -->\n\n## Passing snippets to components\n\n### Explicit props\n\nWithin the template, snippets are values just like any other. As such, they can be passed to components as props:\n\n<!-- codeblock:start {\"title\":\"Explicit snippet props\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport Table from './Table.svelte';\n\n\tconst fruits = [\n\t\t{ name: 'apples', qty: 5, price: 2 },\n\t\t{ name: 'bananas', qty: 10, price: 1 },\n\t\t{ name: 'cherries', qty: 20, price: 0.5 }\n\t];\n</script>\n\n{#snippet header()}\n\t<th>fruit</th>\n\t<th>qty</th>\n\t<th>price</th>\n\t<th>total</th>\n{/snippet}\n\n{#snippet row(d)}\n\t<td>{d.name}</td>\n\t<td>{d.qty}</td>\n\t<td>{d.price}</td>\n\t<td>{d.qty * d.price}</td>\n{/snippet}\n\n<Table data={fruits} +++{header} {row}+++ />\n```\n\n```svelte\n<!--- file: Table.svelte --->\n<script>\n\tlet { data, header, row } = $props();\n</script>\n\n<table>\n\t{#if header}\n\t\t<thead>\n\t\t\t<tr>{@render header()}</tr>\n\t\t</thead>\n\t{/if}\n\n\t<tbody>\n\t\t{#each data as d}\n\t\t\t<tr>{@render row(d)}</tr>\n\t\t{/each}\n\t</tbody>\n</table>\n\n<style>\n\ttable {\n\t\ttext-align: left;\n\t\tborder-spacing: 0;\n\t}\n\n\ttbody tr:nth-child(2n+1) {\n\t\tbackground: ButtonFace;\n\t}\n\n\ttable :global(th), table :global(td) {\n\t\tpadding: 0.5em;\n\t}\n</style>\n```\n\n<!-- codeblock:end -->\n\nThink about it like passing content instead of data to a component. The concept is similar to slots in web components.\n\n### Implicit props\n\nAs an authoring convenience, snippets declared directly _inside_ a component implicitly become props _on_ the component:\n\n<!-- codeblock:start {\"title\":\"Implicit snippet props\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport Table from './Table.svelte';\n\n\tconst fruits = [\n\t\t{ name: 'apples', qty: 5, price: 2 },\n\t\t{ name: 'bananas', qty: 10, price: 1 },\n\t\t{ name: 'cherries', qty: 20, price: 0.5 }\n\t];\n</script>\n\n<Table data={fruits}>\n\t{#snippet header()}\n\t\t<th>fruit</th>\n\t\t<th>qty</th>\n\t\t<th>price</th>\n\t\t<th>total</th>\n\t{/snippet}\n\n\t{#snippet row(d)}\n\t\t<td>{d.name}</td>\n\t\t<td>{d.qty}</td>\n\t\t<td>{d.price}</td>\n\t\t<td>{d.qty * d.price}</td>\n\t{/snippet}\n</Table>\n```\n\n```svelte\n<!--- file: Table.svelte --->\n<script>\n\tlet { data, header, row } = $props();\n</script>\n\n<table>\n\t{#if header}\n\t\t<thead>\n\t\t\t<tr>{@render header()}</tr>\n\t\t</thead>\n\t{/if}\n\n\t<tbody>\n\t\t{#each data as d}\n\t\t\t<tr>{@render row(d)}</tr>\n\t\t{/each}\n\t</tbody>\n</table>\n\n<style>\n\ttable {\n\t\ttext-align: left;\n\t\tborder-spacing: 0;\n\t}\n\n\ttbody tr:nth-child(2n+1) {\n\t\tbackground: ButtonFace;\n\t}\n\n\ttable :global(th), table :global(td) {\n\t\tpadding: 0.5em;\n\t}\n</style>\n```\n\n<!-- codeblock:end -->\n\n### Implicit `children` snippet\n\nAny content inside the component tags that is _not_ a snippet declaration implicitly becomes part of the `children` snippet:\n\n<!-- codeblock:start {\"title\":\"Implicit children snippet\",\"selected\":\"Button.svelte\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport Button from './Button.svelte';\n</script>\n\n<Button>click me</Button>\n```\n\n```svelte\n<!--- file: Button.svelte --->\n<script>\n\tlet { children } = $props();\n</script>\n\n<!-- result will be <button>click me</button> -->\n<button>{@render children()}</button>\n```\n\n<!-- codeblock:end -->\n\n> [!NOTE] Note that you cannot have a prop called `children` if you also have content inside the component — for this reason, you should avoid having props with that name\n\n### Optional snippet props\n\nYou can declare snippet props as being optional. You can either use optional chaining to not render anything if the snippet isn't set...\n\n```svelte\n<script>\n let { children } = $props();\n</script>\n\n{@render children?.()}\n```\n\n...or use an `#if` block to render fallback content:\n\n```svelte\n<script>\n let { children } = $props();\n</script>\n\n{#if children}\n {@render children()}\n{:else}\n fallback content\n{/if}\n```\n\n## Typing snippets\n\nSnippets implement the `Snippet` interface imported from `'svelte'`:\n\n```svelte\n<script lang=\"ts\">\n\timport type { Snippet } from 'svelte';\n\n\tinterface Props {\n\t\tdata: any[];\n\t\tchildren: Snippet;\n\t\trow: Snippet<[any]>;\n\t}\n\n\tlet { data, children, row }: Props = $props();\n</script>\n```\n\nWith this change, red squigglies will appear if you try and use the component without providing a `data` prop and a `row` snippet. Notice that the type argument provided to `Snippet` is a tuple, since snippets can have multiple parameters.\n\nWe can tighten things up further by declaring a generic, so that `data` and `row` refer to the same type:\n\n```svelte\n<script lang=\"ts\" generics=\"T\">\n\timport type { Snippet } from 'svelte';\n\n\tlet {\n\t\tdata,\n\t\tchildren,\n\t\trow\n\t}: {\n\t\tdata: T[];\n\t\tchildren: Snippet;\n\t\trow: Snippet<[T]>;\n\t} = $props();\n</script>\n```\n\n## Exporting snippets\n\nSnippets declared at the top level of a `.svelte` file can be exported from a `<script module>` for use in other components, provided they don't reference any declarations in a non-module `<script>` (whether directly or indirectly, via other snippets):\n\n<!-- codeblock:start {\"title\":\"Exported snippets\",\"selected\":\"snippets.svelte\"} -->\n\n```svelte\n<!--- file: App.svelte --->\n<script>\n\timport { add } from './snippets.svelte';\n</script>\n\n{@render add(1, 2)}\n\n```\n\n```svelte\n<!--- file: snippets.svelte --->\n<script module>\n\texport { add };\n</script>\n\n{#snippet add(a, b)}\n\t{a} + {b} = {a + b}\n{/snippet}\n```\n\n<!-- codeblock:end -->\n\n> [!NOTE]\n> This requires Svelte 5.5.0 or newer\n\n## Programmatic snippets\n\nSnippets can be created programmatically with the [`createRawSnippet`](https://svelte.dev/docs/svelte/svelte/llms.txt#createRawSnippet) API. This is intended for advanced use cases.\n\n## Snippets and slots\n\nIn Svelte 4, content can be passed to components using [slots](https://svelte.dev/docs/svelte/legacy-slots/llms.txt). Snippets are more powerful and flexible, and so slots have been deprecated in Svelte 5.\n"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "svelte-core-bestpractices/references/svelte-reactivity.md",
|
|
163
|
+
"include": [
|
|
164
|
+
"skills"
|
|
165
|
+
],
|
|
166
|
+
"exclude": [],
|
|
167
|
+
"contents": "## createSubscriber\n\n<blockquote class=\"since note\">\n\nAvailable since 5.7.0\n\n</blockquote>\n\nReturns a `subscribe` function that integrates external event-based systems with Svelte's reactivity.\nIt's particularly useful for integrating with web APIs like `MediaQuery`, `IntersectionObserver`, or `WebSocket`.\n\nIf `subscribe` is called inside an effect (including indirectly, for example inside a getter),\nthe `start` callback will be called with an `update` function. Whenever `update` is called, the effect re-runs.\n\nIf `start` returns a cleanup function, it will be called when the effect is destroyed.\n\nIf `subscribe` is called in multiple effects, `start` will only be called once as long as the effects\nare active, and the returned teardown function will only be called when all effects are destroyed.\n\nIt's best understood with an example. Here's an implementation of [`MediaQuery`](https://svelte.dev/docs/svelte/svelte-reactivity/llms.txt#MediaQuery):\n\n```js\n// @errors: 7031\nimport { createSubscriber } from 'svelte/reactivity';\nimport { on } from 'svelte/events';\n\nexport class MediaQuery {\n\t#query;\n\t#subscribe;\n\n\tconstructor(query) {\n\t\tthis.#query = window.matchMedia(`(${query})`);\n\n\t\tthis.#subscribe = createSubscriber((update) => {\n\t\t\t// when the `change` event occurs, re-run any effects that read `this.current`\n\t\t\tconst off = on(this.#query, 'change', update);\n\n\t\t\t// stop listening when all the effects are destroyed\n\t\t\treturn () => off();\n\t\t});\n\t}\n\n\tget current() {\n\t\t// This makes the getter reactive, if read in an effect\n\t\tthis.#subscribe();\n\n\t\t// Return the current state of the query, whether or not we're in an effect\n\t\treturn this.#query.matches;\n\t}\n}\n```\n\n<div class=\"ts-block\">\n\n```dts\nfunction createSubscriber(\n\tstart: (update: () => void) => (() => void) | void\n): () => void;\n```\n\n</div>\n"
|
|
168
|
+
},
|
|
73
169
|
{
|
|
74
170
|
"name": "package.json",
|
|
75
171
|
"include": [
|
package/dist/src/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as StringQuestion, C as BooleanQuestion, D as OptionValues, E as OptionDefinition, O as Question, S as BaseQuestion, T as NumberQuestion, _ as SvApi, a as Addon, b as Workspace, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as SetupResult, h as PreparedAddon, i as add, j as officialAddons, k as SelectQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as defineAddon, w as MultiSelectQuestion, x as WorkspaceOptions, y as defineAddonOptions } from "../engine-
|
|
1
|
+
import { A as StringQuestion, C as BooleanQuestion, D as OptionValues, E as OptionDefinition, O as Question, S as BaseQuestion, T as NumberQuestion, _ as SvApi, a as Addon, b as Workspace, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as SetupResult, h as PreparedAddon, i as add, j as officialAddons, k as SelectQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as defineAddon, w as MultiSelectQuestion, x as WorkspaceOptions, y as defineAddonOptions } from "../engine-5Sg3lJiQ.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/create/index.d.ts
|
|
4
4
|
type TemplateType = (typeof templateTypes)[number];
|
package/dist/src/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as defineAddonOptions, m as create$1, o as officialAddons, s as defineAddon, t as add, y as svDeprecated } from "../engine-
|
|
1
|
+
import { c as defineAddonOptions, m as create$1, o as officialAddons, s as defineAddon, t as add, y as svDeprecated } from "../engine-1Kj9XHT7.mjs";
|
|
2
2
|
//#region src/index.ts
|
|
3
3
|
function create(cwdOrOptions, legacyOptions) {
|
|
4
4
|
if (typeof cwdOrOptions === "string") {
|
package/dist/src/testing.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as OptionMap, t as AddonMap } from "../engine-
|
|
1
|
+
import { r as OptionMap, t as AddonMap } from "../engine-5Sg3lJiQ.mjs";
|
|
2
2
|
import { Page } from "@playwright/test";
|
|
3
3
|
import { TestProject } from "vitest/node";
|
|
4
4
|
|
|
@@ -50,8 +50,8 @@ type SetupTestOptions<Addons extends AddonMap> = {
|
|
|
50
50
|
};
|
|
51
51
|
type PrepareServerOptions = {
|
|
52
52
|
cwd: string;
|
|
53
|
-
page: Page;
|
|
54
|
-
buildCommand?: string;
|
|
53
|
+
page: Page; /** @default 'pnpm build' */
|
|
54
|
+
buildCommand?: string; /** @default 'pnpm preview' */
|
|
55
55
|
previewCommand?: string;
|
|
56
56
|
/**
|
|
57
57
|
* Vitest's `expect`, injected by `createSetupTest`. Used to make a Vitest-counted
|
package/dist/src/testing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as __toESM, b as __commonJSMin, f as R, i as addPnpmAllowBuilds, m as create, p as z, t as add, x as __require } from "../engine-
|
|
1
|
+
import { S as __toESM, b as __commonJSMin, f as R, i as addPnpmAllowBuilds, m as create, p as z, t as add, x as __require } from "../engine-1Kj9XHT7.mjs";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import V from "node:process";
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"sv": "^0.
|
|
25
|
+
"sv": "^0.17.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"sv": "^0.
|
|
29
|
-
"@sveltejs/sv-utils": "^0.3.
|
|
28
|
+
"sv": "^0.17.1",
|
|
29
|
+
"@sveltejs/sv-utils": "^0.3.3",
|
|
30
30
|
"@playwright/test": "^1.60.0",
|
|
31
31
|
"@types/node": "^25.9.1",
|
|
32
32
|
"tsdown": "^0.22.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sv",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A command line interface (CLI) for creating and maintaining Svelte applications",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,21 +25,19 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@sveltejs/sv-utils": "0.3.
|
|
28
|
+
"@sveltejs/sv-utils": "0.3.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.5.0",
|
|
32
32
|
"@types/gitignore-parser": "^0.0.3",
|
|
33
33
|
"@types/ps-tree": "^1.1.6",
|
|
34
|
-
"@types/tar-fs": "^2.0.4",
|
|
35
34
|
"commander": "^15.0.0",
|
|
36
35
|
"create-vite": "^8.2.0",
|
|
37
36
|
"empathic": "^2.0.1",
|
|
38
37
|
"gitignore-parser": "^0.0.2",
|
|
38
|
+
"modern-tar": "^0.7.7",
|
|
39
39
|
"ps-tree": "^1.2.0",
|
|
40
40
|
"sucrase": "^3.35.1",
|
|
41
|
-
"svelte": "^5.56.1",
|
|
42
|
-
"tar-fs": "^3.1.2",
|
|
43
41
|
"tiny-glob": "^0.2.9",
|
|
44
42
|
"tinyexec": "^1.2.4",
|
|
45
43
|
"valibot": "^1.4.1"
|
|
@@ -57,6 +55,7 @@
|
|
|
57
55
|
"scripts": {
|
|
58
56
|
"check": "tsgo",
|
|
59
57
|
"format": "pnpm lint --write",
|
|
60
|
-
"lint": "prettier --check . --config ../../prettier.config.js --ignore-path ../../.gitignore --ignore-path .gitignore --ignore-path ../../.prettierignore"
|
|
58
|
+
"lint": "prettier --check . --config ../../prettier.config.js --ignore-path ../../.gitignore --ignore-path .gitignore --ignore-path ../../.prettierignore",
|
|
59
|
+
"update-template-repo": "./src/create/scripts/update-template-repo.sh"
|
|
61
60
|
}
|
|
62
61
|
}
|