Next post: {next.title}
{/if} ``` ## Universal vs Server Load Functions **Server load functions** (`+page.server.js`, `+layout.server.js`): - Always run on the server - Can access database, filesystem, private env vars - Must return serializable data - Have access to `cookies`, `locals`, etc. **Universal load functions** (`+page.js`, `+layout.js`): - Run on server during SSR, then in browser - Useful for fetching from external APIs - Can return non-serializable data (like component constructors) - Receive data from server load functions via the `data` property ## Making Fetch Requests Use the provided `fetch` function for enhanced features: ```js // src/routes/items/[id]/+page.js export async function load({ fetch, params }) { const res = await fetch(`/api/items/${params.id}`); const item = await res.json(); return { item }; } ``` ## Headers and Cookies Set response headers: ```js export async function load({ fetch, setHeaders }) { const response = await fetch(url); setHeaders({ age: response.headers.get('age'), 'cache-control': response.headers.get('cache-control') }); return response.json(); } ``` Access cookies in server load functions: ```js export async function load({ cookies }) { const sessionid = cookies.get('sessionid'); return { user: await db.getUser(sessionid) }; } ``` ## Using Parent Data Access data from parent load functions: ```js export async function load({ parent }) { const { a } = await parent(); return { b: a + 1 }; } ``` ## Errors and Redirects Throw errors: ```js import { error } from '@sveltejs/kit'; export function load({ locals }) { if (!locals.user) { error(401, 'not logged in'); } } ``` Redirect users: ```js import { redirect } from '@sveltejs/kit'; export function load({ locals }) { if (!locals.user) { redirect(307, '/login'); } } ``` ## Streaming with Promises Server load functions can stream promises as they resolve: ```js export async function load({ params }) { return { comments: loadComments(params.slug), post: await loadPost(params.slug) }; } ``` ```svelte{comment.content}
{/each} {:catch error}error loading comments: {error.message}
{/await} ``` ## Rerunning Load Functions Load functions rerun when: - Referenced params or URL properties change - A parent load function reran and `await parent()` was called - A dependency was invalidated with `invalidate(url)` or `invalidateAll()` Manually invalidate load functions: ```js // In load function export async function load({ fetch, depends }) { depends('app:random'); // ... } // In component import { invalidate } from '$app/navigation'; function rerunLoadFunction() { invalidate('app:random'); } ``` ## Dependency Tracking Exclude from dependency tracking with `untrack`: ```js export async function load({ untrack, url }) { if (untrack(() => url.pathname === '/')) { return { message: 'Welcome!' }; } } ``` ## docs/kit/20-core-concepts/30-form-actions.md # Svelte Form Actions ## Default Actions Define a default action in `+page.server.js`: ```js /// file: src/routes/login/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { default: async (event) => { // TODO log the user in } }; ``` Use it with a simple form: ```svelte ``` From other pages, specify the action path: ```html ``` ## Named Actions Multiple actions in one page: ```js /// file: src/routes/login/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { login: async (event) => { // TODO log the user in }, register: async (event) => { // TODO register the user } }; ``` Invoke with query parameter: ```svelte ``` Use `formaction` for multiple actions in one form: ```svelte ``` > Note: Can't mix default and named actions ## Action Implementation ```js import * as db from '$lib/server/db'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password'); const user = await db.getUser(email); cookies.set('sessionid', await db.createSession(user), { path: '/' }); return { success: true }; } }; ``` Access returned data in component: ```svelte {#if form?.success}Successfully logged in! Welcome back, {data.user.name}
{/if} ``` ### Validation Errors Return errors with the `fail` function: ```js import { fail } from '@sveltejs/kit'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password'); if (!email) { return fail(400, { email, missing: true }); } const user = await db.getUser(email); if (!user || user.password !== db.hash(password)) { return fail(400, { email, incorrect: true }); } // Success case } }; ``` Handle errors in the component: ```svelte ``` ### Redirects ```js import { fail, redirect } from '@sveltejs/kit'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request, url }) => { // validation logic... if (url.searchParams.has('redirectTo')) { redirect(303, url.searchParams.get('redirectTo')); } return { success: true }; } }; ``` ## Loading Data After an action runs, the page's `load` functions run. If you modify cookies in an action, update `event.locals` too: ```js /// file: src/routes/account/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { logout: async (event) => { event.cookies.delete('sessionid', { path: '/' }); event.locals.user = null; } }; ``` ## Progressive Enhancement ### use:enhance Basic enhancement: ```svelte ``` Default behavior: - Updates `form` property and `page.form` (only for same-page actions) - Resets the form - Invalidates all data on success - Handles redirects and errors - Resets focus ### Customizing use:enhance ```svelte ``` To target `+page.server.js` actions with fetch: ```js const response = await fetch(this.action, { method: 'POST', body: data, headers: { 'x-sveltekit-action': 'true' } }); ``` ## GET Forms For forms that don't need to POST data: ```html ``` These navigate like `` elements and support the same data attributes for controlling router behavior. ## docs/kit/20-core-concepts/40-page-options.md # Svelte 5 Page Options ## Core Concepts ### Rendering Modes SvelteKit supports three rendering strategies: - **Server-Side Rendering (SSR)**: Default, renders on server first - **Client-Side Rendering (CSR)**: Hydrates server-rendered HTML - **Prerendering**: Generates static HTML at build time Options can be set in `+page.js`, `+page.server.js`, `+layout.js`, or `+layout.server.js`. Child pages override parent layouts. ## Page Options ### prerender Generate static HTML at build time: ```js /// file: +page.js/+page.server.js/+server.js export const prerender = true; // Enable for this route export const prerender = false; // Disable for this route export const prerender = 'auto'; // Prerender but keep in SSR manifest ``` **When to use prerendering**: - Content must be the same for all users - No need for `url.searchParams` during prerendering - Pages with [actions](form-actions) cannot be prerendered **Route conflicts**: Use file extensions for server routes to avoid conflicts: ``` src/routes/foo.json/+server.js // Creates foo.json src/routes/foo/bar.json/+server.js // Creates foo/bar.json ``` ### entries For dynamic routes that need prerendering: ```js /// file: src/routes/blog/[slug]/+page.server.js /** @type {import('./$types').EntryGenerator} */ export function entries() { return [ { slug: 'hello-world' }, { slug: 'another-blog-post' } ]; } export const prerender = true; ``` ### ssr Disable server-side rendering: ```js /// file: +page.js export const ssr = false; // Creates empty shell page, renders only on client ``` ### csr Disable client-side rendering: ```js /// file: +page.js export const csr = false; // No JavaScript sent to client, links cause full page navigation ``` Enable CSR only during development: ```js /// file: +page.js import { dev } from '$app/environment'; export const csr = dev; ``` ### trailingSlash Control URL trailing slashes: ```js /// file: src/routes/+layout.js export const trailingSlash = 'always'; // '/about/' format // Options: 'never' (default), 'always', 'ignore' ``` ### config Platform-specific configuration for adapters: ```js /// file: src/routes/+page.js /** @type {import('some-adapter').Config} */ export const config = { runtime: 'edge' }; ``` Config objects merge at the top level but not deeper levels. ## Best Practices - Use prerendering for static content - Use SSR for dynamic, SEO-important pages - Use CSR-only (SPA mode) for admin sections - Avoid ignoring trailing slashes (harmful for SEO) - Keep browser-only code in component files, not in page option files ## docs/kit/20-core-concepts/50-state-management.md # Svelte 5 State Management ## Server State Guidelines ### Avoid Shared State on Server Servers are stateless and shared by multiple users. Never store user data in shared variables: ```js // NEVER DO THIS! let user; // Shared by all users export function load() { return { user }; } export const actions = { default: async ({ request }) => { const data = await request.formData(); user = { // BAD: exposes one user's data to others name: data.get('name'), secret: data.get('secret') }; } } ``` Instead, authenticate users with cookies and store data in databases. ### No Side-Effects in Load Load functions should be pure: ```js // NEVER DO THIS! import { user } from '$lib/user'; export async function load({ fetch }) { const response = await fetch('/api/user'); user.set(await response.json()); // BAD: shared state } ``` Instead, return the data: ```js export async function load({ fetch }) { const response = await fetch('/api/user'); return { user: await response.json() }; } ``` ## Using Context for State Use Svelte's context API for component tree state: ```svelte ``` ```svelteWelcome {user().name}
``` > Pass functions to `setContext` to maintain reactivity across boundaries. ## Component State Preservation SvelteKit reuses components during navigation. Make values reactive to handle updates: ```svelte ``` Correct approach: ```svelte ``` To force component remounting on navigation: ```svelte {#key page.url.pathname}Status: %sveltekit.status%
Message: %sveltekit.error.message%
``` ## Type Safety Customize error shape with TypeScript: ```ts declare global { namespace App { interface Error { code: string; id: string; } } } export {}; ``` ## docs/kit/30-advanced/30-link-options.md # Link Options in SvelteKit SvelteKit uses standard `` elements for navigation between routes. When clicking a link within your app, SvelteKit imports the code and calls necessary `load` functions to fetch data. ## data-sveltekit-preload-data Controls when data preloading begins: - `"hover"` - starts on mouse hover or mobile `touchstart` - `"tap"` - starts on `touchstart` or `mousedown` Default setup in `app.html`: ```html