diff --git a/.changeset/svelte-devtools-adapter.md b/.changeset/svelte-devtools-adapter.md new file mode 100644 index 00000000..4f648eb4 --- /dev/null +++ b/.changeset/svelte-devtools-adapter.md @@ -0,0 +1,6 @@ +--- +'@tanstack/svelte-devtools': minor +'@tanstack/devtools-utils': minor +--- + +feat: add Svelte 5 adapter and devtools-utils Svelte factories diff --git a/docs/config.json b/docs/config.json index b255291d..b1cb2b03 100644 --- a/docs/config.json +++ b/docs/config.json @@ -45,6 +45,13 @@ { "label": "Basic Setup", "to": "framework/vue/basic-setup" }, { "label": "Vue Adapter", "to": "framework/vue/adapter" } ] + }, + { + "label": "svelte", + "children": [ + { "label": "Basic Setup", "to": "framework/svelte/basic-setup" }, + { "label": "Svelte Adapter", "to": "framework/svelte/adapter" } + ] } ] }, @@ -89,6 +96,12 @@ "children": [ { "label": "Custom Plugins", "to": "framework/vue/guides/custom-plugins" } ] + }, + { + "label": "svelte", + "children": [ + { "label": "Custom Plugins", "to": "framework/svelte/guides/custom-plugins" } + ] } ] }, @@ -121,6 +134,12 @@ "children": [ { "label": "Vue Reference", "to": "framework/vue/reference/index" } ] + }, + { + "label": "svelte", + "children": [ + { "label": "Svelte Reference", "to": "framework/svelte/reference/index" } + ] } ] }, diff --git a/docs/devtools-utils.md b/docs/devtools-utils.md index 5f581c20..4b643111 100644 --- a/docs/devtools-utils.md +++ b/docs/devtools-utils.md @@ -21,7 +21,7 @@ interface DevtoolsPanelProps { } ``` -> The Vue variant additionally accepts `'system'` as a theme value. +> The Vue and Svelte variants additionally accept `'system'` as a theme value. Import it from the framework-specific subpath: @@ -37,6 +37,9 @@ import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact' // Vue import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue' + +// Svelte +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/svelte' ``` ## React @@ -252,6 +255,49 @@ const [MyPanel, NoOpPanel] = createVuePanel(MyDevtoolsCore) The panel component accepts `theme` and `devtoolsProps` as props. It mounts the core instance into a `div` element on `onMounted` and calls `unmount()` on `onUnmounted`. +## Svelte + +### createSveltePlugin + +The Svelte factory takes a `name` string and a Svelte component as separate arguments, similar to the Vue API. + +**Signature:** + +```ts +function createSveltePlugin( + name: string, + component: Component, +): readonly [Plugin, NoOpPlugin] +``` + +**Usage:** + +```ts +import { createSveltePlugin } from '@tanstack/devtools-utils/svelte' +import MyStorePanel from './MyStorePanel.svelte' + +const [MyPlugin, NoOpPlugin] = createSveltePlugin('My Store', MyStorePanel) +``` + +The returned functions: + +- **`Plugin(props?)`** -- returns `{ name, component, props }` where `component` is your Svelte component. +- **`NoOpPlugin(props?)`** -- returns `{ name, component: NoOpComponent, props }` where the component renders nothing visible. + +Both accept an optional `props` object that gets forwarded to the component on mount. + +### createSveltePanel + +For class-based devtools cores, Svelte provides `createSveltePanel`. It creates a wrapper that handles mounting and unmounting the core class: + +```ts +import { createSveltePanel } from '@tanstack/devtools-utils/svelte' + +const [MyPanel, NoOpPanel] = createSveltePanel(MyDevtoolsCore) +``` + +The panel accepts `theme` and `devtoolsProps` props. It creates a `div` element, mounts the core instance into it, and calls `unmount()` on cleanup. + ## When to Use Factories vs Manual Plugin Objects **Use the factories** when you are building a reusable library plugin that will be published as a package. The factories ensure: diff --git a/docs/framework/svelte/adapter.md b/docs/framework/svelte/adapter.md new file mode 100644 index 00000000..bc77594a --- /dev/null +++ b/docs/framework/svelte/adapter.md @@ -0,0 +1,76 @@ +--- +title: TanStack Devtools Svelte Adapter +id: adapter +--- + +The Svelte adapter wraps `TanStackDevtoolsCore` in a Svelte 5 component, using Svelte's `mount()` and `unmount()` APIs to dynamically render plugins into the correct DOM containers managed by the devtools shell. + +## Installation + +```sh +npm install @tanstack/svelte-devtools +``` + +## Component Props + +The `TanStackDevtools` component accepts the following props, defined by the `TanStackDevtoolsSvelteInit` interface: + +| Prop | Type | Description | +| --- | --- | --- | +| `plugins` | `TanStackDevtoolsSveltePlugin[]` | Array of plugins to render inside the devtools panel. | +| `config` | `Partial` | Configuration for the devtools shell. Sets the initial state on first load; afterwards settings are persisted in local storage. | +| `eventBusConfig` | `ClientEventBusConfig` | Configuration for the TanStack Devtools client event bus. | + +## Plugin Type + +Each plugin in the `plugins` array must conform to the `TanStackDevtoolsSveltePlugin` type: + +```ts +type TanStackDevtoolsSveltePlugin = { + id?: string + component: Component + name: string | Component + props?: Record + defaultOpen?: boolean +} +``` + +| Field | Type | Description | +| --- | --- | --- | +| `id` | `string` (optional) | Unique identifier for the plugin. | +| `component` | `Component` | The Svelte component to render as the plugin panel content. | +| `name` | `string \| Component` | Display name for the tab title. Can be a plain string or a Svelte component for custom rendering. | +| `props` | `Record` (optional) | Additional props passed to the plugin component on mount. | +| `defaultOpen` | `boolean` (optional) | Whether this plugin tab should be open by default. | + +## Key Difference from Other Frameworks + +The Svelte adapter uses `component` (a Svelte component reference) instead of `render` (a JSX element) in plugin definitions. Props are provided through the `props` field and passed to the component via Svelte's `mount()` API, rather than being embedded directly in a JSX expression. + +```svelte + + + + +``` + +## Exports + +The `@tanstack/svelte-devtools` package exports: + +- **`TanStackDevtools`** -- The main Svelte component that renders the devtools panel. +- **`TanStackDevtoolsSveltePlugin`** (type) -- The type for plugin definitions. +- **`TanStackDevtoolsSvelteInit`** (type) -- The props interface for the `TanStackDevtools` component. + +The package depends on `@tanstack/devtools` (the core package), which provides `TanStackDevtoolsCore`, `TanStackDevtoolsConfig`, `ClientEventBusConfig`, and other core utilities. diff --git a/docs/framework/svelte/basic-setup.md b/docs/framework/svelte/basic-setup.md new file mode 100644 index 00000000..8f3aa1d8 --- /dev/null +++ b/docs/framework/svelte/basic-setup.md @@ -0,0 +1,53 @@ +--- +title: Basic setup +id: basic-setup +--- + +TanStack Devtools provides you with an easy-to-use and modular client that allows you to compose multiple devtools into one easy-to-use panel. + +## Setup + +Install the [TanStack Devtools](https://www.npmjs.com/package/@tanstack/svelte-devtools) library. This will install the devtools core as well as provide you with the Svelte-specific adapter. + +```bash +npm i @tanstack/svelte-devtools +``` + +Next, in the root of your application, import the `TanStackDevtools` component from `@tanstack/svelte-devtools` and add it to your template. + +```svelte + + +
+ +
+ +``` + +Import the desired devtools and provide them to the `TanStackDevtools` component via the `plugins` prop along with a label for the menu. + +```svelte + + +
+ +
+ +``` + +> Note: The Svelte adapter uses `component` (a Svelte component reference) instead of `render` (a JSX element) in plugin definitions. Additional props can be provided via the `props` field and are passed to the component on mount. + +Finally, add any additional configuration you desire to the `TanStackDevtools` component. More information can be found under the [TanStack Devtools Configuration](../../configuration) section. diff --git a/docs/framework/svelte/guides/custom-plugins.md b/docs/framework/svelte/guides/custom-plugins.md new file mode 100644 index 00000000..0206752e --- /dev/null +++ b/docs/framework/svelte/guides/custom-plugins.md @@ -0,0 +1,203 @@ +--- +title: Custom plugins +id: custom-plugins +--- + +TanStack devtools allows you to create your own custom plugins by emitting and listening to our event bus. + +## Prerequisite + +This guide will walk you through a simple example where our library is a counter with a count history. A working example can be found in our [custom-plugin example](https://tanstack.com/devtools/latest/docs/framework/react/examples/custom-devtools). + +This is our library code: + +counter.ts +```tsx +export function createCounter() { + let count = 0 + const history = [] + + return { + getCount: () => count, + increment: () => { + count++ + history.push(count) + }, + decrement: () => { + count-- + history.push(count) + }, + }; +} +``` + +## Event Client Setup + +Install the [TanStack Devtools Event Client](https://www.npmjs.com/package/@tanstack/devtools-event-client) utils. + +```bash +npm i @tanstack/devtools-event-client +``` + +First you will need to setup the `EventClient`. + +eventClient.ts +```tsx +import { EventClient } from '@tanstack/devtools-event-client' + + +type EventMap = { + // The key is the event suffix only — the pluginId is prepended automatically by EventClient + // The value is the expected type of the event payload + 'counter-state': { count: number, history: number[] } +} + +class CustomEventClient extends EventClient { + constructor() { + super({ + // The pluginId is prepended to event map keys when emitting/listening + pluginId: 'custom-devtools', + }) + } +} + +// This is where the magic happens, it'll be used throughout your application. +export const DevtoolsEventClient = new CustomEventClient() +``` + +## Event Client Integration + +Now we need to hook our `EventClient` into the application code. This can be done in many way's, a useEffect that emits the current state, or a subscription to an observer, all that matters is that when you want to emit the current state you do the following. + +Our new library code will looks as follows: + +counter.ts +```tsx +import { DevtoolsEventClient } from './eventClient.ts' + +export function createCounter() { + let count = 0 + const history: Array = [] + + return { + getCount: () => count, + increment: () => { + count++ + history.push(count) + + // The emit eventSuffix must match that of the EventMap defined in eventClient.ts + DevtoolsEventClient.emit('counter-state', { + count, + history, + }) + }, + decrement: () => { + count-- + history.push(count) + + DevtoolsEventClient.emit('counter-state', { + count, + history, + }) + }, + } +} +``` + +> [!IMPORTANT] +> `EventClient` is framework agnostic so this process will be the same regardless of framework or even in vanilla JavaScript. + +## Consuming The Event Client + +Now we need to create our devtools panel. For Svelte, create a component that listens to events from the `EventClient` using Svelte 5 runes. + +DevtoolPanel.svelte +```svelte + + +
+
{state?.count}
+
{JSON.stringify(state?.history)}
+
+``` + +## Application Integration + +This step follows what's shown in [basic-setup](../basic-setup) for a more documented guide go check it out. + +App.svelte +```svelte + + +
+ +
+ +``` + +## Debugging + +Both the `TanStackDevtools` component and the TanStack `EventClient` come with built in debug mode which will log to the console the emitted event as well as the EventClient status. + +TanStackDevtools debugging mode can be activated like so: +```svelte + + + +``` + +Where as the EventClient's debug mode can be activated by: +```tsx +class CustomEventClient extends EventClient { + constructor() { + super({ + pluginId: 'custom-devtools', + debug: true, + }) + } +} +``` + +Activating the debug mode will log to the console the current events that emitter has emitted or listened to. The EventClient will have appended `[tanstack-devtools:${pluginId}]` and the client will have appended `[tanstack-devtools:client-bus]`. + +Heres an example of both: +``` +[tanstack-devtools:client-bus] Initializing client event bus + +[tanstack-devtools:custom-devtools-plugin] Registered event to bus custom-devtools:counter-state +``` diff --git a/docs/installation.md b/docs/installation.md index f1bb2766..eed71d8c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -48,6 +48,20 @@ npm install -D @tanstack/devtools-vite TanStack Devtools is compatible with Vue 3+ +## Svelte + +```sh +npm install -D @tanstack/svelte-devtools +``` + +The Vite plugin (`@tanstack/devtools-vite`) is optional for Svelte — it enables additional features like source inspection and console piping but isn't required for basic usage. + +```sh +npm install -D @tanstack/devtools-vite +``` + +TanStack Devtools is compatible with Svelte 5+ + ## Vanilla JS ```sh diff --git a/docs/plans/2026-03-04-svelte-devtools-design.md b/docs/plans/2026-03-04-svelte-devtools-design.md new file mode 100644 index 00000000..b7a8de1b --- /dev/null +++ b/docs/plans/2026-03-04-svelte-devtools-design.md @@ -0,0 +1,48 @@ +# Svelte Devtools Adapter Design + +## Goal + +Create `@tanstack/svelte-devtools` adapter package and extend `@tanstack/devtools-utils` with Svelte-specific factory functions, following the same patterns as existing React, Vue, and Angular adapters. + +## Target + +Svelte 5+ (runes, `mount`/`unmount` API from `'svelte'`) + +## Architecture + +### Adapter (`@tanstack/svelte-devtools`) + +A Svelte 5 component that wraps `TanStackDevtoolsCore`. Uses Svelte 5's imperative `mount()` / `unmount()` from `'svelte'` to render plugin components into the DOM containers provided by the core. + +**Plugin type:** +```ts +type TanStackDevtoolsSveltePlugin = { + id?: string + component: Component + name: string | Component + props?: Record + defaultOpen?: boolean +} +``` + +**Rendering flow:** +1. Core calls `render(el, theme)` → adapter calls `mount(SvelteComponent, { target: el, props: { theme, ...plugin.props } })` +2. Core calls `destroy(pluginId)` → adapter calls `unmount()` on stored component instances +3. Reactive updates via `$effect` watching props changes → calls `devtools.setConfig()` + +### devtools-utils (`@tanstack/devtools-utils/svelte`) + +- `createSveltePlugin(name, component)` → `[Plugin, NoOpPlugin]` tuple +- `createSveltePanel(CoreClass)` → `[Panel, NoOpPanel]` tuple + +### Build + +Vite with `@sveltejs/vite-plugin-svelte` for `.svelte` file compilation. Uses `tanstackViteConfig` consistent with other packages. + +## Documentation + +Following the same pattern as Vue/Angular: +- `docs/framework/svelte/basic-setup.md` +- `docs/framework/svelte/adapter.md` +- `docs/framework/svelte/guides/custom-plugins.md` +- Updates to `docs/config.json`, `docs/installation.md`, `docs/quick-start.md`, `docs/devtools-utils.md` diff --git a/docs/plans/2026-03-04-svelte-devtools-plan.md b/docs/plans/2026-03-04-svelte-devtools-plan.md new file mode 100644 index 00000000..c876e373 --- /dev/null +++ b/docs/plans/2026-03-04-svelte-devtools-plan.md @@ -0,0 +1,764 @@ +# Svelte Devtools Adapter Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Create `@tanstack/svelte-devtools` adapter package and extend `@tanstack/devtools-utils` with Svelte-specific factories, plus add documentation. + +**Architecture:** Svelte 5 component wrapping TanStackDevtoolsCore. Uses Svelte 5's imperative `mount()`/`unmount()` API to render plugin components into DOM containers. The devtools-utils subpath provides `createSveltePlugin` and `createSveltePanel` factory functions following the `[Plugin, NoOpPlugin]` tuple pattern. + +**Tech Stack:** Svelte 5, Vite, `@sveltejs/vite-plugin-svelte`, TypeScript + +--- + +### Task 1: Create svelte-devtools package scaffold + +**Files:** +- Create: `packages/svelte-devtools/package.json` +- Create: `packages/svelte-devtools/tsconfig.json` +- Create: `packages/svelte-devtools/eslint.config.js` +- Create: `packages/svelte-devtools/vite.config.ts` +- Modify: `package.json` (root — add override) + +**Step 1: Create package.json** + +```json +{ + "name": "@tanstack/svelte-devtools", + "version": "0.0.1", + "description": "TanStack Devtools is a set of tools for building advanced devtools for your Svelte application.", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/devtools.git", + "directory": "packages/svelte-devtools" + }, + "homepage": "https://tanstack.com/devtools", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "svelte", + "devtools" + ], + "type": "module", + "types": "dist/esm/index.d.ts", + "module": "dist/esm/index.js", + "svelte": "dist/esm/index.js", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + } + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "test:build": "publint --strict", + "build": "vite build" + }, + "dependencies": { + "@tanstack/devtools": "workspace:*" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0" + }, + "peerDependencies": { + "svelte": ">=5.0.0" + } +} +``` + +**Step 2: Create tsconfig.json** + +Reference pattern: `packages/vue-devtools/tsconfig.json` + +```json +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src", "eslint.config.js", "vite.config.ts", "tests"] +} +``` + +**Step 3: Create eslint.config.js** + +Reference pattern: `packages/vue-devtools/eslint.config.js` — Svelte uses `eslint-plugin-svelte`. + +```js +// @ts-check + +import pluginSvelte from 'eslint-plugin-svelte' +import rootConfig from '../../eslint.config.js' + +export default [ + ...rootConfig, + ...pluginSvelte.configs['flat/recommended'], +] +``` + +Note: Add `eslint-plugin-svelte` to devDependencies if needed. If eslint issues arise during testing, simplify to just `rootConfig`. + +**Step 4: Create vite.config.ts** + +Reference pattern: `packages/vue-devtools/vite.config.ts` — uses framework plugin + tanstackViteConfig with externalDeps. + +```ts +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import packageJson from './package.json' + +const config = defineConfig({ + plugins: [svelte() as any], + test: { + name: packageJson.name, + dir: './tests', + watch: false, + environment: 'jsdom', + globals: true, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/index.ts'], + srcDir: './src', + externalDeps: ['svelte'], + cjs: false, + }), +) +``` + +**Step 5: Add root override** + +In root `package.json`, add to `overrides`: +```json +"@tanstack/svelte-devtools": "workspace:*" +``` + +**Step 6: Run pnpm install and verify** + +Run: `pnpm install` +Expected: No errors + +**Step 7: Commit** + +```bash +git add packages/svelte-devtools/package.json packages/svelte-devtools/tsconfig.json packages/svelte-devtools/eslint.config.js packages/svelte-devtools/vite.config.ts package.json pnpm-lock.yaml +git commit -m "feat(svelte-devtools): scaffold package" +``` + +--- + +### Task 2: Create svelte-devtools types + +**Files:** +- Create: `packages/svelte-devtools/src/types.ts` + +**Step 1: Create types** + +Reference: `packages/vue-devtools/src/types.ts` — Vue uses `Component`, Svelte uses `Component` from `svelte`. + +```ts +import type { Component } from 'svelte' +import type { + ClientEventBusConfig, + TanStackDevtoolsConfig, +} from '@tanstack/devtools' + +export type TanStackDevtoolsSveltePlugin = { + id?: string + component: Component + name: string | Component + props?: Record + defaultOpen?: boolean +} + +export interface TanStackDevtoolsSvelteInit { + plugins?: Array + config?: Partial + eventBusConfig?: ClientEventBusConfig +} +``` + +**Step 2: Commit** + +```bash +git add packages/svelte-devtools/src/types.ts +git commit -m "feat(svelte-devtools): add type definitions" +``` + +--- + +### Task 3: Create svelte-devtools main component + +**Files:** +- Create: `packages/svelte-devtools/src/devtools.svelte.ts` + +**Key concepts:** +- Svelte 5 uses `mount(Component, { target, props })` and `unmount(instance)` from `'svelte'` +- The `.svelte.ts` extension enables Svelte 5 runes (`$state`, `$effect`) in plain TS files +- `TanStackDevtoolsCore` provides DOM containers, we mount Svelte components into them +- `PLUGIN_CONTAINER_ID` is used for destroy cleanup + +**Step 1: Create the devtools component** + +```ts +import { mount, unmount } from 'svelte' +import { PLUGIN_CONTAINER_ID, TanStackDevtoolsCore } from '@tanstack/devtools' +import type { Component } from 'svelte' +import type { TanStackDevtoolsPlugin } from '@tanstack/devtools' +import type { + TanStackDevtoolsSvelteInit, + TanStackDevtoolsSveltePlugin, +} from './types' + +type MountedComponent = ReturnType + +export class TanStackDevtoolsSvelteAdapter { + private devtools: TanStackDevtoolsCore | null = null + private mountedComponents: Array<{ instance: MountedComponent; containerId: string }> = [] + + mount(target: HTMLElement, init: TanStackDevtoolsSvelteInit) { + const pluginsMap = this.getPluginsMap(init.plugins) + + this.devtools = new TanStackDevtoolsCore({ + config: init.config, + eventBusConfig: init.eventBusConfig, + plugins: pluginsMap, + }) + + this.devtools.mount(target) + } + + update(init: TanStackDevtoolsSvelteInit) { + if (this.devtools) { + this.devtools.setConfig({ + config: init.config, + eventBusConfig: init.eventBusConfig, + plugins: this.getPluginsMap(init.plugins), + }) + } + } + + destroy() { + this.destroyAllComponents() + if (this.devtools) { + this.devtools.unmount() + this.devtools = null + } + } + + private getPluginsMap( + plugins?: Array, + ): Array { + if (!plugins) return [] + return plugins.map((plugin) => this.convertPlugin(plugin)) + } + + private convertPlugin( + plugin: TanStackDevtoolsSveltePlugin, + ): TanStackDevtoolsPlugin { + return { + id: plugin.id, + defaultOpen: plugin.defaultOpen, + name: + typeof plugin.name === 'string' + ? plugin.name + : (el, theme) => { + this.renderComponent(plugin.name as Component, el, { + theme, + ...(plugin.props ?? {}), + }) + }, + render: (el, theme) => { + this.renderComponent(plugin.component, el, { + theme, + ...(plugin.props ?? {}), + }) + }, + destroy: (pluginId) => { + this.destroyComponentsInContainer( + `${PLUGIN_CONTAINER_ID}-${pluginId}`, + ) + }, + } + } + + private renderComponent( + component: Component, + container: HTMLElement, + props: Record, + ) { + const instance = mount(component, { + target: container, + props, + }) + + const containerId = container.id || container.parentElement?.id || '' + this.mountedComponents.push({ instance, containerId }) + } + + private destroyComponentsInContainer(containerId: string) { + this.mountedComponents = this.mountedComponents.filter((entry) => { + if (entry.containerId === containerId) { + unmount(entry.instance) + return false + } + return true + }) + } + + private destroyAllComponents() { + for (const entry of this.mountedComponents) { + unmount(entry.instance) + } + this.mountedComponents = [] + } +} +``` + +**Step 2: Commit** + +```bash +git add packages/svelte-devtools/src/devtools.svelte.ts +git commit -m "feat(svelte-devtools): add core adapter class" +``` + +--- + +### Task 4: Create the Svelte wrapper component + +**Files:** +- Create: `packages/svelte-devtools/src/TanStackDevtools.svelte` + +This is the actual `.svelte` component users import. It wraps the adapter class with Svelte 5 runes for reactivity. + +**Step 1: Create the Svelte component** + +```svelte + + +
+``` + +**Step 2: Commit** + +```bash +git add packages/svelte-devtools/src/TanStackDevtools.svelte +git commit -m "feat(svelte-devtools): add TanStackDevtools Svelte component" +``` + +--- + +### Task 5: Create barrel export + +**Files:** +- Create: `packages/svelte-devtools/src/index.ts` + +**Step 1: Create index.ts** + +```ts +export { default as TanStackDevtools } from './TanStackDevtools.svelte' + +export type { + TanStackDevtoolsSveltePlugin, + TanStackDevtoolsSvelteInit, +} from './types' +``` + +**Step 2: Commit** + +```bash +git add packages/svelte-devtools/src/index.ts +git commit -m "feat(svelte-devtools): add barrel export" +``` + +--- + +### Task 6: Create devtools-utils Svelte subpath + +**Files:** +- Create: `packages/devtools-utils/src/svelte/index.ts` +- Create: `packages/devtools-utils/src/svelte/plugin.ts` +- Create: `packages/devtools-utils/src/svelte/panel.ts` + +**Step 1: Create plugin.ts** + +Reference: `packages/devtools-utils/src/vue/plugin.ts` — same `(name, component)` API pattern. + +```ts +import type { Component } from 'svelte' + +export function createSveltePlugin( + name: string, + component: Component, +) { + function Plugin(props?: Record) { + return { + name, + component, + props, + } + } + + function NoOpPlugin(props?: Record) { + return { + name, + component: (() => {}) as unknown as Component, + props, + } + } + + return [Plugin, NoOpPlugin] as const +} +``` + +Note: Svelte doesn't have a `Fragment` equivalent like Vue. A no-op component is an empty component. We use a minimal function cast. Alternatively, we could create a small no-op Svelte component, but that requires `.svelte` compilation in devtools-utils. Since this follows the same pattern as the Vue/Angular adapters where the NoOp is a minimal empty component, using a function cast keeps it simple. + +**Step 2: Create panel.ts** + +Reference: `packages/devtools-utils/src/vue/panel.ts` — wraps a class-based core. + +```ts +import type { Component } from 'svelte' + +export interface DevtoolsPanelProps { + theme?: 'dark' | 'light' | 'system' +} + +export function createSveltePanel< + TComponentProps extends DevtoolsPanelProps, + TCoreDevtoolsClass extends { + mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void + unmount: () => void + }, +>( + CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass, +): [Component, Component] { + // For Svelte, we return component factories that will be used with mount() + // The actual Panel and NoOpPanel need to be .svelte files or use Svelte's component API + // Since devtools-utils builds without the Svelte plugin, we return simple objects + // that the adapter will handle + + // Panel component factory — creates a div and mounts the core class into it + const Panel: Component = ((anchor: any, props: any) => { + const el = document.createElement('div') + el.style.height = '100%' + anchor.before(el) + + const instance = new CoreClass(props?.devtoolsProps as TComponentProps) + instance.mount(el, props?.theme) + + return { + destroy() { + instance.unmount() + el.remove() + }, + } + }) as any + + const NoOpPanel: Component = (() => ({})) as any + + return [Panel, NoOpPanel] +} +``` + +Note: The panel factory is more complex in Svelte since we can't use `.svelte` files in devtools-utils (it builds without the Svelte plugin). The implementation provides a minimal imperative wrapper. If this doesn't work cleanly during build testing, we can simplify to just export the factory types and let consumers handle mounting. + +**Step 3: Create index.ts** + +```ts +export * from './panel' +export * from './plugin' +``` + +**Step 4: Commit** + +```bash +git add packages/devtools-utils/src/svelte/ +git commit -m "feat(devtools-utils): add Svelte factory functions" +``` + +--- + +### Task 7: Update devtools-utils package config for Svelte + +**Files:** +- Modify: `packages/devtools-utils/package.json` — add `./svelte` export, add svelte peer dep, update build script +- Create: `packages/devtools-utils/vite.config.svelte.ts` +- Modify: `packages/devtools-utils/tsconfig.json` — add vite.config.svelte.ts to include + +**Step 1: Add vite.config.svelte.ts** + +Reference: `packages/devtools-utils/vite.config.vue.ts` + +```ts +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import packageJson from './package.json' + +const config = defineConfig({ + plugins: [], + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'jsdom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/svelte/index.ts'], + srcDir: './src/svelte', + outDir: './dist/svelte', + cjs: false, + }), +) +``` + +**Step 2: Update package.json exports** + +Add to exports object (after `./vue`): +```json +"./svelte": { + "import": { + "types": "./dist/svelte/esm/index.d.ts", + "default": "./dist/svelte/esm/index.js" + } +} +``` + +Add to peerDependencies (alphabetically sorted): +```json +"svelte": ">=5.0.0" +``` + +Add to peerDependenciesMeta: +```json +"svelte": { + "optional": true +} +``` + +Update build script — append: ` && vite build --config vite.config.svelte.ts` + +**Step 3: Update tsconfig.json** + +Add `"vite.config.svelte.ts"` to include array. + +**Step 4: Run pnpm install** + +Run: `pnpm install` + +**Step 5: Commit** + +```bash +git add packages/devtools-utils/package.json packages/devtools-utils/vite.config.svelte.ts packages/devtools-utils/tsconfig.json pnpm-lock.yaml +git commit -m "feat(devtools-utils): add Svelte build config and exports" +``` + +--- + +### Task 8: Update knip.json for Svelte + +**Files:** +- Modify: `knip.json` + +**Step 1: Update knip config** + +Add svelte to devtools-utils ignoreDependencies if needed, and add entry/project patterns: + +In `packages/devtools-utils` workspace entry, update: +- Add `"**/vite.config.svelte.ts"` to entry array +- Add `"**/src/svelte/**"` to entry array +- Do the same for project array + +If svelte-devtools needs a knip entry, add it. + +**Step 2: Commit** + +```bash +git add knip.json +git commit -m "chore: update knip config for Svelte packages" +``` + +--- + +### Task 9: Build and fix issues + +**Step 1: Build svelte-devtools** + +Run: `cd packages/svelte-devtools && pnpm build` + +Fix any build errors. Common issues: +- Svelte plugin config may need adjustments +- `.svelte` file imports may need `.js` extension in `.svelte.ts` files +- External deps configuration + +**Step 2: Build devtools-utils with Svelte** + +Run: `cd packages/devtools-utils && vite build --config vite.config.svelte.ts` + +Fix any build errors. + +**Step 3: Run full test suite** + +Run: `pnpm run test` + +Fix any failures: +- `sherif`: peerDependencies must be alphabetically sorted +- `eslint`: Check for lint violations +- `knip`: Check for unused deps +- `publint`: Check for package config issues +- `tsc`: Check for type errors + +**Step 4: Commit fixes** + +```bash +git add -A +git commit -m "fix: resolve build and test issues for Svelte adapter" +``` + +--- + +### Task 10: Add Svelte documentation + +**Files:** +- Create: `docs/framework/svelte/basic-setup.md` +- Create: `docs/framework/svelte/adapter.md` +- Create: `docs/framework/svelte/guides/custom-plugins.md` +- Modify: `docs/config.json` — add svelte framework sections +- Modify: `docs/installation.md` — add Svelte section +- Modify: `docs/quick-start.md` — add Svelte section +- Modify: `docs/devtools-utils.md` — add Svelte section + +**Step 1: Create basic-setup.md** + +Follow pattern of `docs/framework/vue/basic-setup.md` but with Svelte syntax. + +**Step 2: Create adapter.md** + +Follow pattern of `docs/framework/vue/adapter.md` but for Svelte component inputs. + +**Step 3: Create custom-plugins.md** + +Follow pattern of `docs/framework/vue/guides/custom-plugins.md` but with Svelte 5 runes. + +**Step 4: Update config.json** + +Add `angular`-style entries for svelte in Getting Started, Guides, and API Reference sections. + +**Step 5: Update installation.md** + +Add Svelte section before Vanilla JS. + +**Step 6: Update quick-start.md** + +Add Svelte section before Vite Plugin. Update overview text to include Svelte. + +**Step 7: Update devtools-utils.md** + +Add Svelte section with `createSveltePlugin` and `createSveltePanel` docs. Add Svelte import to DevtoolsPanelProps examples. + +**Step 8: Commit** + +```bash +git add docs/ +git commit -m "docs: add Svelte documentation" +``` + +--- + +### Task 11: Add changeset + +**Files:** +- Create: `.changeset/.md` + +**Step 1: Create changeset** + +Create a changeset for the new packages: + +```md +--- +'@tanstack/svelte-devtools': minor +'@tanstack/devtools-utils': minor +--- + +feat: add Svelte 5 adapter and devtools-utils Svelte factories +``` + +**Step 2: Commit** + +```bash +git add .changeset/ +git commit -m "chore: add changeset for Svelte adapter" +``` + +--- + +### Task 12: Final verification + +**Step 1: Run full test suite** + +Run: `pnpm run test` + +Expected: All checks pass (sherif, knip, eslint, types, build, publint) + +**Step 2: Verify build output** + +Run: `ls packages/svelte-devtools/dist/esm/` + +Expected: `index.js`, `index.d.ts` exist and are non-empty + +Run: `ls packages/devtools-utils/dist/svelte/esm/` + +Expected: `index.js`, `index.d.ts` exist and are non-empty diff --git a/docs/quick-start.md b/docs/quick-start.md index 016c430b..356a8582 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -3,7 +3,7 @@ title: Quick Start id: quick-start --- -TanStack Devtools is a framework-agnostic devtool for managing and debugging devtools plugins across React, Preact, Solid, and Vue. Pick your framework below to get started. +TanStack Devtools is a framework-agnostic devtool for managing and debugging devtools plugins across React, Preact, Solid, Vue, and Svelte. Pick your framework below to get started. ## React @@ -204,6 +204,46 @@ const plugins: TanStackDevtoolsVuePlugin[] = [ ``` +## Svelte + +Install the devtools: + +```bash +npm install @tanstack/svelte-devtools +``` + +Add the `TanStackDevtools` component to the root of your application: + +```svelte + + +
+ +
+ +``` + +To add plugins, define them as an array and pass them via the `plugins` prop. Svelte uses `component` instead of `render` in plugin definitions: + +```svelte + + +
+ +
+ +``` + ## Vite Plugin All frameworks benefit from the optional Vite plugin, which provides enhanced console logs, go-to-source, and a server event bus. Install it as a dev dependency: diff --git a/knip.json b/knip.json index 24871a78..a9393ad6 100644 --- a/knip.json +++ b/knip.json @@ -4,9 +4,19 @@ "ignoreWorkspaces": ["examples/**"], "workspaces": { "packages/devtools-utils": { - "ignoreDependencies": ["react", "solid-js", "@types/react"], - "entry": ["**/vite.config.solid.ts", "**/src/solid/**"], - "project": ["**/vite.config.solid.ts", "**/src/solid/**"] + "ignoreDependencies": ["react", "solid-js", "svelte", "@types/react"], + "entry": [ + "**/vite.config.solid.ts", + "**/src/solid/**", + "**/vite.config.svelte.ts", + "**/src/svelte/**" + ], + "project": [ + "**/vite.config.solid.ts", + "**/src/solid/**", + "**/vite.config.svelte.ts", + "**/src/svelte/**" + ] }, "packages/devtools-ui": { "entry": ["**/tests/**/*.ts"] diff --git a/package.json b/package.json index ab53cbf6..7ff6ecd3 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "@tanstack/react-devtools": "workspace:*", "@tanstack/preact-devtools": "workspace:*", "@tanstack/solid-devtools": "workspace:*", - "@tanstack/devtools-vite": "workspace:*" + "@tanstack/devtools-vite": "workspace:*", + "@tanstack/svelte-devtools": "workspace:*" } } diff --git a/packages/devtools-utils/package.json b/packages/devtools-utils/package.json index 3353dc8f..82867827 100644 --- a/packages/devtools-utils/package.json +++ b/packages/devtools-utils/package.json @@ -53,6 +53,12 @@ "default": "./dist/vue/esm/index.js" } }, + "./svelte": { + "import": { + "types": "./dist/svelte/esm/index.d.ts", + "default": "./dist/svelte/esm/index.js" + } + }, "./package.json": "./package.json" }, "sideEffects": false, @@ -67,6 +73,7 @@ "preact": ">=10.0.0", "react": ">=17.0.0", "solid-js": ">=1.9.7", + "svelte": ">=5.0.0", "vue": ">=3.2.0" }, "peerDependenciesMeta": { @@ -82,6 +89,9 @@ "solid-js": { "optional": true }, + "svelte": { + "optional": true + }, "vue": { "optional": true } @@ -98,7 +108,7 @@ "test:lib:dev": "pnpm test:lib --watch", "test:types": "tsc", "test:build": "publint --strict", - "build": "vite build && vite build --config vite.config.preact.ts && vite build --config vite.config.vue.ts && tsup " + "build": "vite build && vite build --config vite.config.preact.ts && vite build --config vite.config.vue.ts && vite build --config vite.config.svelte.ts && tsup " }, "devDependencies": { "tsup": "^8.5.0", diff --git a/packages/devtools-utils/src/svelte/index.ts b/packages/devtools-utils/src/svelte/index.ts new file mode 100644 index 00000000..37bc5ffd --- /dev/null +++ b/packages/devtools-utils/src/svelte/index.ts @@ -0,0 +1,2 @@ +export * from './panel' +export * from './plugin' diff --git a/packages/devtools-utils/src/svelte/panel.ts b/packages/devtools-utils/src/svelte/panel.ts new file mode 100644 index 00000000..0def6925 --- /dev/null +++ b/packages/devtools-utils/src/svelte/panel.ts @@ -0,0 +1,35 @@ +import type { Component } from 'svelte' + +export interface DevtoolsPanelProps { + theme?: 'dark' | 'light' | 'system' +} + +export function createSveltePanel< + TComponentProps extends DevtoolsPanelProps, + TCoreDevtoolsClass extends { + mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void + unmount: () => void + }, +>( + CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass, +): [Component, Component] { + const Panel: Component = ((anchor: any, props: any) => { + const el = document.createElement('div') + el.style.height = '100%' + anchor.before(el) + + const instance = new CoreClass(props?.devtoolsProps as TComponentProps) + instance.mount(el, props?.theme) + + return { + destroy() { + instance.unmount() + el.remove() + }, + } + }) as any + + const NoOpPanel: Component = (() => ({})) as any + + return [Panel, NoOpPanel] +} diff --git a/packages/devtools-utils/src/svelte/plugin.ts b/packages/devtools-utils/src/svelte/plugin.ts new file mode 100644 index 00000000..71af9215 --- /dev/null +++ b/packages/devtools-utils/src/svelte/plugin.ts @@ -0,0 +1,21 @@ +import type { Component } from 'svelte' + +export function createSveltePlugin(name: string, component: Component) { + function Plugin(props?: Record) { + return { + name, + component, + props, + } + } + + function NoOpPlugin(props?: Record) { + return { + name, + component: (() => {}) as unknown as Component, + props, + } + } + + return [Plugin, NoOpPlugin] as const +} diff --git a/packages/devtools-utils/tsconfig.json b/packages/devtools-utils/tsconfig.json index 30291221..4c5696e8 100644 --- a/packages/devtools-utils/tsconfig.json +++ b/packages/devtools-utils/tsconfig.json @@ -11,6 +11,7 @@ "vite.config.ts", "vite.config.preact.ts", "vite.config.vue.ts", + "vite.config.svelte.ts", "tests", "vite.config.solid.ts" ] diff --git a/packages/devtools-utils/vite.config.svelte.ts b/packages/devtools-utils/vite.config.svelte.ts new file mode 100644 index 00000000..cdfc5dfa --- /dev/null +++ b/packages/devtools-utils/vite.config.svelte.ts @@ -0,0 +1,25 @@ +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import packageJson from './package.json' + +const config = defineConfig({ + plugins: [], + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'jsdom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/svelte/index.ts'], + srcDir: './src/svelte', + outDir: './dist/svelte', + cjs: false, + }), +) diff --git a/packages/svelte-devtools/eslint.config.js b/packages/svelte-devtools/eslint.config.js new file mode 100644 index 00000000..8ce6ad05 --- /dev/null +++ b/packages/svelte-devtools/eslint.config.js @@ -0,0 +1,5 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +export default [...rootConfig] diff --git a/packages/svelte-devtools/package.json b/packages/svelte-devtools/package.json new file mode 100644 index 00000000..2950c8c9 --- /dev/null +++ b/packages/svelte-devtools/package.json @@ -0,0 +1,61 @@ +{ + "name": "@tanstack/svelte-devtools", + "version": "0.0.1", + "description": "TanStack Devtools is a set of tools for building advanced devtools for your Svelte application.", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/devtools.git", + "directory": "packages/svelte-devtools" + }, + "homepage": "https://tanstack.com/devtools", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "svelte", + "devtools" + ], + "type": "module", + "types": "dist/esm/index.d.ts", + "module": "dist/esm/index.js", + "svelte": "dist/esm/index.js", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + } + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "test:build": "publint --strict", + "build": "vite build" + }, + "dependencies": { + "@tanstack/devtools": "workspace:*" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "svelte": "^5.0.0" + }, + "peerDependencies": { + "svelte": ">=5.0.0" + } +} diff --git a/packages/svelte-devtools/src/TanStackDevtools.svelte b/packages/svelte-devtools/src/TanStackDevtools.svelte new file mode 100644 index 00000000..e1e3ae0d --- /dev/null +++ b/packages/svelte-devtools/src/TanStackDevtools.svelte @@ -0,0 +1,24 @@ + + +
diff --git a/packages/svelte-devtools/src/devtools.svelte.ts b/packages/svelte-devtools/src/devtools.svelte.ts new file mode 100644 index 00000000..f1d05bfb --- /dev/null +++ b/packages/svelte-devtools/src/devtools.svelte.ts @@ -0,0 +1,113 @@ +import { mount, unmount } from 'svelte' +import { PLUGIN_CONTAINER_ID, TanStackDevtoolsCore } from '@tanstack/devtools' +import type { Component } from 'svelte' +import type { TanStackDevtoolsPlugin } from '@tanstack/devtools' +import type { + TanStackDevtoolsSvelteInit, + TanStackDevtoolsSveltePlugin, +} from './types' + +type MountedComponent = ReturnType + +export class TanStackDevtoolsSvelteAdapter { + private devtools: TanStackDevtoolsCore | null = null + private mountedComponents: Array<{ + instance: MountedComponent + containerId: string + }> = [] + + mount(target: HTMLElement, init: TanStackDevtoolsSvelteInit) { + const pluginsMap = this.getPluginsMap(init.plugins) + + this.devtools = new TanStackDevtoolsCore({ + config: init.config, + eventBusConfig: init.eventBusConfig, + plugins: pluginsMap, + }) + + this.devtools.mount(target) + } + + update(init: TanStackDevtoolsSvelteInit) { + if (this.devtools) { + this.devtools.setConfig({ + config: init.config, + eventBusConfig: init.eventBusConfig, + plugins: this.getPluginsMap(init.plugins), + }) + } + } + + destroy() { + this.destroyAllComponents() + if (this.devtools) { + this.devtools.unmount() + this.devtools = null + } + } + + private getPluginsMap( + plugins?: Array, + ): Array { + if (!plugins) return [] + return plugins.map((plugin) => this.convertPlugin(plugin)) + } + + private convertPlugin( + plugin: TanStackDevtoolsSveltePlugin, + ): TanStackDevtoolsPlugin { + return { + id: plugin.id, + defaultOpen: plugin.defaultOpen, + name: + typeof plugin.name === 'string' + ? plugin.name + : (el, theme) => { + this.renderComponent(plugin.name as Component, el, { + theme, + ...(plugin.props ?? {}), + }) + }, + render: (el, theme) => { + this.renderComponent(plugin.component, el, { + theme, + ...(plugin.props ?? {}), + }) + }, + destroy: (pluginId) => { + this.destroyComponentsInContainer(`${PLUGIN_CONTAINER_ID}-${pluginId}`) + }, + } + } + + private renderComponent( + component: Component, + container: HTMLElement, + props: Record, + ) { + const instance = mount(component, { + target: container, + props, + }) + + const containerId = container.id || container.parentElement?.id || '' + this.mountedComponents.push({ instance, containerId }) + } + + private destroyComponentsInContainer(containerId: string) { + this.mountedComponents = this.mountedComponents.filter((entry) => { + if (entry.containerId === containerId) { + unmount(entry.instance) + return false + } + return true + }) + } + + private destroyAllComponents() { + for (const entry of this.mountedComponents) { + unmount(entry.instance) + } + this.mountedComponents = [] + } +} diff --git a/packages/svelte-devtools/src/index.ts b/packages/svelte-devtools/src/index.ts new file mode 100644 index 00000000..5e9ef867 --- /dev/null +++ b/packages/svelte-devtools/src/index.ts @@ -0,0 +1,6 @@ +export { default as TanStackDevtools } from './TanStackDevtools.svelte' + +export type { + TanStackDevtoolsSveltePlugin, + TanStackDevtoolsSvelteInit, +} from './types' diff --git a/packages/svelte-devtools/src/types.ts b/packages/svelte-devtools/src/types.ts new file mode 100644 index 00000000..1d776552 --- /dev/null +++ b/packages/svelte-devtools/src/types.ts @@ -0,0 +1,19 @@ +import type { Component } from 'svelte' +import type { + ClientEventBusConfig, + TanStackDevtoolsConfig, +} from '@tanstack/devtools' + +export type TanStackDevtoolsSveltePlugin = { + id?: string + component: Component + name: string | Component + props?: Record + defaultOpen?: boolean +} + +export interface TanStackDevtoolsSvelteInit { + plugins?: Array + config?: Partial + eventBusConfig?: ClientEventBusConfig +} diff --git a/packages/svelte-devtools/tsconfig.json b/packages/svelte-devtools/tsconfig.json new file mode 100644 index 00000000..3acd44a0 --- /dev/null +++ b/packages/svelte-devtools/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src", "eslint.config.js", "vite.config.ts", "tests"] +} diff --git a/packages/svelte-devtools/vite.config.ts b/packages/svelte-devtools/vite.config.ts new file mode 100644 index 00000000..1b04ddbe --- /dev/null +++ b/packages/svelte-devtools/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import packageJson from './package.json' + +const config = defineConfig({ + plugins: [svelte()], + test: { + name: packageJson.name, + dir: './tests', + watch: false, + environment: 'jsdom', + globals: true, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/index.ts'], + srcDir: './src', + externalDeps: ['svelte'], + cjs: false, + }), +) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6dc48de..224460ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -801,6 +801,9 @@ importers: solid-js: specifier: '>=1.9.7' version: 1.9.11 + svelte: + specifier: '>=5.0.0' + version: 5.53.7 vue: specifier: '>=3.2.0' version: 3.5.29(typescript@5.9.3) @@ -946,6 +949,19 @@ importers: specifier: ^2.11.8 version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + packages/svelte-devtools: + dependencies: + '@tanstack/devtools': + specifier: workspace:* + version: link:../devtools + devDependencies: + '@sveltejs/vite-plugin-svelte': + specifier: ^6.0.0 + version: 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + svelte: + specifier: ^5.0.0 + version: 5.53.7 + packages/vue-devtools: dependencies: '@tanstack/devtools': @@ -3182,6 +3198,21 @@ packages: peerDependencies: acorn: ^8.9.0 + '@sveltejs/vite-plugin-svelte-inspector@5.0.2': + resolution: {integrity: sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@sveltejs/vite-plugin-svelte@6.2.4': + resolution: {integrity: sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + '@svitejs/changesets-changelog-github-compact@1.2.0': resolution: {integrity: sha512-08eKiDAjj4zLug1taXSIJ0kGL5cawjVCyJkBb6EWSg5fEPX6L+Wtr0CH2If4j5KYylz85iaZiFlUItvgJvll5g==} engines: {node: ^14.13.1 || ^16.0.0 || >=18} @@ -6911,6 +6942,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} @@ -10919,6 +10953,23 @@ snapshots: dependencies: acorn: 8.16.0 + '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + obug: 2.1.1 + svelte: 5.53.7 + vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + deepmerge: 4.3.1 + magic-string: 0.30.21 + obug: 2.1.1 + svelte: 5.53.7 + vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@svitejs/changesets-changelog-github-compact@1.2.0': dependencies: '@changesets/get-github-info': 0.6.0 @@ -15484,6 +15535,8 @@ snapshots: object-assign@4.1.1: {} + obug@2.1.1: {} + ofetch@1.5.1: dependencies: destr: 2.0.5