Skip to content

Commit 295e7cf

Browse files
committed
feat: community add-ons - rebase 2, electric boogaloo
Scope check, peerDep enforcement, zero deps, tsdown bundling, bye sv-add keyword.
1 parent 504bce9 commit 295e7cf

File tree

10 files changed

+90
-36
lines changed

10 files changed

+90
-36
lines changed

packages/sv-utils/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
},
3939
"keywords": [
4040
"sv",
41-
"sv-add",
4241
"svelte",
4342
"sveltekit"
4443
]

packages/sv/src/cli/create.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ async function createProject(cwd: ProjectPath, options: Options) {
263263
const parentDirName = path.basename(path.dirname(projectPath));
264264
const projectName = parentDirName.startsWith('@') ? `${parentDirName}/${basename}` : basename;
265265

266+
if (template === 'addon' && !projectName.startsWith('@')) {
267+
// At this stage, we don't support un-scoped add-ons
268+
// FYI: a demo exists for `npx sv add my-cool-addon`
269+
common.errorAndExit(
270+
`Community add-ons must be published under an npm org (e.g. ${color.command('@my-org/sv')}). Unscoped package names are not supported at this stage.`
271+
);
272+
}
273+
266274
if (template === 'addon' && options.add.length > 0) {
267275
common.errorAndExit(
268276
`The ${color.command('--add')} flag cannot be used with the ${color.command('addon')} template.`

packages/sv/src/cli/tests/cli.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ describe('cli', () => {
123123
// replace sv and sv-utils versions in package.json for tests
124124
const packageJsonPath = path.resolve(testOutputPath, 'package.json');
125125
const { data: packageJson } = parse.json(fs.readFileSync(packageJsonPath, 'utf-8'));
126-
packageJson.dependencies['sv'] = 'file:../../../..';
127-
packageJson.dependencies['@sveltejs/sv-utils'] = 'file:../../../../sv-utils';
126+
packageJson.peerDependencies['sv'] = 'file:../../../..';
127+
packageJson.devDependencies['sv'] = 'file:../../../..';
128+
packageJson.devDependencies['@sveltejs/sv-utils'] = 'file:../../../../sv-utils';
128129
fs.writeFileSync(
129130
packageJsonPath,
130131
JSON.stringify(packageJson, null, 3).replaceAll(' ', '\t')

packages/sv/src/cli/tests/snapshots/@my-org/sv/CONTRIBUTING.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,25 @@ Your `add-on` should:
2424
- export a function that returns a `defineAddon` object.
2525
- have a `package.json` with an `exports` field that points to the main entry point of the add-on.
2626

27-
## Sharing your add-on
27+
## Building
2828

29-
When you're ready to publish your add-on to npm, run:
29+
Your add-on is bundled with [tsdown](https://tsdown.dev/) into a single file in `dist/`. This bundles everything except `sv` (which is a peer dependency provided at runtime).
3030

31-
```shell
31+
```sh
32+
npm run build
33+
```
34+
35+
## Publishing
36+
37+
When you're ready to publish your add-on to npm:
38+
39+
```sh
3240
npm login
3341
npm publish
3442
```
3543

44+
> `prepublishOnly` will automatically run the build before publishing.
45+
3646
## Things to be aware of
3747

38-
Community add-ons are **not permitted** to have any external dependencies outside of `sv`. If the use of a dependency is absolutely necessary, then they can be bundled using a bundler of your choosing (e.g. Rollup, Rolldown, tsup, etc.).
48+
Community add-ons must have `sv` as a `peerDependency` and should **not** have any `dependencies`. Everything else (including `@sveltejs/sv-utils`) is bundled at build time by tsdown.

packages/sv/src/cli/tests/snapshots/@my-org/sv/package.json

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,37 @@
88
"demo-create": "sv create demo --types ts --template minimal --no-add-ons --no-install",
99
"demo-add": "sv add file:../ --cwd demo --no-git-check --no-install",
1010
"demo-add:ci": "sv add file:../=who:you --cwd demo --no-git-check --no-download-check --no-install",
11+
"build": "tsdown",
12+
"prepublishOnly": "npm run build",
1113
"test": "vitest run"
1214
},
1315
"files": [
14-
"src",
15-
"!src/**/*.test.*"
16+
"dist"
1617
],
1718
"exports": {
1819
".": {
1920
"default": "./src/index.js"
2021
}
2122
},
22-
"dependencies": {
23-
"@sveltejs/sv-utils": "latest",
23+
"publishConfig": {
24+
"access": "public",
25+
"exports": {
26+
".": {
27+
"default": "./dist/index.js"
28+
}
29+
}
30+
},
31+
"peerDependencies": {
2432
"sv": "latest"
2533
},
2634
"devDependencies": {
2735
"@playwright/test": "^1.58.2",
36+
"@sveltejs/sv-utils": "latest",
37+
"sv": "latest",
38+
"tsdown": "^0.21.4",
2839
"vitest": "^4.1.0"
2940
},
3041
"keywords": [
3142
"sv-add"
32-
],
33-
"publishConfig": {
34-
"directory": "dist",
35-
"access": "public"
36-
}
43+
]
3744
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from 'tsdown';
2+
3+
export default defineConfig({
4+
entry: ['src/index.js'],
5+
format: 'esm'
6+
});

packages/sv/src/core/fetch-packages.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,21 @@ import type { AddonDefinition, AddonReference } from './config.ts';
1414
const NODE_MODULES = fileURLToPath(new URL('../../node_modules', import.meta.url));
1515

1616
function verifyPackage(addonPkg: Record<string, any>, specifier: string): string | undefined {
17-
// We should look only for dependencies, not devDependencies or peerDependencies
17+
const peerDeps = { ...addonPkg.peerDependencies };
1818
const deps = { ...addonPkg.dependencies };
1919

20-
// valid addons should always have a dependency on `sv`
21-
const addonSvVersion = deps['sv'];
20+
// valid addons should always have `sv` as a peerDependency
21+
const addonSvVersion = peerDeps['sv'];
2222
if (!addonSvVersion) {
2323
throw new Error(
24-
`Invalid add-on package specified: '${specifier}' is missing a dependency on 'sv' in its 'package.json'`
24+
`Invalid add-on package specified: '${specifier}' is missing 'sv' in its 'peerDependencies'`
2525
);
2626
}
2727

28-
// addons should never have any external dependencies outside of `sv` and `@sveltejs/sv-utils`
29-
for (const dep of Object.keys(deps)) {
30-
if (dep === 'sv' || dep === '@sveltejs/sv-utils') continue;
28+
// addons should not have any dependencies (everything should be bundled)
29+
if (Object.keys(deps).length > 0) {
3130
throw new Error(
32-
`Invalid add-on package detected: '${specifier}'\nCommunity addons should not have any external 'dependencies' besides 'sv'. Consider bundling your dependencies if they are necessary`
31+
`Invalid add-on package detected: '${specifier}'\nCommunity add-ons should not have any 'dependencies'. Use 'peerDependencies' for 'sv' and bundle everything else`
3332
);
3433
}
3534

packages/sv/src/create/shared/+addon/CONTRIBUTING.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,25 @@ Your `add-on` should:
2424
- export a function that returns a `defineAddon` object.
2525
- have a `package.json` with an `exports` field that points to the main entry point of the add-on.
2626

27-
## Sharing your add-on
27+
## Building
2828

29-
When you're ready to publish your add-on to npm, run:
29+
Your add-on is bundled with [tsdown](https://tsdown.dev/) into a single file in `dist/`. This bundles everything except `sv` (which is a peer dependency provided at runtime).
3030

31-
```shell
31+
```sh
32+
npm run build
33+
```
34+
35+
## Publishing
36+
37+
When you're ready to publish your add-on to npm:
38+
39+
```sh
3240
npm login
3341
npm publish
3442
```
3543

44+
> `prepublishOnly` will automatically run the build before publishing.
45+
3646
## Things to be aware of
3747

38-
Community add-ons are **not permitted** to have any external dependencies outside of `sv`. If the use of a dependency is absolutely necessary, then they can be bundled using a bundler of your choosing (e.g. Rollup, Rolldown, tsup, etc.).
48+
Community add-ons must have `sv` as a `peerDependency` and should **not** have any `dependencies`. Everything else (including `@sveltejs/sv-utils`) is bundled at build time by tsdown.

packages/sv/src/create/templates/addon/package.template.json

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,34 @@
88
"demo-create": "sv create demo --types ts --template minimal --no-add-ons --no-install",
99
"demo-add": "sv add file:../ --cwd demo --no-git-check --no-install",
1010
"demo-add:ci": "sv add file:../=who:you --cwd demo --no-git-check --no-download-check --no-install",
11+
"build": "tsdown",
12+
"prepublishOnly": "npm run build",
1113
"test": "vitest run"
1214
},
13-
"files": ["src", "!src/**/*.test.*"],
15+
"files": ["dist"],
1416
"exports": {
1517
".": {
1618
"default": "./src/index.js"
1719
}
1820
},
19-
"dependencies": {
20-
"@sveltejs/sv-utils": "workspace:*",
21+
"publishConfig": {
22+
"access": "public",
23+
"exports": {
24+
".": {
25+
"default": "./dist/index.js"
26+
}
27+
}
28+
},
29+
"peerDependencies": {
2130
"sv": "workspace:*"
2231
},
2332
"devDependencies": {
33+
"sv": "workspace:*",
34+
"@sveltejs/sv-utils": "workspace:*",
2435
"@playwright/test": "^1.58.2",
2536
"@types/node": "^25.2.1",
37+
"tsdown": "^0.21.4",
2638
"vitest": "^4.1.0"
2739
},
28-
"keywords": ["sv-add"],
29-
"publishConfig": {
30-
"directory": "dist",
31-
"access": "public"
32-
}
40+
"keywords": ["sv-add"]
3341
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from 'tsdown';
2+
3+
export default defineConfig({
4+
entry: ['src/index.js'],
5+
format: 'esm'
6+
});

0 commit comments

Comments
 (0)