acks this assignment automatically
let activeFilters: string[] = [];
let processedData: MetricData[] = [];
// Reactive declaration: recalculates when dependencies change
$: filteredMetrics = initialMetrics.filter(metric =>
activeFilters.length === 0 || activeFilters.includes(metric.category)
);
function applyFilter(category: string): void {
// Reassignment triggers compiler update
activeFilters = activeFilters.includes(category)
? activeFilters.filter(f => f !== category)
: [...activeFilters, category];
}
</script>
**Rationale:** Plain assignment combined with `$:` reactive declarations eliminates manual dependency tracking. The compiler transforms these into efficient DOM patching instructions. AI models trained on React will attempt to use `useEffect`-style watchers or manual state managers; the guardrail forces alignment with Svelte's transformation pipeline.
### Step 2: Centralize Cross-Component State with Stores
When state must persist across component boundaries, Svelte provides a built-in store system with auto-subscription syntax. This removes the need for context providers, prop drilling, or external state libraries.
**Implementation:**
```typescript
// src/lib/stores/session.ts
import { writable, derived } from 'svelte/store';
import type { UserSession, SessionMetrics } from '$lib/types';
const sessionData = writable<UserSession | null>(null);
const metrics = derived(sessionData, ($session) => {
if (!$session) return { active: false, lastLogin: null };
return {
active: true,
lastLogin: $session.lastAccess,
tokenExpiry: $session.expiresAt
};
});
export const session = {
subscribe: sessionData.subscribe,
update: sessionData.update,
set: sessionData.set,
metrics
};
Rationale: The $ prefix auto-subscription syntax handles subscription and cleanup automatically. AI models frequently generate manual .subscribe() calls with forgotten .unsubscribe() cleanup, causing memory leaks. The store pattern centralizes logic, enforces type safety, and aligns with Svelte's reactive programming model.
Step 3: Route Data Through Server Load Functions
In SvelteKit, data fetching must occur at the routing layer, not inside component lifecycle hooks. This ensures server-side rendering, eliminates client-side loading states, and prevents hydration mismatches.
Implementation:
// src/routes/dashboard/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch, cookies }) => {
const authToken = cookies.get('auth_token');
if (!authToken) throw error(401, 'Unauthorized');
const response = await fetch('/api/v2/metrics', {
headers: { Authorization: `Bearer ${authToken}` }
});
if (!response.ok) throw error(response.status, 'Failed to load metrics');
return {
metrics: await response.json(),
timestamp: new Date().toISOString()
};
};
Rationale: Server load functions run in a Node.js environment before HTML generation. Client-side fetch inside onMount forces a double-render cycle and breaks SSR. The guardrail ensures data availability at hydration time, matching server output with client expectations.
Step 4: Replace Manual DOM Binding with Directives
Svelte's template directives handle event binding, class toggling, and transitions with automatic cleanup. AI models default to addEventListener and string interpolation, which bypass the compiler's optimization pass.
Implementation:
<!-- MetricCard.svelte -->
<script lang="ts">
export let label: string;
export let isActive: boolean = false;
function handleExpand(): void {
// Toggle logic handled by compiler
}
</script>
<div
class:expanded={isActive}
on:click|preventDefault={handleExpand}
transition:fade={{ duration: 200 }}
>
<span>{label}</span>
</div>
Rationale: Directives like class:name, on:event|modifier, and transition: are compiled into efficient DOM operations. Manual event binding requires explicit cleanup and interferes with Svelte's component lifecycle. The directive approach guarantees memory safety and consistent rendering behavior.
Pitfall Guide
1. Manual Event Listener Attachment
Explanation: AI models frequently generate element.addEventListener('click', handler) inside component scripts. This bypasses Svelte's template compiler, requires manual cleanup, and creates memory leaks when components unmount.
Fix: Replace all manual bindings with on:event directives in the template. Use modifiers like |preventDefault or |once directly in the directive syntax.
2. Top-Level Browser API Access
Explanation: Accessing window, document, or localStorage at the module level breaks server-side rendering. The server environment lacks these globals, causing hydration errors or runtime crashes during deployment.
Fix: Wrap browser-specific code in onMount() callbacks or use $app/environment's browser flag for conditional execution. Never access DOM APIs outside lifecycle boundaries.
3. Array/Object Mutation Without Reassignment
Explanation: Calling .push(), .splice(), or directly mutating object properties does not trigger Svelte's reactivity. The compiler only watches for assignment operators (=, +=, etc.).
Fix: Always reassign reactive variables. Use spread syntax for arrays (items = [...items, newItem]) or object rest syntax for properties (config = { ...config, updated: true }).
4. Client-Side Data Fetching in Lifecycle Hooks
Explanation: Placing fetch() calls inside onMount() forces the client to request data after HTML delivery. This creates loading spinners, delays interactivity, and breaks SSR content availability.
Fix: Move all initial data requests to +page.server.ts or +layout.server.ts load functions. Use client-side fetch only for post-interaction updates or real-time subscriptions.
5. String Interpolation for Dynamic Classes
Explanation: Building class strings via template literals (class="${isActive ? 'active' : ''}") requires runtime string evaluation and prevents compiler optimizations. It also increases bundle size and reduces readability.
Fix: Use the class:name={condition} directive. The compiler generates efficient class toggle logic and removes dead code paths during build.
6. Ignoring Svelte 5 Snippet Syntax
Explanation: AI training data contains mixed Svelte 4 and Svelte 5 patterns. Using <slot> in Svelte 5 projects creates deprecated component contracts and prevents modern content projection features.
Fix: Migrate to {#snippet name(params)}{/snippet} and {@render name(params)}. Snippets provide type-safe, composable content projection without the limitations of slot fallbacks.
7. Untyped Component Contracts
Explanation: AI-generated components often omit TypeScript types on export let props and event dispatchers. This defeats static analysis, enables runtime type errors, and breaks IDE autocomplete.
Fix: Enforce strict typing on all exported props. Use createEventDispatcher<{eventName: PayloadType}>() for type-safe event contracts. Enable strict: true in tsconfig.json to catch implicit any violations.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Local component state | Plain variable assignment + $: derived values | Compiler handles updates automatically; zero runtime overhead | Baseline |
| Cross-component state | svelte/store with $ auto-subscription | Eliminates prop drilling; automatic cleanup prevents memory leaks | Low |
| Initial page data | +page.server.ts load function | Enables SSR; removes client loading states; aligns hydration | Low |
| Post-interaction data | Client-side fetch inside event handlers | Necessary for real-time updates; avoids blocking initial render | Medium |
| Complex animations | svelte/motion (spring/tweened) | Hardware-accelerated; compiler-optimized; no external dependencies | Low |
| Global theming | CSS custom properties + :global() in app.css | Maintains component scope; enables runtime theme switching | Low |
Configuration Template
# AI Framework Guardrails: Svelte 5 + SvelteKit
## Core Architecture
- Framework: Svelte 5 (compiler-driven reactivity)
- Meta-framework: SvelteKit (file-based routing, server load functions)
- State: svelte/store (writable, readable, derived)
- Styling: Scoped CSS + CSS custom properties
- Testing: Vitest + @testing-library/svelte
## Reactivity Protocol
- Use plain variable assignment for state mutations
- Apply $: syntax for derived values and reactive statements
- Never use useState, useEffect, ref, or signal wrappers
- Mutate arrays/objects via reassignment, not direct method calls
## Component Contract
- Props: export let propName with explicit TypeScript types
- Events: createEventDispatcher<{event: Payload}> with generic typing
- Lifecycle: onMount for DOM-dependent side effects; return cleanup function
- Content Projection: {#snippet} and {@render} for Svelte 5; <slot> only for legacy Svelte 4
## Data Loading Strategy
- Initial data: +page.server.ts or +layout.server.ts load functions
- Form submissions: form actions in +page.server.ts
- API endpoints: +server.ts for non-form data requirements
- Client fetch: Only for post-interaction updates or real-time streams
## DOM & Styling Rules
- Events: on:event|modifier directive syntax
- Classes: class:name={condition} directive
- Transitions: svelte/transition built-ins (fade, fly, slide, scale)
- Motion: svelte/motion (tweened, spring)
- Global styles: :global() selector or app.css only
- SSR safety: window/document/localStorage restricted to onMount or browser checks
## Prohibited Patterns
- Manual addEventListener in component scripts
- Top-level DOM or browser API access
- External state management libraries
- String interpolation for dynamic class names
- Client-side fetch for initial page data
- Untyped export let declarations
Quick Start Guide
- Initialize Guardrails: Place the configuration template in your project root as
AI_RULES.md or integrate it into your AI assistant's project context. Verify the AI acknowledges Svelte 5 syntax and SvelteKit routing conventions.
- Configure TypeScript: Update
tsconfig.json with "strict": true and "moduleResolution": "bundler". Run npx svelte-kit sync to generate route types.
- Validate Reactivity: Create a test component using plain assignment and
$: derived values. Verify the compiler generates update statements by inspecting the build output or using Svelte DevTools.
- Audit Data Flow: Replace any
onMount fetch calls with +page.server.ts load functions. Test SSR output to confirm data hydration matches client state.
- Run Test Suite: Execute
npm test with Vitest. Verify component rendering, store subscriptions, and event dispatching pass without manual lifecycle mocking.