- name
- sveltekit-config
- license
- Apache-2.0
- description
- SvelteKit 配置/构建/部署/性能技能。当用户配置 adapter(node/static/cloudflare/netlify/vercel)、使用 advanced routing/layouts、优化性能(代码分割/asset/hydration)、处理 images(@sveltejs/enhanced-img)、实现 accessibility/SEO、调试 SvelteKit 应用、从 SvelteKit v1/Sapper 迁移时使用。
# SvelteKit Config
## When to use this skill
Use this skill whenever you are working on SvelteKit's configuration, build pipeline, deployment, performance, images, accessibility, SEO, debugging, or migration concerns. This includes:
- Choosing or configuring an adapter (`adapter-node`, `adapter-static`, `adapter-cloudflare`, `adapter-netlify`, `adapter-vercel`)
- Building (`vite build`) and previewing (`vite preview`) production apps
- Advanced routing (rest params, optional params, matchers, route sorting, filename encoding)
- Advanced layouts (route groups, breaking out of layouts with `@`)
- Auth integration patterns (sessions vs tokens, hooks-based auth)
- Performance optimization (code splitting, asset opt, avoiding waterfalls)
- Image handling (`@sveltejs/enhanced-img`, CDN loading, `<picture>`/`<img>` patterns)
- Accessibility (route announcements, focus management, `lang` attribute)
- SEO (titles, meta tags, sitemaps, JSON-LD)
- Breakpoint debugging (VS Code, Chrome DevTools)
- Migrating from SvelteKit v1 or Sapper
For routing/data/load basics, see `sveltekit-overview`. For Svelte components/runes, see `svelte-runes`.
## Critical: Building and previewing
`vite build` runs in two stages: Vite produces an optimized production build, then your adapter tailors the output for the target platform. Prerendering executes during build.
During the build, SvelteKit loads your `+page/layout(.server).js` for analysis. Code that must NOT run at build time should guard with `building` from `$app/environment`:
```js
import { building } from '$app/environment';
import { initialiseDatabase } from '$lib/server/database';
if (!building) initialiseDatabase();
export function load() { /* ... */ }
```
After building, run `vite preview` (or `npm run preview`) to test the production build locally. Preview runs in Node, so adapter-specific behavior (e.g. Cloudflare's `platform` object) does NOT apply — use `wrangler dev` for Cloudflare or the platform's CLI for accurate testing.
```sh
npm run build # vite build + adapter
npm run preview # vite preview (Node)
```
## Critical: Adapters — when to use which
The adapter is configured in `svelte.config.js` under `kit.adapter`. `adapter-auto` ships by default in new projects and picks the right adapter for known deployment environments (Cloudflare Pages, Netlify, Vercel, Azure SWA, SST, Google Cloud Run). Once you've chosen a target, install that adapter explicitly so it lands in your lockfile.
| Target | Adapter | Notes |
|---------------------------------|----------------------------------|-------|
| Node server / Docker / VM | `@sveltejs/adapter-node` | Standalone Node server. Most flexible. |
| Static hosting (no SSR) | `@sveltejs/adapter-static` | SSG or SPA fallback. |
| Cloudflare Workers / Pages | `@sveltejs/adapter-cloudflare` | Unified adapter for both. |
| Netlify | `@sveltejs/adapter-netlify` | Node functions or Deno edge. |
| Vercel | `@sveltejs/adapter-vercel` | Serverless or edge, ISR support. |
Adapter quick guide:
```js
// svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default { kit: { adapter: adapter() } };
```
### Platform-specific context
Some adapters expose platform info (KV namespaces, Durable Objects, env vars) via `event.platform` in hooks/server routes. Type augmentation in `src/app.d.ts`:
```ts
declare global {
namespace App {
interface Platform {
env: { MY_KV: KVNamespace };
}
}
}
export {};
```
Always prefer `$env/static/private` for environment variables — `$env/dynamic/*` cannot be used during prerendering.
## Critical: Advanced routing
SvelteKit routes are filesystem-based. Beyond basic dynamic segments, you have several advanced features.
### Rest parameters — `[...rest]`
Match an unknown number of segments. `src/routes/a/[...rest]/z/+page.svelte` matches `/a/z`, `/a/b/z`, `/a/b/c/z`. The `rest` param is a string with `/`-separated segments.
```tree
src/routes/[org]/[repo]/tree/[branch]/[...file]/+page.svelte
```
Use rest parameters to render custom 404s — add `[...path]/+page.js` that calls `error(404)` so a nested `+error.svelte` is reached.
### Optional parameters — `[[lang]]`
Wrap with double brackets to make a param optional. `[[lang]]/home` matches both `/home` and `/en/home`. An optional param cannot follow a rest param.
### Matching — `[name=type]`
Constrain a parameter with a matcher from `src/params/`:
```js
// src/params/fruit.js
/** @type {import('@sveltejs/kit').ParamMatcher} */
export function match(param) {
return param === 'apple' || param === 'orange';
}
```
Then write `src/routes/fruits/[page=fruit]/+page.svelte`. Matchers run on both server and browser.
### Sorting
When multiple routes match, SvelteKit sorts by:
1. More specific routes win (fewer params = more specific)
2. Matchers (`[name=type]`) beat unconstrained (`[name]`)
3. `[[optional]]` and `[...rest]` are lowest priority unless they're the final segment
4. Ties resolved alphabetically
### Encoding special characters
Use hex escape `[x+nn]` in folder names: `/` → `[x+2f]`, `:` → `[x+3a]`, etc. Use `[u+nnnn]` for Unicode (no surrogate pairs needed).
```tree
src/routes/smileys/[x+3a]-[x+29]/+page.svelte
# matches /smileys/:-)
```
## Critical: Advanced layouts
By default, the layout hierarchy mirrors the folder hierarchy. Use these patterns to reshape it.
### Route groups — `(group)`
Parentheses-wrapped folder names don't appear in the URL. Use to share a layout between routes without affecting URL structure.
```tree
src/routes/
├ (app)/dashboard/+page.svelte
├ (app)/+layout.svelte # app shell
├ (marketing)/about/+page.svelte
├ (marketing)/+layout.svelte # marketing shell
└ +layout.svelte
```
### Breaking out — `+page@layout.svelte`
Append `@<segment>` (or `@` for root) to reset the layout chain. `+page@(app).svelte` inherits only from `(app)/+layout.svelte`.
Options: `+page@[id].svelte`, `+page@item.svelte`, `+page@(app).svelte`, `+page@.svelte`.
Layouts can also break out: `+layout@.svelte` rewinds to root for everything below it.
### Reset to root
If you want most of your app under one layout but a few routes to escape, put everything inside a group except the outliers:
```tree
src/routes/
├ (app)/...
└ admin/+page.svelte # does NOT inherit (app) layout
```
## Critical: Auth integration
Auth = authentication (who is this?) + authorization (what can they do?).
### Sessions vs tokens
- **Sessions**: ID stored in DB. Revocable instantly, requires DB lookup per request.
- **JWT tokens**: Self-contained, no DB lookup, but cannot be revoked immediately. Better latency.
### Integration pattern
Check auth cookies in `src/hooks.server.js`, populate `event.locals.user`, then read `locals` in `+page.server.js` / `+server.js` load functions.
```js
// src/hooks.server.js
export async function handle({ event, resolve }) {
event.locals.user = await getUser(event.cookies.get('session'));
return resolve(event);
}
```
### Libraries
- `npx sv add better-auth` — Better Auth integration via Svelte CLI
- [Lucia auth guide](https://lucia-auth.com/) — reference SvelteKit examples for session-based auth
Always require `path: '/'` when calling `cookies.set(...)` in SvelteKit v2.
## Critical: Performance optimization
SvelteKit ships with: code-splitting, asset preloading, file hashing, request coalescing, parallel loading, data inlining, conservative invalidation, link preloading. To go further:
### Diagnose
- PageSpeed Insights / Lighthouse / WebPageTest
- Chrome DevTools Network + Performance tabs
- Test in **preview mode** (after `vite build`), not dev mode
### Assets
- Use `@sveltejs/enhanced-img` for images (smaller formats, intrinsic dimensions)
- Lazy-load below-the-fold videos with `preload="none"`
- Subset fonts; preload critical fonts via `handle` hook's `preload` filter
### Code size
- Use Svelte 5 (smaller than 4)
- Use `rollup-plugin-visualizer` to find heavy packages
- Prefer dynamic `import()` for conditional code
- Push third-party scripts to web workers (Partytown)
### Avoid waterfalls
- Use **server `load` functions** for backend calls (avoid client → server → backend chains)
- Issue parallel queries with `Promise.all` / DB joins
- SPA mode causes waterfalls — prerender instead
### Hosting
- Deploy frontend near backend (or use edge)
- Ensure HTTP/2+
## Critical: Images
### Vite's built-in handling
```svelte
<script>
import logo from '$lib/assets/logo.png';
</script>
<img alt="logo" src={logo} />
```
Vite hashes the filename and inlines small assets.
### @sveltejs/enhanced-img
Build-time image optimization: generates `avif`/`webp`, sets intrinsic `width`/`height` (prevents CLS), strips EXIF.
```js
// vite.config.js — plugin order matters
import { enhancedImages } from '@sveltejs/enhanced-img';
import { sveltekit } from '@sveltejs/kit/vite';
export default { plugins: [enhancedImages(), sveltekit()] };
```
Usage:
```svelte
<enhanced:img src="./image.jpg" alt="..." sizes="min(1280px, 100vw)" />
```
Generated `<picture>` includes multiple formats and sizes for HiDPI. Provide 2x source for retina displays.
Custom widths: `<enhanced:img src="./image.png?w=1280;640;400" />`
Per-image transforms: `<enhanced:img src="./image.jpg?blur=15" />`
### Dynamic CDN loading
For images unavailable at build time (CMS, DB), use a CDN library:
- `@unpic/svelte` — CDN-agnostic
- `svelte-cloudinary` — Cloudinary
- CMS-bundled: Contentful, Storyblok, Contentstack
### Best practices
- Set `fetchpriority="high"` and avoid `loading="lazy"` for LCP images
- Always provide `alt` text
- Don't use `em`/`rem` in `sizes`
- Mix strategies: Vite for `<meta>`, enhanced-img for hero, CDN for user content
## Critical: Accessibility
SvelteKit provides an accessible foundation; you're still responsible for app-level a11y.
### Route announcements
SvelteKit injects a live region that reads the `<title>` after each client-side navigation. Every page must have a unique, descriptive `<title>` in a `<svelte:head>`:
```svelte
<svelte:head>
<title>Todo List</title>
</svelte:head>
```
### Focus management
After each navigation, SvelteKit focuses `<body>` (or `[autofocus]` element if present). Override with `afterNavigate` for custom behavior:
```js
import { afterNavigate } from '$app/navigation';
afterNavigate(() => document.querySelector('.focus-me')?.focus());
```
Use `data-sveltekit-keepfocus` on a `<form>` to preserve input focus. `goto(url, { keepFocus: true })` for programmatic nav.
### `lang` attribute
Set `<html lang="en">` (or your language) in `src/app.html`. For multi-language sites, use a `transformPageChunk` in `handle` to set per-request.
## Critical: SEO
SvelteKit ships with SSR, normalized trailing-slash URLs, and good defaults. Manual steps:
### Per-page meta
```svelte
<svelte:head>
<title>Page Title — Site Name</title>
<meta name="description" content="..." />
<meta property="og:title" content="..." />
<meta property="og:description" content="..." />
<meta property="og:image" content="..." />
<meta property="og:type" content="website" />
<link rel="canonical" href="https://..." />
</svelte:head>
```
Common pattern: return SEO data from `load`, render in root layout's `<svelte:head>`.
### Sitemap
```js
// src/routes/sitemap.xml/+server.js
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
عرض على GitHub