Skip to main content

add-on

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:

npx sv create --template addon my-addon
cd my-addon

Add-on structure

Typically, an add-on looks like this:

hover keywords in the code to have some more context

import { import defineAddondefineAddon, import defineAddonOptionsdefineAddonOptions, import parseparse, import sveltesvelte } from 'sv/core';

// Define options that will be prompted to the user (or passed as arguments)
const const options: anyoptions = import defineAddonOptionsdefineAddonOptions()
	.add('who', {
		question: stringquestion: 'To whom should the addon say hello?',
		type: stringtype: 'string' // boolean | number | select | multiselect
	})
	.build();

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

	options: anyoptions,

	// preparing step, check requirements and dependencies
	
setup: ({ dependsOn }: {
    dependsOn: any;
}) => void
setup
: ({ dependsOn: anydependsOn }) => {
dependsOn: anydependsOn('tailwindcss'); }, // actual execution of the addon
run: ({ kit, cancel, sv, options }: {
    kit: any;
    cancel: any;
    sv: any;
    options: any;
}) => any
run
: ({ kit: anykit, cancel: anycancel, sv: anysv, options: anyoptions }) => {
if (!kit: anykit) return cancel: anycancel('SvelteKit is required'); // Add "Hello [who]!"" to the root page sv: anysv.file(kit: anykit.routesDirectory + '/+page.svelte', (content: anycontent) => { const { const ast: anyast, const generateCode: anygenerateCode } = import parseparse.svelte(content: anycontent); import sveltesvelte.addFragment(const ast: anyast, `<p>Hello ${options: anyoptions.who}!</p>`); return const generateCode: anygenerateCode(); }); } });

Development with file: protocol

While developing your add-on, you can test it locally using the file: protocol:

# In your test project
npx sv add file:../path/to/my-addon

This allows you to iterate quickly without publishing to npm.

Testing with sv/testing

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

import { const test: TestAPI

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.
@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.
@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.
@throwsError If called inside another test function.
@examplets // Define a simple test test('should add two numbers', () => { expect(add(1, 2)).toBe(3); });
@examplets // Define a test with options test('should subtract two numbers', { retry: 3 }, () => { expect(subtract(5, 2)).toBe(3); });
test
, const expect: ExpectStaticexpect } from 'vitest';
import { import setupTestsetupTest } from 'sv/testing'; import import addonaddon from './index.js'; test<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number | TestCollectorOptions): void (+2 overloads)

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.
@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.
@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.
@throwsError If called inside another test function.
@examplets // Define a simple test test('should add two numbers', () => { expect(add(1, 2)).toBe(3); });
@examplets // Define a test with options test('should subtract two numbers', { retry: 3 }, () => { expect(subtract(5, 2)).toBe(3); });
test
('adds hello message', async () => {
const { const content: anycontent } = await import setupTestsetupTest({ addon: anyaddon,
options: {
    who: string;
}
options
: { who: stringwho: 'World' },
files: {
    'src/routes/+page.svelte': string;
}
files
: {
'src/routes/+page.svelte': '<h1>Welcome</h1>' } }); expect<any>(actual: any, message?: string): Assertion<any> (+1 overload)expect(const content: anycontent('src/routes/+page.svelte')).JestAssertion<any>.toContain: <string>(item: string) => void

Used when you want to check that an item is in a list. For testing the items in the list, this uses ===, a strict equality check.

@exampleexpect(items).toContain('apple'); expect(numbers).toContain(5);
toContain
('Hello World!');
});

Publishing to npm

Package structure

Your add-on must have sv as a dependency in package.json:

{
	"name": "@your-org/sv",
	"version": "1.0.0",
	"type": "module",
	"exports": {
		".": "./dist/index.js"
	},
	"dependencies": {
		"sv": "^0.11.0"
	},
	"keywords": ["sv-add"]
}

Add the sv-add keyword so users can discover your add-on on npm.

Export options

Your package can export the add-on in two ways:

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

    {
    	"exports": {
    		".": "./dist/index.js"
    	}
    }
  2. /sv export (for packages that have other functionality):

    {
    	"exports": {
    		".": "./dist/main.js",
    		"./sv": "./dist/addon.js"
    	}
    }

Naming conventions

  • Scoped packages: Use @your-org/sv as the package name. Users can then install with just npx sv add @your-org.
  • Regular packages: Any name works. Users install with npx sv add your-package-name.

Version compatibility

Your add-on should specify the minimum sv version it requires in package.json. If a user’s sv version has a different major version than what your add-on was built for, they will see a compatibility warning.

Edit this page on GitHub llms.txt

previous next