-
-
Notifications
You must be signed in to change notification settings - Fork 89
docs: community addon #1018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
docs: community addon #1018
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
358b6ab
first pass
sacrosanctic 4285eb3
use `path.join`
sacrosanctic 68a5149
move addon doc out of api
sacrosanctic 77d80cf
fix link
sacrosanctic 838b421
reverse path.join
sacrosanctic 5963d8b
something
sacrosanctic 929e40e
why wont it work!
sacrosanctic cf38bc9
first part
jycouet c910bb7
doc review
jycouet a1331ed
fix preview ?
jycouet 530545a
refacto
jycouet 0c3f9ee
move things around
jycouet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are the quotes required?
There was a problem hiding this comment.
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)