Rilasciato · in miglioramento
Guida a SvelteKit · 4/6
Per ora questo capitolo è disponibile solo in inglese.
In SvelteKit you read page data with load functions and change data with form actions. This chapter covers both, along with API endpoints, server-only modules, environment variables and state shared between components.
A load in +page.ts is a universal load: it runs on the server for the first request and in the browser for later client-side navigations. A load in +page.server.ts is a server load: it always runs on the server, so it can talk to a database or use secret keys. Either way, the object it returns becomes the page's data prop.
// src/routes/blog/[slug]/+page.server.ts
import { error } from '@sveltejs/kit';
import { db } from '#lib/server/db.js';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
const post = await db.post.findBySlug(params.slug);
if (!post) error(404, 'Post not found');
return { post };
};<!-- src/routes/blog/[slug]/+page.svelte -->
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<h1>{data.post.title}</h1>
<p>{data.post.summary}</p>./$types is generated by SvelteKit for each route, so params.slug and data.post are typed automatically. Calling error() or redirect() stops execution immediately, so there is no need to throw them. In a universal load, use the fetch passed in as an argument: during SSR it handles cookies and relative URLs correctly, and its responses are inlined into the HTML so the browser does not repeat the request. Data returned from a layout's load is merged into the data of child pages, and child loads can read it with await parent().
A +server.ts file exports functions named after HTTP methods. Each receives a standard Request and returns a Response; use the standard Response.json() for JSON.
// src/routes/api/search/+server.ts
import type { RequestHandler } from './$types';
import { searchPosts } from '#lib/server/search.js';
export const GET: RequestHandler = async ({ url }) => {
const q = url.searchParams.get('q') ?? '';
const results = await searchPosts(q);
return Response.json({ q, results });
};Mutations belong in the actions export of +page.server.ts. They work with a plain <form method="POST">, so they function without JavaScript, and adding use:enhance updates the page in place without a full reload. When validation fails, return with a status code and data for the form.
fail()// src/routes/subscribe/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
import { db } from '#lib/server/db.js';
import type { Actions } from './$types';
export const actions = {
default: async ({ request }) => {
const form = await request.formData();
const email = String(form.get('email') ?? '');
if (!email.includes('@')) {
return fail(400, { email, invalid: true });
}
await db.subscriber.create({ email });
redirect(303, '/subscribe/thanks');
}
} satisfies Actions;<script lang="ts">
import { enhance } from '$app/forms';
import type { PageProps } from './$types';
let { form }: PageProps = $props();
</script>
<form method="POST" use:enhance>
<input name="email" type="email" value={form?.email ?? ''} />
{#if form?.invalid}<p class="error">Please check your email address.</p>{/if}
<button>Subscribe</button>
</form>With several actions, give each a name in actions and target it with action="?/register".
A module with a server segment in its file name (db.server.ts) or inside a server folder (src/lib/server/) cannot be imported by browser code; if it is, the build fails with an error. Environment variables are declared in src/env.ts and imported from $app/env/private or $app/env/public. Variables are private by default; only those marked public: true are available in the browser.
// src/env.ts
import { defineEnvVars } from '@sveltejs/kit/env';
export const variables = defineEnvVars({
DATABASE_URL: {},
SITE_NAME: { public: true }
});
// then, in src/lib/server/db.ts:
// import { DATABASE_URL } from '$app/env/private';The $env/* modules you may see in older material, such as $env/static/private, are deprecated in the current release. For per-request values like the signed-in user, set them on event.locals in the handle hook of src/hooks.server.ts and read them in server loads and actions.
When several components need the same state, put $state in a .svelte.ts file and export it. Runes are allowed in files with that extension.
// src/lib/cart.svelte.ts
export const cart = $state({ items: [] as { id: string; qty: number }[] });
export function addToCart(id: string) {
const found = cart.items.find((item) => item.id === id);
if (found) found.qty += 1;
else cart.items.push({ id, qty: 1 });
}Be careful on the server, though: it is a single long-lived process shared by every user, so per-user data stored in module-level state can leak between requests. Pass per-user data down from load through data, or attach it to the component tree with Svelte's setContext and getContext, which are created fresh for each request. State that should survive a reload, such as filters or sort order, fits well in URL search params like ?sort=price. Stores from svelte/store, such as writable, still work, but runes are the default for new code.
load in +page.ts (universal) or +page.server.ts (server).use:enhance; build external APIs with +server.ts.server modules and $app/env/private.$state in .svelte.ts files, but never keep per-user data in server module state.
0 commenti
Accedi · Accedi per lasciare un commento.
Scrivi tu il primo commento.