Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 9 additions & 38 deletions documentation/docs/20-commands/20-sv-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,49 +71,20 @@ Prevents installing dependencies
> [!NOTE]
> Svelte maintainers have not reviewed community add-ons for malicious code!

You can find [community add-ons on npm](https://www.npmx.dev/search?q=keyword:sv-add) by searching for keyword: `sv-add`.

### How to install a community add-on

```sh
npx sv add [PROTOCOL][COMMUNITY_ADDON]
```

You can:

- mix and match official and community add-ons
- use the interactive prompt or give args to the cli
- use the `--add` option in the `create` command

```sh
npx sv add eslint "@supacool"
```
Community add-ons are npm packages published by the community. Look out for add-ons from your favorite libraries and tools. _(soon)_ many are building `sv` add-ons to make integration a one-liner. You can find them [on npm](https://www.npmx.dev/search?q=keyword:sv-add) by searching for keyword: `sv-add`.

```sh
npx sv create --add eslint "@supacool"
```

### Package Protocols

```sh
# Scoped package: @org (preferred), we will look for @org/sv
npx sv add "@supacool"

# Regular npm package (with or without scope)
npx sv add my-cool-addon
# Install a community add-on by org
npx sv add @supacool

# Local add-on
# Use a local add-on (for development or custom/private add-ons)
npx sv add file:../path/to/my-addon
```

### How to create a community add-on

To start on a good track, create your add-on with the `addon` template.
# Mix and match official and community add-ons
npx sv add eslint @supacool
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the quotes required?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On windows yes :/
On the rest no

I agree that it's way better wo the quote!
Maybe we could add "On windows do like this..." ? (But it's also kinda ungly)


```sh
npx sv create --template addon [path]
# Also works when creating a new project directly
npx sv create --add eslint @supacool
```

In your new add-on directory, check out the `README.md` and `CONTRIBUTING.md` to get started.

Then you can continue with the [API docs](/docs/cli/add-on) to start building your add-on. You can also have a look at the [official addons source code](https://github.com/sveltejs/cli/tree/main/packages/sv/src/addons) to get some inspiration on what can be done.
Want to create your own? Check the [Add-on Docs](community).
222 changes: 222 additions & 0 deletions documentation/docs/30-add-ons/99-community.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
---
title: [create your own]
---

> [!NOTE]
> Community add-ons are currently **experimental**. The API may change. Don't use them in production yet!

This guide covers how to create, test, and publish community add-ons for `sv`.

## Quick start

The easiest way to create an add-on is using the `addon` template:

```sh
npx sv create --template addon [path]
```

The project has a `README.md` and `CONTRIBUTING.md` to guide you along.

## Project structure

Typically, an add-on looks like this:

```js
// @noErrors
import { transforms } from '@sveltejs/sv-utils';
import { defineAddon, defineAddonOptions } from 'sv';

// your add-on definition, the entry point
export default defineAddon({
id: 'your-addon-name',

// optional: one-liner shown in prompts
shortDescription: 'does X',

// optional: link to docs/repo
homepage: 'https://...',

// Define options for user prompts (or passed as arguments)
options: defineAddonOptions()
.add('who', {
question: 'To whom should the addon say hello?',
type: 'string' // boolean | number | select | multiselect
})
.build(),

// preparing step, check requirements and dependencies
setup: ({ dependsOn }) => {
dependsOn('tailwindcss');
},

// actual execution of the addon
run: ({ isKit, cancel, sv, options, directory }) => {
if (!isKit) return cancel('SvelteKit is required');

// Add "Hello [who]!" to the root page
sv.file(
directory.kitRoutes + '/+page.svelte',
transforms.svelte(({ ast, svelte }) => {
svelte.addFragment(ast, `<p>Hello ${options.who}!</p>`);
})
);
}
});
```

> `sv` is responsible for the file system - `sv.file()` accepts a `path` to the file and a callback function to modify it.
> `@sveltejs/sv-utils` is responsible for the content - `transforms.svelte()` provides you with the proper AST and utils to modify the file. See [sv-utils](/docs/cli/sv-utils) for the full API.

## Development

You can run your add-on locally using the `file:` protocol:

```sh
cd /path/to/test-project
npx sv add file:../path/to/my-addon
```

This allows you to iterate quickly without publishing to npm.

The `file:` protocol also works for custom or private add-ons that you don't intend to publish - for example, to standardize project setup across your team or organization.

> [!NOTE]
> It is not necessary to build your add-on during development.

## Testing

The `sv/testing` module provides utilities for testing your add-on:

```js
import { setupTest } from 'sv/testing';
import { test, expect } from 'vitest';
import addon from './index.js';

test('adds hello message', async () => {
const { content } = await setupTest({
addon,
options: { who: 'World' },
files: {
'src/routes/+page.svelte': '<h1>Welcome</h1>'
}
});

expect(content('src/routes/+page.svelte')).toContain('Hello World!');
});
```

## Publishing

### Bundling

Community add-ons are bundled with [tsdown](https://tsdown.dev/) into a single file. Everything is bundled except `sv`. (It is a peer dependency provided at runtime.)

### `package.json`

Your add-on must have `sv` as a peer dependency and **no** `dependencies` in `package.json`:

```jsonc
{
"name": "@your-org/sv",
"version": "1.0.0",
"type": "module",
// entrypoint during development
"exports": {
".": "./src/index.js"
},
"publishConfig": {
"access": "public",
// entrypoint on build
"exports": {
".": { "default": "./dist/index.js" }
}
},
// cannot have dependencies
"dependencies": {},
"peerDependencies": {
// minimum version required to run by this addon
"sv": "^0.13.0"
},
// Add this keyword so users can discover your add-on
"keywords": ["sv-add"]
}
```

### Naming convention

Name your package `@your-org/sv`. Users install it by typing just the org:

```sh
# npm package: @your-org/sv
npx sv add @your-org
```

> [!NOTE]
> Unscoped packages are not supported yet

### Export options

`sv` first tries to import `your-package/sv`, then falls back to the default export. This means you have two options:

1. **Default export** (recommended for dedicated add-on packages):

```json
{
"exports": {
".": "./src/index.js"
}
}
```

2. **`./sv` export** (for packages that also export other functionality):
```json
{
"exports": {
".": "./src/main.js",
"./sv": "./src/addon.js"
}
}
```

### Publish to npm

```sh
npm login
npm publish
```

> `prepublishOnly` automatically runs the build before publishing.

## Next steps

You can optionally display guidance in the console after your add-on runs:

```js
// @noErrors
import { color } from '@sveltejs/sv-utils';

export default defineAddon({
// ...
nextSteps: ({ options }) => [
`Run ${color.command('npm run dev')} to start developing`,
`Check out the docs at https://...`
]
});
```

## Version compatibility

Your add-on should specify a minimum `sv` version in `peerDependencies`. Your user will get a compatibility warning if their `sv` version has a different major version than what was specified.

## Examples

See the [official add-on source code](https://github.com/sveltejs/cli/tree/main/packages/sv/src/addons) for some real world examples.

## Architecture

The Svelte CLI is split into two packages with a clear boundary:

- **`sv`** = **where and when** to do it. It owns paths, workspace detection, dependency tracking, and file I/O. The engine orchestrates add-on execution.
- **`@sveltejs/sv-utils`** = **what** to do to content. It provides parsers, language tooling, and typed transforms. Everything here is pure - no file system, no workspace awareness.

This separation means transforms are testable without a workspace and composable across add-ons.
Loading
Loading