Svelte MCP
This commit is contained in:
parent
417ec134c1
commit
4d14fc2d6d
7 changed files with 243 additions and 60 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"svelte": {
|
|
||||||
"url": "https://mcp.svelte.dev/mcp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
176
.cursor/skills/svelte-code-writer/SKILL.md
Normal file
176
.cursor/skills/svelte-code-writer/SKILL.md
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
---
|
||||||
|
name: svelte-code-writer
|
||||||
|
description: 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.
|
||||||
|
---
|
||||||
|
|
||||||
|
## `$state`
|
||||||
|
|
||||||
|
Only 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.
|
||||||
|
|
||||||
|
Objects 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.
|
||||||
|
|
||||||
|
## `$derived`
|
||||||
|
|
||||||
|
To compute something from state, use `$derived` rather than `$effect`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// do this
|
||||||
|
let square = $derived(num * num);
|
||||||
|
|
||||||
|
// don't do this
|
||||||
|
let square;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
square = num * num;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!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`.
|
||||||
|
|
||||||
|
Deriveds are writable — you can assign to them, just like `$state`, except that they will re-evaluate when their expression changes.
|
||||||
|
|
||||||
|
If 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.
|
||||||
|
|
||||||
|
## `$effect`
|
||||||
|
|
||||||
|
Effects are an escape hatch and should mostly be avoided. In particular, avoid updating state inside effects.
|
||||||
|
|
||||||
|
- If you need to sync state to an external library such as D3, it is often neater to use [`{@attach ...}`](references/@attach.md)
|
||||||
|
- 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
|
||||||
|
- If you need to log values for debugging purposes, use [`$inspect`](references/$inspect.md)
|
||||||
|
- If you need to observe something external to Svelte, use [`createSubscriber`](references/svelte-reactivity.md)
|
||||||
|
|
||||||
|
Never wrap the contents of an effect in `if (browser) {...}` or similar — effects do not run on the server.
|
||||||
|
|
||||||
|
## `$props`
|
||||||
|
|
||||||
|
Treat props as though they will change. For example, values that depend on props should usually use `$derived`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// @errors: 2451
|
||||||
|
let { type } = $props();
|
||||||
|
|
||||||
|
// do this
|
||||||
|
let color = $derived(type === 'danger' ? 'red' : 'green');
|
||||||
|
|
||||||
|
// don't do this — `color` will not update if `type` changes
|
||||||
|
let color = type === 'danger' ? 'red' : 'green';
|
||||||
|
```
|
||||||
|
|
||||||
|
## `$inspect.trace`
|
||||||
|
|
||||||
|
`$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.
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
Any element attribute starting with `on` is treated as an event listener:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<button onclick={() => {...}}>click me</button>
|
||||||
|
|
||||||
|
<!-- attribute shorthand also works -->
|
||||||
|
<button {onclick}>...</button>
|
||||||
|
|
||||||
|
<!-- so do spread attributes -->
|
||||||
|
<button {...props}>...</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to attach listeners to `window` or `document` you can use `<svelte:window>` and `<svelte:document>`:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<svelte:window onkeydown={...} />
|
||||||
|
<svelte:document onvisibilitychange={...} />
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid using `onMount` or `$effect` for this.
|
||||||
|
|
||||||
|
## Snippets
|
||||||
|
|
||||||
|
[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.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
{#snippet greeting(name)}
|
||||||
|
<p>hello {name}!</p>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{@render greeting('world')}
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!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.
|
||||||
|
|
||||||
|
## Each blocks
|
||||||
|
|
||||||
|
Prefer 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.
|
||||||
|
|
||||||
|
> [!NOTE] The key _must_ uniquely identify the object. Do not use the index as a key.
|
||||||
|
|
||||||
|
Avoid destructuring if you need to mutate the item (with something like `bind:value={item.count}`, for example).
|
||||||
|
|
||||||
|
## Using JavaScript variables in CSS
|
||||||
|
|
||||||
|
If you have a JS variable that you want to use inside CSS you can set a CSS custom property with the `style:` directive.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<div style:--columns={columns}>...</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then reference `var(--columns)` inside the component's `<style>`.
|
||||||
|
|
||||||
|
## Styling child components
|
||||||
|
|
||||||
|
The 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:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<!-- Parent.svelte -->
|
||||||
|
<Child --color="red" />
|
||||||
|
|
||||||
|
<!-- Child.svelte -->
|
||||||
|
<h1>Hello</h1>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
color: var(--color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<div>
|
||||||
|
<Child />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div :global {
|
||||||
|
h1 {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Consider 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.
|
||||||
|
|
||||||
|
Use `createContext` rather than `setContext` and `getContext`, as it provides type safety.
|
||||||
|
|
||||||
|
## Async Svelte
|
||||||
|
|
||||||
|
If 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.
|
||||||
|
|
||||||
|
## Avoid legacy features
|
||||||
|
|
||||||
|
Always use runes mode for new code, and avoid features that have more modern replacements:
|
||||||
|
|
||||||
|
- use `$state` instead of implicit reactivity (e.g. `let count = 0; count += 1`)
|
||||||
|
- use `$derived` and `$effect` instead of `$:` assignments and statements (but only use effects when there is no better solution)
|
||||||
|
- use `$props` instead of `export let`, `$$props` and `$$restProps`
|
||||||
|
- use `onclick={...}` instead of `on:click={...}`
|
||||||
|
- use `{#snippet ...}` and `{@render ...}` instead of `<slot>` and `$$slots` and `<svelte:fragment>`
|
||||||
|
- use `<DynamicComponent>` instead of `<svelte:component this={DynamicComponent}>`
|
||||||
|
- use `import Self from './ThisComponent.svelte'` and `<Self>` instead of `<svelte:self>`
|
||||||
|
- use classes with `$state` fields to share reactivity between components, instead of using stores
|
||||||
|
- use `{@attach ...}` instead of `use:action`
|
||||||
|
- use clsx-style arrays and objects in `class` attributes, instead of the `class:` directive
|
||||||
66
.cursor/skills/svelte-core-bestpractices/SKILL.md
Normal file
66
.cursor/skills/svelte-core-bestpractices/SKILL.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
name: svelte-core-bestpractices
|
||||||
|
description: 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.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Svelte 5 Code Writer
|
||||||
|
|
||||||
|
## CLI Tools
|
||||||
|
|
||||||
|
You have access to `@sveltejs/mcp` CLI for Svelte-specific assistance. Use these commands via `npx`:
|
||||||
|
|
||||||
|
### List Documentation Sections
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @sveltejs/mcp list-sections
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists all available Svelte 5 and SvelteKit documentation sections with titles and paths.
|
||||||
|
|
||||||
|
### Get Documentation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @sveltejs/mcp get-documentation "<section1>,<section2>,..."
|
||||||
|
```
|
||||||
|
|
||||||
|
Retrieves full documentation for specified sections. Use after `list-sections` to fetch relevant docs.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @sveltejs/mcp get-documentation "$state,$derived,$effect"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Svelte Autofixer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @sveltejs/mcp svelte-autofixer "<code_or_path>" [options]
|
||||||
|
```
|
||||||
|
|
||||||
|
Analyzes Svelte code and suggests fixes for common issues.
|
||||||
|
|
||||||
|
**Options:**
|
||||||
|
|
||||||
|
- `--async` - Enable async Svelte mode (default: false)
|
||||||
|
- `--svelte-version` - Target version: 4 or 5 (default: 5)
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Analyze inline code (escape $ as \$)
|
||||||
|
npx @sveltejs/mcp svelte-autofixer '<script>let count = \$state(0);</script>'
|
||||||
|
|
||||||
|
# Analyze a file
|
||||||
|
npx @sveltejs/mcp svelte-autofixer ./src/lib/Component.svelte
|
||||||
|
|
||||||
|
# Target Svelte 4
|
||||||
|
npx @sveltejs/mcp svelte-autofixer ./Component.svelte --svelte-version 4
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** When passing code with runes (`$state`, `$derived`, etc.) via the terminal, escape the `$` character as `\$` to prevent shell variable substitution.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. **Uncertain about syntax?** Run `list-sections` then `get-documentation` for relevant topics
|
||||||
|
2. **Reviewing/debugging?** Run `svelte-autofixer` on the code to detect issues
|
||||||
|
3. **Always validate** - Run `svelte-autofixer` before finalizing any Svelte component
|
||||||
3
.github/copilot-instructions.md
vendored
3
.github/copilot-instructions.md
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
When talking about Svelte code, please always use Svelte 5 syntax in instructions and code samples unless explicitly asked to use Svelte 4 syntax. Refer to the Svelte llms.txt document at [bin/llms/svelte/llms-small.txt](../bin/llms/svelte/llms-small.txt) in this repo for details on Svelte 5 syntax. Also refer to the SvelteKit llms.txt document at [bin/llms/svelte-kit/llms-small.txt](../bin/llms/svelte-kit/llms-small.txt) in this repo for details on SvelteKit, the framework we use in this repo.
|
|
||||||
|
|
||||||
Many components added to projects come from the `@reuters-graphics/graphics-components` library, which is our team's component library including many Svelte components and other utilities. Refer to the graphics components llms.txt document at [bin/llms/graphics-components/llms.txt](../bin/llms/graphics-components/llms.txt) in this repo for details on working with components from that library and especially for examples of our usual conventions for adding graphics components to a page.
|
|
||||||
50
.github/publish.yaml
vendored
50
.github/publish.yaml
vendored
|
|
@ -1,50 +0,0 @@
|
||||||
###############################
|
|
||||||
# To publish the project via GitHub Actions:
|
|
||||||
# - move this file into .github/workflows
|
|
||||||
# - uncomment the following lines and configure
|
|
||||||
###############################
|
|
||||||
|
|
||||||
# name: Publish page
|
|
||||||
|
|
||||||
# # These line define what will trigger your project to publish
|
|
||||||
# on:
|
|
||||||
# # ... when you hit the API endpoint for this repo
|
|
||||||
# # Read more: https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event
|
|
||||||
# workflow_dispatch:
|
|
||||||
# # ... whenever you push code to the master branch on GitHub
|
|
||||||
# push:
|
|
||||||
# branches:
|
|
||||||
# - master
|
|
||||||
# # ... on a cron schedule
|
|
||||||
# schedule:
|
|
||||||
# # Customize to whatever interval you need:
|
|
||||||
# # https://crontab.guru/
|
|
||||||
# - cron: '35 * * * *'
|
|
||||||
#
|
|
||||||
# jobs:
|
|
||||||
# publish-page:
|
|
||||||
# name: Publish page
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# env:
|
|
||||||
# SERVER_WORKFLOW: true
|
|
||||||
# GRAPHICS_SERVER_USERNAME: ${{ secrets.GRAPHICS_SERVER_USERNAME }}
|
|
||||||
# GRAPHICS_SERVER_PASSWORD: ${{ secrets.GRAPHICS_SERVER_PASSWORD }}
|
|
||||||
# GRAPHICS_SERVER_API_KEY: ${{ secrets.GRAPHICS_SERVER_API_KEY }}
|
|
||||||
# SKIP_BUILD_GIT_COMMIT: true
|
|
||||||
# GRAPHICS_SERVER_PUBLISH: true
|
|
||||||
# # This line will notify a Teams channel everytime your project successfully publishes
|
|
||||||
# # GRAPHICS_SERVER_NOTIFY_TEAMS_CHANNEL: # Add a Teams webhook URL here
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v4
|
|
||||||
# - uses: pnpm/action-setup@v4
|
|
||||||
# with:
|
|
||||||
# version: 9
|
|
||||||
# - uses: actions/setup-node@v4
|
|
||||||
# with:
|
|
||||||
# node-version: 20
|
|
||||||
# cache: pnpm
|
|
||||||
# - run: git config user.name github-actions
|
|
||||||
# - run: git config user.email github-actions@github.com
|
|
||||||
# - run: pnpm install
|
|
||||||
# - run: pnpm upload
|
|
||||||
# - run: pnpm publish:publish
|
|
||||||
0
.github/workflows/.keep
vendored
0
.github/workflows/.keep
vendored
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -200,3 +200,4 @@ graphics-pack/
|
||||||
project-files/docs-ai-ps/
|
project-files/docs-ai-ps/
|
||||||
src/statics/images/docs-ai-ps
|
src/statics/images/docs-ai-ps
|
||||||
.lefthook-local/
|
.lefthook-local/
|
||||||
|
.pnpm-store
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue