From 9218efa6e2acfa6a6c0f60f2c303a5273de2f5e1 Mon Sep 17 00:00:00 2001 From: isUnknown Date: Sat, 7 Feb 2026 08:25:44 +0100 Subject: [PATCH] add conventions dir with svelte kit front end conventions --- .../svelte-kit-frontend-conventions.md | 611 ++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 conventions/svelte-kit-frontend-conventions.md diff --git a/conventions/svelte-kit-frontend-conventions.md b/conventions/svelte-kit-frontend-conventions.md new file mode 100644 index 0000000..f605ece --- /dev/null +++ b/conventions/svelte-kit-frontend-conventions.md @@ -0,0 +1,611 @@ + + +# SvelteKit Style Guide for LLM Code Generation + +## Environment + +- **Target Svelte Version**: **SvelteKit 1.0** +- **Target TypeScript Version**: **4.x** + +## General Principles + +1. **Use Svelte components as the primary building blocks.** +2. **Prefer composition over inheritance at all times.** +3. **Use TypeScript for type safety and interfaces consistently throughout the codebase.** +4. **Follow Svelte's conventions for naming and code formatting rigorously.** +5. **Utilize reactive declarations and stores appropriately to manage state.** + +## Design Principles + +### 1. High Cohesion and Low Coupling + +- **Ensure each component or module has a single, well-defined responsibility.** +- **Minimize dependencies between components using props, events, and the context API.** + +### 2. Favor Composition Over Inheritance + +- **Build complex UIs from simpler components using composition.** +- **Avoid class inheritance entirely; Svelte favors functional and reactive programming.** +- **Utilize slots and props to compose and customize components effectively.** + +### 3. Start with the Data + +- **Define data structures first using TypeScript interfaces or types.** +- **Use type annotations to specify data types clearly and consistently.** +- **Design components and stores around data structures, not behaviors.** + +### 4. Depend on Abstractions + +- **Use TypeScript interfaces and types to define contracts between components and services.** +- **Code against abstractions, not concrete implementations, to enhance flexibility.** +- **Leverage dependency injection via the context API or module imports to decouple components.** + +### 5. Separate Creation from Use + +- **Initialize data and services outside of components whenever possible.** +- **Pass dependencies as props or through the context API; do not hardcode dependencies within components.** +- **Use service modules for shared logic and API interactions.** + +### 6. Keep Things Simple + +- **Write simple and readable code, avoiding clever or complex solutions.** +- **Do not add unnecessary functionality (YAGNI principle).** +- **Refactor and simplify code regularly to maintain clarity and efficiency.** + +## Coding Standards + +### TypeScript Type Annotations + +1. **Use built-in types and generics like `Array`, `Promise`, and `Record`.** +2. **Define custom types and interfaces for all complex data structures.** +3. **Use union types (e.g., `string | number`) where necessary.** +4. **Use `type | undefined` for optional properties instead of `null`.** +5. **Annotate all variables, function parameters, and return types explicitly.** +6. **Avoid using `any`; if the type cannot be determined, use `unknown` and refine as soon as possible.** + +**Example:** + +```typescript +interface User { + id: number; + name: string; + email?: string; +} + +function greet(user: User): string { + return `Hello, ${user.name}!`; +} +``` + +### Components + +1. **Use PascalCase for component names and filenames (e.g., `MyComponent.svelte`).** +2. **Keep components focused and small, adhering strictly to the Single Responsibility Principle.** +3. **Use reactive statements and declarations to manage state changes effectively.** +4. **Avoid using `bind:this`; use Svelte's reactivity and refs for DOM manipulation instead.** + +### Props and State + +1. **Define props using the `export` keyword in components, and annotate their types.** +2. **Use default values for props when appropriate to ensure components behave predictably.** +3. **Manage local state within components using reactive variables and statements.** +4. **Avoid modifying props directly; treat them as immutable within the component.** + +**Example:** + +```svelte + +``` + +### Stores + +1. **Use Svelte's `writable`, `readable`, and `derived` stores for shared state management.** +2. **Create custom stores for complex state logic and encapsulate related functionality.** +3. **Subscribe to stores using the `$` prefix for automatic reactivity in components.** +4. **Unsubscribe from stores manually only if subscribing imperatively; otherwise, let Svelte handle it.** + +**Example:** + +```typescript +// store.ts +import { writable } from 'svelte/store'; + +export const count = writable(0); +``` + +```svelte + + + +``` + +### Events + +1. **Use Svelte's event system for communication between components.** +2. **Dispatch custom events using `createEventDispatcher` with typed event payloads.** +3. **Handle events using the `on:eventName` directive in parent components.** +4. **Name events descriptively, using camelCase, to reflect their purpose clearly.** + +**Example:** + +```svelte + + + +``` + +### Naming Conventions + +1. **Use camelCase for variables, functions, and methods.** +2. **Use PascalCase for component names and TypeScript classes or interfaces.** +3. **Use UPPER_SNAKE_CASE for constants that are intended to remain unchanged.** +4. **Choose meaningful and descriptive names for all identifiers to enhance code readability.** + +### Reactive Declarations and Statements + +1. **Use reactive declarations (`$:`) for values that depend on reactive variables.** +2. **Avoid side effects within reactive statements; keep them pure and predictable.** +3. **Keep reactive statements simple and focused to maintain clarity.** + +**Example:** + +```svelte + +``` + +### Comments and Documentation + +1. **Use JSDoc comments for functions, interfaces, and any complex logic that requires explanation.** +2. **Document component APIs, including props, events, and slots, thoroughly.** +3. **Write comments to explain non-obvious code; avoid redundant or obvious comments.** + +**Example:** + +```typescript +/** + * Fetches user data from the API. + * @param id - The ID of the user to fetch. + * @returns A Promise that resolves to a User object. + */ +async function fetchUser(id: number): Promise { + // ... +} +``` + +## Data Modeling + +### TypeScript Interfaces and Types + +1. **Define interfaces for object shapes, component props, and API responses.** +2. **Use types for unions, intersections, and more complex type manipulations.** +3. **Prefer interfaces when you need to extend object types through inheritance.** +4. **Use `readonly` and `Partial<>` modifiers when you want to enforce immutability or optionality.** + +**Example:** + +```typescript +interface Address { + street: string; + city: string; + zipCode: string; +} + +interface User { + id: number; + name: string; + address?: Address; +} +``` + +### API Integration + +1. **Define data models that mirror backend API schemas using TypeScript interfaces.** +2. **Use the Fetch API for network requests, leveraging `async`/`await` syntax.** +3. **Handle API responses and errors gracefully, providing meaningful feedback to the user.** +4. **Ensure type safety by explicitly typing API response data.** + +**Example:** + +```typescript +async function getUser(id: number): Promise { + const response = await fetch(`/api/users/${id}`); + if (!response.ok) { + throw new Error(`Failed to fetch user with id ${id}`); + } + return response.json() as Promise; +} +``` + +### Composition Patterns + +1. **Compose components using props and slots to build flexible and reusable UIs.** +2. **Use the context API for dependency injection to avoid prop drilling.** +3. **Create higher-order components (HOCs) only when necessary; prefer composition over HOCs.** +4. **Utilize custom stores to manage shared logic and state effectively.** + +**Example:** + +```svelte + + +``` + +## Application Structure + +### File Organization + +1. **Organize files by feature or domain, grouping related components, stores, and utilities together.** +2. **Use consistent and descriptive naming conventions for files and directories.** +3. **Separate concerns by keeping components, stores, utilities, and styles in their respective directories.** +4. **Avoid deep directory nesting to maintain simplicity and ease of navigation.** + +**Example Directory Structure:** + +``` +src/ +├── components/ +│ ├── Button.svelte +│ └── Modal.svelte +├── routes/ +│ ├── +layout.svelte +│ └── +page.svelte +├── stores/ +│ └── userStore.ts +├── lib/ +│ └── utils.ts +``` + +### Routing + +1. **Use SvelteKit's file-based routing system exclusively.** +2. **Organize routes within the `src/routes` directory, using `+page.svelte` and `+layout.svelte` appropriately.** +3. **Use nested layouts and pages to create a hierarchical structure.** +4. **Leverage dynamic routes and parameters for flexible navigation and data retrieval.** + +**Example:** + +``` +src/routes/ +├── +layout.svelte +├── index.svelte +├── about.svelte +└── items/ + ├── +page.svelte + └── [id]/ + └── +page.svelte +``` + +### Data Fetching and Load Functions + +1. **Use `load` functions in `+page.ts` or `+layout.ts` for data fetching required by the page.** +2. **Perform server-side fetching whenever possible to improve performance and SEO.** +3. **Handle errors and redirects within the `load` function using SvelteKit's conventions.** +4. **Use the `fetch` function provided by the `load` context to make requests, ensuring cookies and headers are preserved.** + +**Example:** + +```typescript +// +page.ts +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ fetch, params }) => { + const response = await fetch(`/api/items/${params.id}`); + if (!response.ok) { + return { + status: response.status, + error: new Error(`Failed to fetch item with id ${params.id}`), + }; + } + const item = (await response.json()) as Item; + return { item }; +}; +``` + +### Stores and State Management + +1. **Use Svelte stores for global or shared state across components or pages.** +2. **Avoid using stores for state that is local to a component; use component state instead.** +3. **Use `derived` stores for computed state based on other stores to avoid redundant computations.** +4. **Keep store logic encapsulated within the store to promote maintainability and reuse.** + +### Error Handling + +1. **Use SvelteKit's error handling by returning errors from `load` functions or throwing exceptions.** +2. **Create custom error pages (`__error.svelte`) to display user-friendly error messages.** +3. **Use try-catch blocks for asynchronous operations within components and `load` functions.** +4. **Provide informative and actionable error messages to enhance user experience.** + +**Example:** + +```typescript +// +page.ts +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ fetch }) => { + try { + const response = await fetch('/api/data'); + if (!response.ok) { + throw new Error(`Failed to fetch data: ${response.statusText}`); + } + const data = await response.json(); + return { data }; + } catch (error) { + return { + status: 500, + error: new Error('Internal Server Error'), + }; + } +}; +``` + +### Dependency Management + +1. **Use npm for package management consistently across the project.** +2. **Specify exact versions of dependencies in `package.json` to ensure consistency across environments.** +3. **Regularly update dependencies and test for compatibility issues.** +4. **Avoid adding unnecessary dependencies to keep the bundle size minimal and reduce potential security risks.** + +### Asynchronous Programming + +1. **Use `async`/`await` syntax for asynchronous code to enhance readability and maintainability.** +2. **Handle promise rejections using try-catch blocks or `.catch()` methods to prevent unhandled exceptions.** +3. **Avoid blocking the UI with heavy computations; use web workers if necessary.** +4. **Leverage Svelte's reactivity to update the UI upon data changes without manual DOM manipulation.** + +### Styling + +1. **Use scoped styles within components by default to avoid style conflicts.** +2. **Leverage CSS variables and themes to maintain consistent styling across the application.** +3. **Follow the BEM (Block, Element, Modifier) naming convention for class names to enhance readability.** +4. **Use SCSS as a preprocessor for advanced styling features and maintainable stylesheets.** + +**Example:** + +```svelte + +``` + +## Best Practices + +### Testing + +1. **Use Vitest as the testing framework for unit and integration tests.** +2. **Use @testing-library/svelte for testing Svelte components.** +3. **Write tests for all critical logic and components to ensure reliability.** +4. **Mock API calls and external dependencies in tests to isolate units and avoid flakiness.** + +**Example:** + +```typescript +// MyComponent.test.ts +import { render, fireEvent } from '@testing-library/svelte'; +import MyComponent from './MyComponent.svelte'; + +test('renders with default props', () => { + const { getByText } = render(MyComponent); + expect(getByText('Default Text')).toBeInTheDocument(); +}); +``` + +### Accessibility + +1. **Follow WAI-ARIA guidelines strictly to ensure the application is accessible to all users.** +2. **Use semantic HTML elements (e.g., ` +``` + +### Using Stores + +```svelte + + + + +``` + +### Fetching Data in Load Function + +```typescript +// +page.ts +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ fetch }) => { + const response = await fetch('/api/items'); + if (!response.ok) { + throw new Error('Failed to fetch items'); + } + const items = (await response.json()) as Item[]; + return { items }; +}; +``` + +### Custom Store + +```typescript +// userStore.ts +import { writable } from 'svelte/store'; +import type { User } from './types'; + +function createUserStore() { + const { subscribe, set } = writable(null); + + return { + subscribe, + login: async (username: string, password: string) => { + const user = await apiLogin(username, password); + set(user); + }, + logout: () => set(null), + }; +} + +export const userStore = createUserStore(); +``` + +### Context API + +```svelte + + + + +``` + +```svelte + + + +
+ +
+``` + +### Error Handling in Load Function + +```typescript +// +page.ts +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ fetch }) => { + try { + const response = await fetch('/api/data'); + if (!response.ok) { + throw new Error(`Failed to fetch data: ${response.statusText}`); + } + const data = await response.json(); + return { data }; + } catch (error) { + return { + status: 500, + error: new Error('Internal Server Error'), + }; + } +}; +``` + +### Unit Testing a Component + +```typescript +// Button.test.ts +import { render, fireEvent } from '@testing-library/svelte'; +import Button from './Button.svelte'; + +test('increments count on click', async () => { + const { getByText, component } = render(Button, { props: { count: 0 } }); + const button = getByText('Count is 0'); + + await fireEvent.click(button); + + expect(component.$$.ctx[0]).toBe(1); + expect(getByText('Count is 1')).toBeInTheDocument(); +}); +```