b192cd53ba
- Add comprehensive project overview and core philosophy - Document file structure reference for the codebase - Create key files reference table for task-specific guidance - Include multi-tenant guidelines and site resolution flow
68 lines
2.7 KiB
Markdown
68 lines
2.7 KiB
Markdown
---
|
|
description: 'Use when writing or editing .svelte.ts reactive state modules. Enforces Svelte 5 runes-based shared state patterns and forbids svelte/store primitives.'
|
|
applyTo: '**/*.svelte.ts'
|
|
---
|
|
|
|
# Svelte Reactive Module Rules (`.svelte.ts`)
|
|
|
|
Use `.svelte.ts` files for **global or cross-tree shared reactive state** that needs to be accessed outside of a component hierarchy. For state scoped to a component subtree, prefer `setContext` / `getContext` instead.
|
|
|
|
## Module-Scope State
|
|
|
|
Declare `$state` at module scope to create a reactive singleton. Export a factory function or a plain object with getter/setter methods — not the raw `$state` variable, which would allow callers to reassign it.
|
|
|
|
```ts
|
|
// ✅ src/lib/state/services.svelte.ts
|
|
const _state = $state({ list: [] as Service[], loading: false });
|
|
|
|
export const servicesStore = {
|
|
get list() {
|
|
return _state.list;
|
|
},
|
|
get loading() {
|
|
return _state.loading;
|
|
},
|
|
set(services: Service[]) {
|
|
_state.list = services;
|
|
},
|
|
setLoading(v: boolean) {
|
|
_state.loading = v;
|
|
}
|
|
};
|
|
```
|
|
|
|
```ts
|
|
// ❌ — callers can do `list = []` bypassing reactivity
|
|
export let list = $state<Service[]>([]);
|
|
```
|
|
|
|
## Derived State
|
|
|
|
Use `$derived` at module scope for computed values:
|
|
|
|
```ts
|
|
const _state = $state({ list: [] as Service[], search: '' });
|
|
|
|
export const filtered = $derived(_state.list.filter((s) => s.name.includes(_state.search)));
|
|
```
|
|
|
|
## Never Use svelte/store
|
|
|
|
Do not use `writable`, `readable`, or `derived` from `svelte/store` in new code.
|
|
|
|
| Instead of | Use |
|
|
| ------------------------ | ---------------------------------------------- |
|
|
| `writable(value)` | `$state(value)` in a `.svelte.ts` module |
|
|
| `derived(store, fn)` | `$derived(fn)` in a `.svelte.ts` module |
|
|
| `readable(value, start)` | `$state` + a setup function in the module body |
|
|
|
|
## When to Use `.svelte.ts` vs `setContext/getContext`
|
|
|
|
| Scenario | Pattern |
|
|
| --------------------------------------------------- | -------------------------------------------------------------------- |
|
|
| State needed across unrelated component trees | `.svelte.ts` module singleton |
|
|
| State scoped to one subtree (e.g. a form, a widget) | `setContext` in parent, `getContext` in children |
|
|
| State that needs SSR / per-request isolation | `setContext` in `+layout.svelte` (never module singletons on server) |
|
|
|
|
> **Warning**: Module singletons are shared across all users in SSR. Only use `.svelte.ts` singletons for state that is client-side only (e.g. UI state, client-cached data). For per-user server state, always use context.
|