Svelte 5, SvelteKit, and pnpm Development Setup
This document provides guidance on setting up and working with Svelte 5, SvelteKit, and pnpm in the Meta Agent Platform project.
Overview
The Meta Agent Platform frontend is built with Svelte 5 and SvelteKit, leveraging Svelte's fine-grained reactivity system and runes for efficient state management, along with SvelteKit's routing, server-side rendering, and API capabilities. We use pnpm as our package manager for its performance benefits and disk space efficiency.
pnpm Setup
Installation
Install pnpm globally:
# Using npm
npm install -g pnpm
# Using curl for Unix systems
curl -fsSL https://get.pnpm.io/install.sh | sh -
# Using PowerShell for Windows
iwr https://get.pnpm.io/install.ps1 -useb | iex
Key pnpm Commands
# Install all dependencies
pnpm install
# Add a dependency
pnpm add <package-name>
# Add a dev dependency
pnpm add -D <package-name>
# Run a script from package.json
pnpm run <script-name>
# Update dependencies
pnpm update
# Run the development server
pnpm dev
pnpm Workspace Configuration
For our monorepo structure, we use pnpm workspaces. The configuration is in pnpm-workspace.yaml:
This allows us to manage multiple packages within a single repository, sharing dependencies and enabling cross-package development.
Svelte 5 Development
Project Structure
Our SvelteKit project follows this structure:
apps/frontend/
├── src/
│ ├── lib/
│ │ ├── components/
│ │ ├── stores/
│ │ └── utils/
│ ├── routes/
│ │ ├── +layout.svelte
│ │ ├── +layout.server.ts
│ │ ├── +page.svelte
│ │ ├── +page.server.ts
│ │ └── [...]/
│ │ ├── +page.svelte
│ │ └── +page.server.ts
│ ├── params/
│ ├── hooks.server.ts
│ └── app.html
├── static/
├── svelte.config.js
├── tsconfig.json
└── vite.config.ts
SvelteKit Routing
SvelteKit uses a file-based routing system:
src/routes/+page.svelte- The home pagesrc/routes/about/+page.svelte- The/aboutpagesrc/routes/[slug]/+page.svelte- Dynamic route with a parametersrc/routes/+layout.svelte- Layout that wraps all pagessrc/routes/+page.server.ts- Server-side logic for a pagesrc/routes/api/+server.ts- API endpoint
Using Runes
Svelte 5 introduces runes for state management. Here are the key runes we use:
$state
For reactive component state:
<script>
let count = $state(0);
function increment() {
count++;
}
</script>
<button onclick={increment}>
Count: {count}
</button>
$derived
For computed values:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<p>{count} doubled is {doubled}</p>
$effect
For side effects:
<script>
let count = $state(0);
$effect(() => {
console.log(`Count changed to ${count}`);
// Update external libraries, APIs, etc.
});
</script>
Data Loading with SvelteKit
SvelteKit provides a structured way to load data for pages:
// src/routes/workflows/[id]/+page.server.ts
export async function load({ params, fetch }) {
const response = await fetch(`/api/workflows/${params.id}`);
const workflow = await response.json();
return { workflow };
}
<!-- src/routes/workflows/[id]/+page.svelte -->
<script>
let { workflow } = $props();
</script>
<h1>{workflow.name}</h1>
API Routes with SvelteKit
Create API endpoints using SvelteKit's server routes:
// src/routes/api/workflows/+server.ts
import { json } from '@sveltejs/kit';
export async function GET({ url }) {
const workflows = await db.getWorkflows();
return json(workflows);
}
export async function POST({ request }) {
const data = await request.json();
const newWorkflow = await db.createWorkflow(data);
return json(newWorkflow, { status: 201 });
}
Form Actions with SvelteKit
Handle form submissions with progressive enhancement:
// src/routes/login/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
export const actions = {
default: async ({ request, cookies }) => {
const data = await request.formData();
const email = data.get('email');
const password = data.get('password');
if (!email || !password) {
return fail(400, { email, missing: true });
}
const user = await login(email, password);
if (!user) {
return fail(400, { email, invalid: true });
}
cookies.set('session', user.token, { path: '/' });
throw redirect(303, '/');
}
};
<!-- src/routes/login/+page.svelte -->
<script>
let { form } = $props();
</script>
<form method="POST">
<input name="email" value={form?.email || ''}>
<input name="password" type="password">
<button>Log in</button>
{#if form?.missing}<p>Missing fields</p>{/if}
{#if form?.invalid}<p>Invalid credentials</p>{/if}
</form>
Working with Svelte Flow
Svelte Flow is our visual workflow builder. Basic usage:
<script>
import { SvelteFlow, Background, Controls } from 'svelte-flow';
import { writable } from 'svelte/store';
const nodes = $state([
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 25 }
}
]);
const edges = $state([]);
</script>
<div style="height: 800px; width: 100%;">
<SvelteFlow {nodes} {edges}>
<Background />
<Controls />
</SvelteFlow>
</div>
Using shadcn-svelte
shadcn-svelte provides customizable UI components:
<script>
import { Button } from "$lib/components/ui/button";
import { Input } from "$lib/components/ui/input";
</script>
<div>
<Input placeholder="Enter your name" />
<Button>Submit</Button>
</div>
Development Workflow
Creating a New SvelteKit Project
# Create a new SvelteKit project
pnpm create svelte@latest my-app
# Select options:
# - Skeleton project
# - TypeScript
# - ESLint, Prettier, Vitest, etc.
# Navigate to the project
cd my-app
# Install dependencies
pnpm install
Starting the Development Server
# Navigate to the frontend app
cd apps/frontend
# Install dependencies
pnpm install
# Start the development server
pnpm dev
Building for Production
Running Tests
Best Practices
State Management
-
Use Runes for Component State: Prefer Svelte 5's runes (
$state,$derived,$effect) over external state management libraries. -
Shared State: For state shared between components, use stores in
$lib/stores/. -
API State: Use svelte-query for API data fetching and caching.
-
Server State: Use SvelteKit's
loadfunctions for server-side data loading. -
Form State: Use SvelteKit's form actions with Superforms for form handling.
Component Design
-
Atomic Design: Follow atomic design principles (atoms, molecules, organisms, templates, pages).
-
Props Typing: Always type your component props:
<script>
let { title, description = 'Default description' } = $props<{
title: string;
description?: string;
}>();
</script>
-
Component Documentation: Document components with JSDoc comments.
-
Layout Structure: Use SvelteKit layouts for shared UI elements.
-
Route Organization: Group related routes in directories.
Performance Considerations
-
Avoid Unnecessary Reactivity: Don't make values reactive if they don't need to be.
-
Use
$derivedfor Computed Values: Instead of computing values in the template or in effects. -
Lazy Loading: Use dynamic imports for large components that aren't immediately needed.
Troubleshooting
Common Issues
-
pnpm Resolution Issues: If you encounter dependency resolution issues, try:
-
TypeScript Errors: Ensure your
tsconfig.jsonis properly configured for Svelte 5. -
Svelte Flow Node Types: If you encounter type issues with Svelte Flow nodes, check the type definitions and ensure you're using the correct properties.
Debugging
-
Svelte DevTools: Install the Svelte DevTools browser extension for debugging.
-
Vite Debugging: Use the
--debugflag with Vite for more verbose output:
Deployment
SvelteKit provides adapters for various deployment platforms:
Update svelte.config.js:
import adapter from '@sveltejs/adapter-cloudflare';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter()
}
};
export default config;
Build for production:
Resources
- Svelte 5 Documentation
- SvelteKit Documentation
- pnpm Documentation
- Svelte Flow Documentation
- shadcn-svelte Documentation
- Superforms Documentation
Migration Notes
From React to Svelte
If you're familiar with React, here are some key differences when working with Svelte:
-
No Virtual DOM: Svelte compiles your components to efficient imperative code.
-
Reactivity vs. Hooks: Svelte's reactivity system is more intuitive than React hooks.
-
Scoped CSS: CSS in Svelte components is scoped by default.
-
Less Boilerplate: Svelte generally requires less code than equivalent React components.
-
Transitions and Animations: Built-in transition and animation systems.
From Next.js to SvelteKit
If you're familiar with Next.js, here are some key differences when working with SvelteKit:
-
File Structure: SvelteKit uses
+page.svelteand+layout.svelteinstead ofpage.tsxandlayout.tsx -
Data Loading: SvelteKit uses
loadfunctions instead ofgetServerSidePropsor React Server Components -
API Routes: SvelteKit uses
+server.tsfiles with HTTP method exports instead of API handlers -
Form Handling: SvelteKit has built-in form actions with progressive enhancement
-
Middleware: SvelteKit uses
hooks.server.tsinstead of middleware files
Last updated: 2025-04-18