From 849b771ac9d0a4b8d0542172bcf0da84cce26eb0 Mon Sep 17 00:00:00 2001 From: neverland Date: Sun, 9 Aug 2026 08:44:35 +0800 Subject: [PATCH] feat(create-rstack): add Svelte library templates --- packages/create-rstack/README.md | 2 + packages/create-rstack/src/index.ts | 3 ++ .../template-lib-svelte-js/AGENTS.md | 14 ++++++ .../template-lib-svelte-js/README.md | 40 ++++++++++++++++ .../template-lib-svelte-js/package.json | 35 ++++++++++++++ .../template-lib-svelte-js/rstack.config.js | 34 ++++++++++++++ .../template-lib-svelte-js/src/Button.svelte | 24 ++++++++++ .../template-lib-svelte-js/src/button.css | 34 ++++++++++++++ .../template-lib-svelte-js/src/index.js | 1 + .../tests/index.test.js | 19 ++++++++ .../template-lib-svelte-ts/AGENTS.md | 14 ++++++ .../template-lib-svelte-ts/README.md | 40 ++++++++++++++++ .../template-lib-svelte-ts/package.json | 41 +++++++++++++++++ .../template-lib-svelte-ts/rstack.config.ts | 34 ++++++++++++++ .../scripts/rslib-plugin-svelte-dts.ts | 46 +++++++++++++++++++ .../template-lib-svelte-ts/src/Button.svelte | 34 ++++++++++++++ .../template-lib-svelte-ts/src/button.css | 34 ++++++++++++++ .../template-lib-svelte-ts/src/index.ts | 1 + .../tests/index.test.ts | 19 ++++++++ .../tests/tsconfig.json | 7 +++ .../template-lib-svelte-ts/tsconfig.json | 25 ++++++++++ packages/create-rstack/tests/create.test.ts | 12 +++++ 22 files changed, 513 insertions(+) create mode 100644 packages/create-rstack/template-lib-svelte-js/AGENTS.md create mode 100644 packages/create-rstack/template-lib-svelte-js/README.md create mode 100644 packages/create-rstack/template-lib-svelte-js/package.json create mode 100644 packages/create-rstack/template-lib-svelte-js/rstack.config.js create mode 100644 packages/create-rstack/template-lib-svelte-js/src/Button.svelte create mode 100644 packages/create-rstack/template-lib-svelte-js/src/button.css create mode 100644 packages/create-rstack/template-lib-svelte-js/src/index.js create mode 100644 packages/create-rstack/template-lib-svelte-js/tests/index.test.js create mode 100644 packages/create-rstack/template-lib-svelte-ts/AGENTS.md create mode 100644 packages/create-rstack/template-lib-svelte-ts/README.md create mode 100644 packages/create-rstack/template-lib-svelte-ts/package.json create mode 100644 packages/create-rstack/template-lib-svelte-ts/rstack.config.ts create mode 100644 packages/create-rstack/template-lib-svelte-ts/scripts/rslib-plugin-svelte-dts.ts create mode 100644 packages/create-rstack/template-lib-svelte-ts/src/Button.svelte create mode 100644 packages/create-rstack/template-lib-svelte-ts/src/button.css create mode 100644 packages/create-rstack/template-lib-svelte-ts/src/index.ts create mode 100644 packages/create-rstack/template-lib-svelte-ts/tests/index.test.ts create mode 100644 packages/create-rstack/template-lib-svelte-ts/tests/tsconfig.json create mode 100644 packages/create-rstack/template-lib-svelte-ts/tsconfig.json diff --git a/packages/create-rstack/README.md b/packages/create-rstack/README.md index 21ff6e9..235a4c6 100644 --- a/packages/create-rstack/README.md +++ b/packages/create-rstack/README.md @@ -41,6 +41,8 @@ npx create-rstack -d my-project -t app-vanilla-ts - `lib-react-ts` - TypeScript React library - `lib-vue-js` - JavaScript Vue library - `lib-vue-ts` - TypeScript Vue library +- `lib-svelte-js` - JavaScript Svelte library +- `lib-svelte-ts` - TypeScript Svelte library - `lib-solid-js` - JavaScript Solid library - `lib-solid-ts` - TypeScript Solid library - `doc-basic` - Basic documentation site diff --git a/packages/create-rstack/src/index.ts b/packages/create-rstack/src/index.ts index 6cbb3a9..a8abeee 100644 --- a/packages/create-rstack/src/index.ts +++ b/packages/create-rstack/src/index.ts @@ -84,6 +84,7 @@ const getTemplateName = async ({ template }: Argv): Promise => { { value: 'node', label: 'Node.js' }, { value: 'react', label: 'React' }, { value: 'vue', label: 'Vue' }, + { value: 'svelte', label: 'Svelte' }, { value: 'solid', label: 'Solid' }, ], }), @@ -126,6 +127,8 @@ await create({ 'lib-react-ts', 'lib-vue-js', 'lib-vue-ts', + 'lib-svelte-js', + 'lib-svelte-ts', 'lib-solid-js', 'lib-solid-ts', 'doc-basic', diff --git a/packages/create-rstack/template-lib-svelte-js/AGENTS.md b/packages/create-rstack/template-lib-svelte-js/AGENTS.md new file mode 100644 index 0000000..234cc72 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/AGENTS.md @@ -0,0 +1,14 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run build` - Build the library for production +- `{{ packageManager }} run dev` - Rebuild the library when source files change +- `{{ packageManager }} run test` - Run tests +- `{{ packageManager }} run test:watch` - Run tests in watch mode + +## Docs + +- Rslib: https://rslib.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt +- Rstest: https://rstest.rs/llms.txt diff --git a/packages/create-rstack/template-lib-svelte-js/README.md b/packages/create-rstack/template-lib-svelte-js/README.md new file mode 100644 index 0000000..ab4b692 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/README.md @@ -0,0 +1,40 @@ +# Rstack library + +## Setup + +Install the dependencies: + +```bash +{{ packageManager }} install +``` + +## Get started + +Build the library: + +```bash +{{ packageManager }} run build +``` + +Build the library in watch mode: + +```bash +{{ packageManager }} run dev +``` + +Run tests: + +```bash +{{ packageManager }} run test +``` + +Run tests in watch mode: + +```bash +{{ packageManager }} run test:watch +``` + +## Learn more + +- [Rstack documentation](https://rstack.rs) +- [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-svelte-js/package.json b/packages/create-rstack/template-lib-svelte-js/package.json new file mode 100644 index 0000000..802ad93 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/package.json @@ -0,0 +1,35 @@ +{ + "name": "rstack-lib-svelte-js", + "version": "0.0.0", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "rs lib", + "dev": "rs lib --watch", + "format": "rs fmt", + "lint": "rs lint", + "test": "rs test", + "test:watch": "rs test --watch" + }, + "devDependencies": { + "@rsbuild/plugin-svelte": "^2.0.1", + "happy-dom": "^20.11.1", + "prettier-plugin-svelte": "^4.1.1", + "rstack": "^0.3.5", + "svelte": "^5.56.8" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/create-rstack/template-lib-svelte-js/rstack.config.js b/packages/create-rstack/template-lib-svelte-js/rstack.config.js new file mode 100644 index 0000000..c8393a7 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/rstack.config.js @@ -0,0 +1,34 @@ +// @ts-check +// Rstack configuration guide: https://rstack.rs/config +import { define } from 'rstack'; + +define.lib(async () => { + const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); + + return { + bundle: false, + source: { + entry: { + index: ['./src/**'], + }, + }, + output: { + target: 'web', + }, + plugins: [pluginSvelte()], + }; +}); + +define.test({ + testEnvironment: 'happy-dom', +}); + +define.lint(async () => { + const { js } = await import('rstack/lint'); + + return [js.configs.recommended]; +}); + +define.fmt({ + plugins: ['prettier-plugin-svelte'], +}); diff --git a/packages/create-rstack/template-lib-svelte-js/src/Button.svelte b/packages/create-rstack/template-lib-svelte-js/src/Button.svelte new file mode 100644 index 0000000..6a7eb75 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/src/Button.svelte @@ -0,0 +1,24 @@ + + + diff --git a/packages/create-rstack/template-lib-svelte-js/src/button.css b/packages/create-rstack/template-lib-svelte-js/src/button.css new file mode 100644 index 0000000..257ef46 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/src/button.css @@ -0,0 +1,34 @@ +.demo-button { + font-weight: 700; + border: 0; + border-radius: 3em; + cursor: pointer; + display: inline-block; + line-height: 1; +} + +.demo-button--primary { + color: white; + background-color: #1ea7fd; +} + +.demo-button--secondary { + color: #333; + background-color: transparent; + box-shadow: rgba(0, 0, 0, 0.15) 0 0 0 1px inset; +} + +.demo-button--small { + font-size: 12px; + padding: 10px 16px; +} + +.demo-button--medium { + font-size: 14px; + padding: 11px 20px; +} + +.demo-button--large { + font-size: 16px; + padding: 12px 24px; +} diff --git a/packages/create-rstack/template-lib-svelte-js/src/index.js b/packages/create-rstack/template-lib-svelte-js/src/index.js new file mode 100644 index 0000000..ae34e39 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/src/index.js @@ -0,0 +1 @@ +export { default as Button } from './Button.svelte'; diff --git a/packages/create-rstack/template-lib-svelte-js/tests/index.test.js b/packages/create-rstack/template-lib-svelte-js/tests/index.test.js new file mode 100644 index 0000000..cfcfa13 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-js/tests/index.test.js @@ -0,0 +1,19 @@ +import { expect, test } from 'rstack/test'; +import { mount, unmount } from 'svelte'; +import Button from '../src/Button.svelte'; + +test('The button should render the default label', () => { + const target = document.createElement('div'); + document.body.append(target); + const component = mount(Button, { target }); + const button = target.querySelector('button'); + + if (!button) { + throw new Error('Expected button to be rendered'); + } + + expect(button.textContent).toBe('Demo Button'); + + unmount(component); + target.remove(); +}); diff --git a/packages/create-rstack/template-lib-svelte-ts/AGENTS.md b/packages/create-rstack/template-lib-svelte-ts/AGENTS.md new file mode 100644 index 0000000..234cc72 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/AGENTS.md @@ -0,0 +1,14 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run build` - Build the library for production +- `{{ packageManager }} run dev` - Rebuild the library when source files change +- `{{ packageManager }} run test` - Run tests +- `{{ packageManager }} run test:watch` - Run tests in watch mode + +## Docs + +- Rslib: https://rslib.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt +- Rstest: https://rstest.rs/llms.txt diff --git a/packages/create-rstack/template-lib-svelte-ts/README.md b/packages/create-rstack/template-lib-svelte-ts/README.md new file mode 100644 index 0000000..ab4b692 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/README.md @@ -0,0 +1,40 @@ +# Rstack library + +## Setup + +Install the dependencies: + +```bash +{{ packageManager }} install +``` + +## Get started + +Build the library: + +```bash +{{ packageManager }} run build +``` + +Build the library in watch mode: + +```bash +{{ packageManager }} run dev +``` + +Run tests: + +```bash +{{ packageManager }} run test +``` + +Run tests in watch mode: + +```bash +{{ packageManager }} run test:watch +``` + +## Learn more + +- [Rstack documentation](https://rstack.rs) +- [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-svelte-ts/package.json b/packages/create-rstack/template-lib-svelte-ts/package.json new file mode 100644 index 0000000..2c6022c --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/package.json @@ -0,0 +1,41 @@ +{ + "name": "rstack-lib-svelte-ts", + "version": "0.0.0", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "types": "./dist/index.d.ts", + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "svelte-check && rs lib", + "dev": "rs lib --watch", + "format": "rs fmt", + "lint": "rs lint", + "test": "rs test", + "test:watch": "rs test --watch" + }, + "devDependencies": { + "@rsbuild/plugin-svelte": "^2.0.1", + "@types/node": "^24.13.3", + "happy-dom": "^20.11.1", + "prettier-plugin-svelte": "^4.1.1", + "rstack": "^0.3.5", + "svelte": "^5.56.8", + "svelte-check": "^4.7.4", + "svelte2tsx": "^0.7.59", + "typescript": "^6.0.3" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts new file mode 100644 index 0000000..463c0e5 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -0,0 +1,34 @@ +// Rstack configuration guide: https://rstack.rs/config +import { define } from 'rstack'; +import { svelteDtsPlugin } from './scripts/rslib-plugin-svelte-dts.ts'; + +define.lib(async () => { + const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); + + return { + bundle: false, + source: { + entry: { + index: ['./src/**'], + }, + }, + output: { + target: 'web', + }, + plugins: [pluginSvelte(), svelteDtsPlugin()], + }; +}); + +define.test({ + testEnvironment: 'happy-dom', +}); + +define.lint(async () => { + const { js, ts } = await import('rstack/lint'); + + return [js.configs.recommended, ts.configs.recommended]; +}); + +define.fmt({ + plugins: ['prettier-plugin-svelte'], +}); diff --git a/packages/create-rstack/template-lib-svelte-ts/scripts/rslib-plugin-svelte-dts.ts b/packages/create-rstack/template-lib-svelte-ts/scripts/rslib-plugin-svelte-dts.ts new file mode 100644 index 0000000..34560f8 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/scripts/rslib-plugin-svelte-dts.ts @@ -0,0 +1,46 @@ +import type { RsbuildPlugin } from 'rstack/lib'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { emitDts, type EmitDtsConfig } from 'svelte2tsx'; + +type SvelteDtsPluginOptions = Partial; + +const resolveProjectPath = (rootPath: string, path: string): string => resolve(rootPath, path); + +export function svelteDtsPlugin(options: SvelteDtsPluginOptions = {}): RsbuildPlugin { + return { + name: 'rslib-plugin-svelte-dts', + setup(api) { + api.onAfterBuild(async ({ isWatch }) => { + if (!isWatch) { + api.logger.start('generating declaration files...'); + } + + const { declarationDir = './dist', libRoot = './src', tsconfig } = options; + const rootPath = api.context.rootPath; + const tsconfigPath = resolveProjectPath( + rootPath, + tsconfig ?? api.getNormalizedConfig().source.tsconfigPath ?? './tsconfig.json', + ); + const svelteShimsPath = options.svelteShimsPath + ? resolveProjectPath(rootPath, options.svelteShimsPath) + : fileURLToPath(import.meta.resolve('svelte2tsx/svelte-shims-v4.d.ts')); + + try { + await emitDts({ + declarationDir: resolveProjectPath(rootPath, declarationDir), + svelteShimsPath, + libRoot: resolveProjectPath(rootPath, libRoot), + tsconfig: tsconfigPath, + }); + + api.logger.ready('declaration files generated with svelte2tsx.'); + } catch (error) { + api.logger.error('Failed to generate declaration files with svelte2tsx.'); + api.logger.error(error); + throw error; + } + }); + }, + }; +} diff --git a/packages/create-rstack/template-lib-svelte-ts/src/Button.svelte b/packages/create-rstack/template-lib-svelte-ts/src/Button.svelte new file mode 100644 index 0000000..24a4391 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/src/Button.svelte @@ -0,0 +1,34 @@ + + + diff --git a/packages/create-rstack/template-lib-svelte-ts/src/button.css b/packages/create-rstack/template-lib-svelte-ts/src/button.css new file mode 100644 index 0000000..257ef46 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/src/button.css @@ -0,0 +1,34 @@ +.demo-button { + font-weight: 700; + border: 0; + border-radius: 3em; + cursor: pointer; + display: inline-block; + line-height: 1; +} + +.demo-button--primary { + color: white; + background-color: #1ea7fd; +} + +.demo-button--secondary { + color: #333; + background-color: transparent; + box-shadow: rgba(0, 0, 0, 0.15) 0 0 0 1px inset; +} + +.demo-button--small { + font-size: 12px; + padding: 10px 16px; +} + +.demo-button--medium { + font-size: 14px; + padding: 11px 20px; +} + +.demo-button--large { + font-size: 16px; + padding: 12px 24px; +} diff --git a/packages/create-rstack/template-lib-svelte-ts/src/index.ts b/packages/create-rstack/template-lib-svelte-ts/src/index.ts new file mode 100644 index 0000000..ae34e39 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/src/index.ts @@ -0,0 +1 @@ +export { default as Button } from './Button.svelte'; diff --git a/packages/create-rstack/template-lib-svelte-ts/tests/index.test.ts b/packages/create-rstack/template-lib-svelte-ts/tests/index.test.ts new file mode 100644 index 0000000..cfcfa13 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/tests/index.test.ts @@ -0,0 +1,19 @@ +import { expect, test } from 'rstack/test'; +import { mount, unmount } from 'svelte'; +import Button from '../src/Button.svelte'; + +test('The button should render the default label', () => { + const target = document.createElement('div'); + document.body.append(target); + const component = mount(Button, { target }); + const button = target.querySelector('button'); + + if (!button) { + throw new Error('Expected button to be rendered'); + } + + expect(button.textContent).toBe('Demo Button'); + + unmount(component); + target.remove(); +}); diff --git a/packages/create-rstack/template-lib-svelte-ts/tests/tsconfig.json b/packages/create-rstack/template-lib-svelte-ts/tests/tsconfig.json new file mode 100644 index 0000000..9148491 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/tests/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": ".." + }, + "include": ["./"] +} diff --git a/packages/create-rstack/template-lib-svelte-ts/tsconfig.json b/packages/create-rstack/template-lib-svelte-ts/tsconfig.json new file mode 100644 index 0000000..e69b020 --- /dev/null +++ b/packages/create-rstack/template-lib-svelte-ts/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "lib": ["DOM", "ES2022"], + "target": "ES2022", + "declaration": true, + "emitDeclarationOnly": true, + "isolatedModules": true, + "skipLibCheck": true, + "types": ["rstack/types", "node", "svelte"], + "useDefineForClassFields": true, + + /* modules */ + "module": "preserve", + "moduleDetection": "force", + "moduleResolution": "bundler", + "verbatimModuleSyntax": true, + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + + /* type checking */ + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "include": ["src", "scripts", "*.config.ts"] +} diff --git a/packages/create-rstack/tests/create.test.ts b/packages/create-rstack/tests/create.test.ts index f89a62f..5866a40 100644 --- a/packages/create-rstack/tests/create.test.ts +++ b/packages/create-rstack/tests/create.test.ts @@ -232,6 +232,18 @@ test.each([ sourceExtension: 'ts', hasTypeScript: true, }, + { + template: 'lib-svelte-js', + configExtension: 'js', + sourceExtension: 'js', + hasTypeScript: false, + }, + { + template: 'lib-svelte-ts', + configExtension: 'ts', + sourceExtension: 'ts', + hasTypeScript: true, + }, { template: 'lib-solid-js', configExtension: 'js',