Документация
Введение permalink
Важное замечание
SvelteKit ещё в ранней стадии разработки, и некоторые вещи могут поменяться, когда мы дойдём до релиза 1.0. Этот документ всё ещё дорабатывается. Если у вас появятся вопросы, обратитесь за помощью в русскоязычный канал в Telegram.
Прочтите руководство по миграции для помощи при переходе с Sapper.
Что такое SvelteKit?
SvelteKit — это фреймворк для создания высокопроизводительных веб-приложений.
Создание приложения с учётом всех современных передовых практик — невероятно сложная задача. Эти практики включают в себя оптимизацию сборки, так что вы загружаете только минимальный необходимый код; поддержку работы без сети; предзагрузку данных страницы до того, как пользователь перейдет на следующую страницу; и настраиваемый рендеринг, который позволяет генерировать HTML на сервере или в браузере во время выполнения или во время сборки. Все эти скучные вещи SvelteKit сделает за вас, а вы можете сотредоточиться на творческой части проекта.
SvelteKit использует Vite вместе со Svelte plugin, что даёт множество возможностей и молниеносную разработку с горячей заменой модулей (HMR), где изменения вашего кода мгновенно отражаются в браузере.
Чтобы понять это руководство, знать Svelte не обязательно, но желательно. Если коротко, Svelte — это фреймворк, который компилирует ваши компоненты в высокооптимизированный ванильный JavaScript. Прочтите вводную статью в блоге Svelte и учебник Svelte, чтобы узнать о нём побольше.
Начало работы
Самый простой способ создать приложение SvelteKit — запустить команду npm init
:
npm init svelte my-app
cd my-app
npm install
npm run dev
Первая команда создаст базовый проект в каталоге my-app
, а также спросит о настройке некоторых базовых инструментов, вроде TypeScript. Обратитесь в раздел FAQ, чтобы узнать о некоторых особенностях настройки дополнительных инструментов. Остальные команды установят необходимые зависимости и запустят проект на localhost:3000.
Вот два наших основных принципа:
- Каждая страница вашего приложения является компонентом Svelte
- Вы создаёте новые страницы путём добавления компонентов в директорию
src/routes
. Они будут рендериться на сервере, так что время первой загрузки приложения для пользователя будет максимально быстрым, а уже затем клиентское приложение возьмёт управление на себя.
Попробуйте поредактировать файлы, чтобы понять, как все работает, и, возможно, даже не придется читать остальную часть этого руководства!
Настройка редактора
Мы рекомендуем использовать Visual Studio Code (он же VS Code) с расширением Svelte, но поддерживается также и множество других редакторов.
Project Structure permalink
A typical SvelteKit project looks like this:
my-project/
├ src/
│ ├ lib/
│ │ └ [your lib files]
│ ├ params/
│ │ └ [your param matchers]
│ ├ routes/
│ │ └ [your routes]
│ ├ app.html
│ └ hooks.js
├ static/
│ └ [your static assets]
├ package.json
├ svelte.config.js
├ tsconfig.json
└ vite.config.js
You'll also find common files like .gitignore
and .npmrc
(and .prettierrc
and .eslintrc.cjs
and so on, if you chose those options when running npm create svelte@latest
).
Project files
src
The src
directory contains the meat of your project.
lib
contains your library code, which can be imported via the$lib
alias, or packaged up for distribution usingsvelte-kit package
params
contains any param matchers your app needsroutes
contains the pages and endpoints of your applicationapp.html
is your page template — an HTML document containing the following placeholders:%sveltekit.head%
—<link>
and<script>
elements needed by the app, plus any<svelte:head>
content%sveltekit.body%
— the markup for a rendered page%sveltekit.assets%
— a relative path from the page topaths.assets
%sveltekit.nonce%
— a CSP nonce for manually included links and scripts, if used
hooks.js
(optional) contains your application's hooksservice-worker.js
(optional) contains your service worker
You can use .ts
files instead of .js
files, if using TypeScript.
static
Any static assets that should be served as-is, like robots.txt
or favicon.png
, go in here.
package.json
Your package.json
file must include @sveltejs/kit
, svelte
and vite
as devDependencies
.
When you create a project with npm create svelte@latest
, you'll also notice that package.json
includes "type": "module"
. This means that .js
files are interpreted as native JavaScript modules with import
and export
keywords. Legacy CommonJS files need a .cjs
file extension.
svelte.config.js
This file contains your Svelte and SvelteKit configuration.
tsconfig.json
This file (or jsconfig.json
, if you prefer type-checked .js
files over .ts
files) configures TypeScript, if you added typechecking during npm create svelte@latest
. Since SvelteKit relies on certain configuration being set a specific way, it generates its own .svelte-kit/tsconfig.json
file which your own config extends
.
vite.config.js
A SvelteKit project is really just a Vite project that uses the @sveltejs/kit/vite
plugin, along with any other Vite configuration.
Other files
test
If you choose to add tests during npm create svelte@latest
, they will go in a test
directory.
.svelte-kit
As you develop and build your project, SvelteKit will generate files in a .svelte-kit
directory (configurable as outDir
). You can ignore its contents, and delete them at any time (they will be regenerated when you next dev
or build
).
Веб-стандарты permalink
В этой документации вы увидите ссылки на стандартные Web API, на основе которого SvelteKit строит. Вместо того, чтобы заново изобретать колесо, мы используем платформу, что означает, что ваши существующие навыки веб-разработки применимы к SvelteKit. И наоборот, время, потраченное на изучение SvelteKit, поможет вам стать лучшим веб-разработчиком в другом месте.
Эти API доступны во всех современных браузерах и во многих небраузерных средах, таких как Cloudflare Workers, Deno и Vercel Edge Functions. Во время разработки и в адаптерах для сред на основе NodeJS (включая AWS Lambda) они доступны через полифиллы, где это необходимо (пока - Node быстро добавляет поддержку большего количества веб-стандартов).
В частности, вы освоитесь со следующим:
Fetch APIs
SvelteKit использует fetch
для получения данных из сети. Он доступен в хуках и эндпоинтах, а также в браузере.
Специальная версия
fetch
доступна в функцияхload
для вызова эндпоинтов непосредственно во время рендеринга на стороне сервера, без вызова HTTP, сохраняя при этом учетные данные. (Чтобы сделать учетные данные в коде на стороне сервера за пределамиload
, вы должны явно передать заголовкиcookie
и/илиauthorization
.) Это также позволяет делать относительные запросы, но для выборки на стороне сервера обычно требуется полный URL-адрес.
Помимо самой fetch
, Fetch API включает в себя следующие интерфейсы:
Request
Экземпляр Request
доступен в хуках и эндпоинтах как event.request
. Он содержит полезные методы, такие как request.json()
и request.formData()
, например, для получения данных, которые были размещены на эндпоинте.
Response
Экземпляр Response
возвращается из await fetch(...)
. По сути, приложение SvelteKit - это машина для превращения Request
в Response
.
Headers
Интерфейс Headers
позволяет читать входящие request.headers
и устанавливать исходящие response.headers
:
// @errors: 2461
/// file: src/routes/what-is-my-user-agent.js
/** @type {import('@sveltejs/kit').RequestHandler} */
export function get(event) {
// log all headers
console.log(...event.request.headers);
return {
body: {
// retrieve a specific header
userAgent: event.request.headers.get('user-agent')
}
};
}
URL APIs
URL-адреса представлены интерфейсом URL
, который включает в себя полезные свойства, такие как origin
и pathname
(и, в браузере, hash
). Этот интерфейс отображается в различных местах — event.url
в хуках и эндпоинтах, $page.url
в pages, from
и to
в [beforeNavigate
и afterNavigate
] (#moduli-$app-navigation) и так далее.
URLSearchParams
Где бы вы ни столкнулись с URL-адресом, вы можете получить доступ к параметрам запроса через url.searchParams
, который является экземпляром URLSearchParams
:
// @filename: ambient.d.ts
declare global {
const url: URL;
}
export {};
// @filename: index.js
// ---cut---
const foo = url.searchParams.get('foo');
Web Crypto
Web Crypto API доступен через глобальный объект "crypto". Он используется внутри для заголовков Политика безопасности контента, но вы также можете использовать его для таких вещей, как генерация UUID:
const uuid = crypto.randomUUID();
Маршруты permalink
Сердцем SvelteKit является роутер основанный на файловой системе. Это означает, что структура вашего приложения определяется структурой файлов его исходников – в частности содержимым папки src/routes
.
Можно указать другую директорию в файле конфигурации проекта.
Существует два типа маршрутов — страницы и эндпоинты.
Страницы обычно отдают HTML-код для отображения пользователю ( а также CSS и JavaScript, необходимые странице). По умолчанию они отрисовываются как на сервере, так и на клиенте, но это поведение можно настроить.
Эндпоинты запускаются только на сервере (или при сборке сайта, если используется предварительная отрисовка). Это то место, где можно выполнять запросы к базам данных или API с приватной авторизацией, а также вывести иные данные которые доступны на сервере. Страницы могут получать данные от эндпоинтов. По умолчанию эндпоинты возвращают ответ в формате JSON, но могут также возвращать данные в любых других форматах.
Страницы
Страницы — это компоненты Svelte, описанные в файлах .svelte
(или любой файл с расширением, указанным в config.extensions
). По умолчанию, когда пользователь впервые посещает приложение, ему будет отправлена сгенерированная на сервере версия запрошенной страницы, а также некоторый JavaScript, который выполняет 'гидратацию' страницы и инициализирует роутер на стороне клиента. С этого момента навигация на другие страницы будет полностью выполняться на стороне клиента обеспечивая очень быстрое перемещение, что типично для клиентских приложений, где некоторая часть разметки не требует перерисовки.
Имя файла определяет маршрут. Например, src/routes/index.svelte
— корневой файл вашего сайта:
/// file: src/routes/index.svelte
<svelte:head>
<title>Добро пожаловать!</title>
</svelte:head>
<h1>Приветствую вас на моём сайте!</h1>
<a href="/about">О сайте</a>
Файл с именем src/routes/about.svelte
или src/routes/about/index.svelte
будет соответствовать маршруту /about
:
/// file: src/routes/about.svelte
<svelte:head>
<title>О сайте</title>
</svelte:head>
<h1>Информация о сайте</h1>
<p>Это самый лучший сайт!</p>
<a href="/">Главная</a>
Обратите внимание, что SvelteKit использует элементы
<a>
для навигации между маршрутами, а не компонент<Link>
, специфичный для платформы.
Динамические параметры задаются при помощи квадратных скобок [...]. Например, можно определить страницу, отображающую статью из блога, таким образом – src/routes/blog/[slug].svelte
. Доступ к этим параметрам можно получить с помощью функции load
или через хранилище page
.
Маршрут может иметь несколько динамических параметров, например src/routes/[category]/[item].svelte
или даже src/routes/[category]-[item].svelte
. (Параметры "не жадные"; в неоднозначном случае, таком как x-y-z
, category
будет x
, а item
будет y-z
.)
Эндпоинты
Эндпоинты - это модули, записанные в файлах .js
(или .ts
), которые экспортируют функции request handler, соответствующие HTTP методам. Они могут читать и записывать данные, доступные только на сервере (например, в базе данных или в файловой системе).
/// file: src/routes/items/[id].js
// @filename: ambient.d.ts
type Item = {};
declare module '$lib/database' {
export const get: (id: string) => Promise<Item>;
}
// @filename: __types/[id].d.ts
import type { RequestHandler as GenericRequestHandler } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<{ id: string }, Body>;
// @filename: index.js
// ---cut---
import db from '$lib/database';
/** @type {import('./__types/[id]').RequestHandler} */
export async function get({ params }) {
// `params.id` берётся из [id].js
const item = await db.get(params.id);
if (item) {
return {
body: { item }
};
}
return {
status: 404
};
}
Не беспокойтесь об импорте
$lib
, мы перейдем к этому позже.
Тип функции get
выше взят из файла ./[id].d.ts
, сгенерированного SvelteKit (внутри вашего outDir
с использованием опции rootDirs
, который обеспечивает безопасность типа при доступе к params
. Дополнительную информацию см. в разделе сгенерированные типы.
Цель обработчика запроса – вернуть объект { status, headers, body }
, который будет ответом на полученный запрос, где status
является кодом ответа HTTP:
2xx
— успешный ответ (по умолчанию200
)3xx
— перенаправление (используется совместно с заголовкомlocation
)4xx
— ошибка от клиента5xx
— ошибка на сервере
Эндпоинты страницы
Если эндпоинт имеет то же имя файла, что и страница (за исключением расширения), страница получает свойства от эндпоинта - через fetch
во время навигации на стороне клиента или через прямой вызов функции во время SSR.
Например страница src/routes/items/[id].svelte
, может получить свойства из body
в конечной точке выше:
/// file: src/routes/items/[id].svelte
<script>
// свойство будет задано ответом от эндпоинта
export let item;
</script>
<h1>{item.title}</h1>
Поскольку страница и маршрут имеют один и тот же URL-адрес, вам нужно будет включить заголовок accept: application/json
, чтобы получить JSON из конечной точки, а не HTML со страницы. Вы также можете получить необработанные данные, добавив /__data.json
к URL-адресу, например /items/[id]/__data.json
.
Автономные эндпоинты
Как мы видели ранее, чаще всего эндпоинты связаны со страницей, для которой передают данные. Однако они могут существовать и отдельно от страниц. Автономные эндпоинты имеют большую гибкость в отношении типа поля body
— кроме объекта, они также могут вернуть строку или Uint8Array
.
Поддержка потоковых запросов и ответов на подходе.
Автономные эндпоинты доступны с расширением файла или без него:
filename | endpoint |
---|---|
src/routes/data/index.json.js | /data.json |
src/routes/data.json.js | /data.json |
src/routes/data/index.js | /data |
src/routes/data.js | /data |
POST, PUT, PATCH, DELETE
Эндпоинты могут обрабатывать любой HTTP-метод, не только GET, путём экспорта соответствующей функции:
// @noErrors
export function post(event) {...}
export function put(event) {...}
export function patch(event) {...}
export function del(event) {...} // `delete` - зарезервированное слово
Как и get
, все эти функции могут возвращать объект body
, который будет передан странице в качестве значений её свойств. Ответы со статусом 4xx/5xx на GET-запросы приведут к отображению страницы с ошибкой. Аналогичные ответы на запросы других HTTP-методов этого не сделают, что позволяет, например, передать и отрисовать ошибки валидации формы.
/// file: src/routes/items.js
// @filename: ambient.d.ts
type Item = {
id: string;
};
type ValidationError = {};
declare module '$lib/database' {
export const list: () => Promise<Item[]>;
export const create: (request: Request) => Promise<[Record<string, ValidationError>, Item]>;
}
// @filename: __types/items.d.ts
import type { RequestHandler as GenericRequestHandler } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<{}, Body>;
// @filename: index.js
// ---cut---
import * as db from '$lib/database';
/** @type {import('./__types/items').RequestHandler} */
export async function get() {
const items = await db.list();
return {
body: { items }
};
}
/** @type {import('./items').RequestHandler} */
export async function post({ request }) {
const [errors, item] = await db.create(request);
if (errors) {
// возвращаем ошибки валидации
return {
status: 400,
body: { errors }
};
}
// перенаправляем на страницу новой штуки
return {
status: 303,
headers: {
location: `/items/${item.id}`
}
};
}
/// file: src/routes/items.svelte
<script>
// У страницы всегда есть доступ к свойствам из `get`...
export let items;
// ...также добавляются свойства из `post`, если страница
// отрисовывается по POST-запросу, например после
// формы ниже
export let errors;
</script>
{#each items as item}
<Preview item={item}/>
{/each}
<form method="post">
<input name="title">
{#if errors?.title}
<p class="error">{errors.title}</p>
{/if}
<button type="submit">Создать штуку</button>
</form>
Получение данных запроса
Объект request
является экземпляром стандартного класса Request, поэтому получить данные из тела запроса не составит труда:
// @filename: ambient.d.ts
declare global {
const create: (data: any) => any;
}
export {};
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function post({ request }) {
const data = await request.formData(); // или .json(), или .text()
await create(data);
return { status: 201 };
}
Установка Cookie
Эндпоинты могут устанавливать Cookie, возвращая объект заголовков с set-cookie
. Чтобы установить несколько Cookie одновременно, верните массив:
// @filename: ambient.d.ts
const cookie1: string;
const cookie2: string;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').RequestHandler} */
export function get() {
return {
headers: {
'set-cookie': [cookie1, cookie2]
}
};
}
Переназначение HTTP методов
HTML-формы поддерживают только методы GET
и POST
. Вы можете указать другие допустимые методы, например PUT
и DELETE
, указав их в файле конфигурации, а затем добавлять параметр _method=МЕТОД
(укажите нужный метод) в аттрибуте формы action
:
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
methodOverride: {
allowed: ['PUT', 'PATCH', 'DELETE']
}
}
};
export default config;
<form method="post" action="/todos/{id}?_method=PUT">
<!-- элементы формы -->
</form>
Использование нативного поведения
<form>
гарантирует, что ваше приложение продолжит работать при сбое или отключении JavaScript.
Приватные модули
Файлы и каталоги, чьи имена начинаются с _
или .
(кроме .well-known
) по умолчанию являются приватными, т.е. они не создают маршруты (но могут быть импортированы файлами, которые это делают). В конфигурации проекта с помощью опции routes
можно указать, какие модули считать приватными, а какие будут создавать маршруты.
Расширенная маршрутизация
Rest-параметры
Если количество сегментов маршрута неизвестно, вы можете использовать синтаксис rest - например, вы можете реализовать средство просмотра файлов GitHub таким образом...
/[org]/[repo]/tree/[branch]/[...file]
И в данном случае запрос для маршрута /sveltejs/kit/tree/master/documentation/docs/01-routing.md
будет преобразован в следующие параметры, доступные на этой странице:
// @noErrors
{
org: 'sveltejs',
repo: 'kit',
branch: 'master',
file: 'documentation/docs/01-routing.md'
}
src/routes/a/[...rest]/z.svelte
будет соответствовать/a/z
(т.е. параметра вообще нет), а также/a/b/z
и/a/b/c/z
и так далее. Убедитесь, что значение параметра rest является допустимым, например, с помощью сопоставления.
Сопоставление
Маршрут, такой как src/routes/archive/[page]
, будет соответствовать /archive/3
, но он также будет соответствовать /archive/potato
. Мы этого не хотим. Вы можете убедиться, что параметры маршрута правильно сформированы, добавив matcher, который принимает строку параметров ("3"
или "potato"
) и возвращает true
, если он действителен - в каталог params
...
/// file: src/params/integer.js
/** @type {import('@sveltejs/kit').ParamMatcher} */
export function validate(param) {
return /^\d+$/.match(param);
}
...и расширение ваших маршрутов:
-src/routes/archive/[page]
+src/routes/archive/[page=integer]
Если путь не совпадает, SvelteKit попытается соответствовать другим маршрутам (используя порядок сортировки, указанный ниже), прежде чем в конечном итоге вернуть 404.
Сопоставления запускаются как на сервере, так и в браузере.
Сортировка
Это нужно, чтобы несколько маршрутов соответствовали данному пути. Например, каждый из этих маршрутов будет соответствовать /foo-abc
:
src/routes/[...catchall].svelte
src/routes/[a].js
src/routes/[b].svelte
src/routes/foo-[c].svelte
SvelteKit должен знать, какой маршрут запрашивается. Для этого он сортирует их по следующим правилам...
- Более конкретные маршруты имеют более высокий приоритет
- Автономные эндпоинты имеют более высокий приоритет, чем страницы с той же спецификой
- Параметры в сопоставлении маршрутов с (
[name=type]
) имеют более высокий приоритет, чем параметры без ([name]
) - Rest parameters имеют наименьшее приоритет
- Ties разрешаются в алфавитном порядке
...Результат этого порядка – /foo-abc
вызовет src/routes/foo-[bar].svelte
, а не менее конкретный маршрут:
src/routes/foo-[c].svelte
src/routes/[a].js
src/routes/[b].svelte
src/routes/[...catchall].svelte
Web standards permalink
Throughout this documentation, you'll see references to the standard Web APIs that SvelteKit builds on top of. Rather than reinventing the wheel, we use the platform, which means your existing web development skills are applicable to SvelteKit. Conversely, time spent learning SvelteKit will help you be a better web developer elsewhere.
These APIs are available in all modern browsers and in many non-browser environments like Cloudflare Workers, Deno and Vercel Edge Functions. During development, and in adapters for Node-based environments (including AWS Lambda), they're made available via polyfills where necessary (for now, that is — Node is rapidly adding support for more web standards).
In particular, you'll get comfortable with the following:
Fetch APIs
SvelteKit uses fetch
for getting data from the network. It's available in hooks and endpoints as well as in the browser.
A special version of
fetch
is available inload
functions for invoking endpoints directly during server-side rendering, without making an HTTP call, while preserving credentials. (To make credentialled fetches in server-side code outsideload
, you must explicitly passcookie
and/orauthorization
headers.) It also allows you to make relative requests, whereas server-sidefetch
normally requires a fully qualified URL.
Besides fetch
itself, the Fetch API includes the following interfaces:
Request
An instance of Request
is accessible in hooks and endpoints as event.request
. It contains useful methods like request.json()
and request.formData()
for e.g. getting data that was posted to an endpoint.
Response
An instance of Response
is returned from await fetch(...)
. Fundamentally, a SvelteKit app is a machine for turning a Request
into a Response
.
Headers
The Headers
interface allows you to read incoming request.headers
and set outgoing response.headers
:
// @errors: 2461
/// file: src/routes/what-is-my-user-agent.js
/** @type {import('@sveltejs/kit').RequestHandler} */
export function GET(event) {
// log all headers
console.log(...event.request.headers);
return {
body: {
// retrieve a specific header
userAgent: event.request.headers.get('user-agent')
}
};
}
Stream APIs
Most of the time, your endpoints will return complete data, as in the userAgent
example above. Sometimes, you may need to return a response that's too large to fit in memory in one go, or is delivered in chunks, and for this the platform provides streams — ReadableStream, WritableStream and TransformStream.
URL APIs
URLs are represented by the URL
interface, which includes useful properties like origin
and pathname
(and, in the browser, hash
). This interface shows up in various places — event.url
in hooks and endpoints, $page.url
in pages, from
and to
in beforeNavigate
and afterNavigate
and so on.
URLSearchParams
Wherever you encounter a URL, you can access query parameters via url.searchParams
, which is an instance of URLSearchParams
:
// @filename: ambient.d.ts
declare global {
const url: URL;
}
export {};
// @filename: index.js
// ---cut---
const foo = url.searchParams.get('foo');
Web Crypto
The Web Crypto API is made available via the crypto
global. It's used internally for Content Security Policy headers, but you can also use it for things like generating UUIDs:
const uuid = crypto.randomUUID();
Макеты permalink
До сих пор мы рассматривали страницы как полностью автономные компоненты — при переходе между страницами существующий компонент уничтожался, а новый занимал его место.
Но во многих приложениях есть элементы, которые должны быть видны на каждой странице, такие как навигация или подвал. Вместо того, чтобы повторять их на каждой странице, мы можем использовать компоненты макета.
Чтобы создать макет, который будет применяться к каждой странице приложения, создайте файл с именем src/routes/__layout.svelte
. По умолчанию макет (SvelteKit использует такой, если не найдет этого файла) выглядит следующим образом:
<slot></slot>
Мы можем добавить любую разметку, стили и поведение, которые мы хотим. Единственное требование — компонент должен иметь <slot>
для содержимого страницы. Например, давайте добавим панель навигации:
/// file: src/routes/__layout.svelte
<nav>
<a href="/">Главная</a>
<a href="/about">О сайте</a>
<a href="/settings">Настройки</a>
</nav>
<slot></slot>
Если мы создадим страницы для /
, /about
и /settings
...
/// file: src/routes/index.svelte
<h1>Главная</h1>
/// file: src/routes/about.svelte
<h1>О сайте</h1>
/// file: src/routes/settings.svelte
<h1>Настройки</h1>
...навигация всегда будет видна, и переход между тремя страницами приведёт только к замене содержимого элемента <h1>
.
Вложенные макеты
Предположим, что у нас не просто одна страница /settings
, а есть и вложенные страницы, вроде /settings/profile
и /settings/notifications
с общим подменю (для реального примера см. github.com/settings).
Мы можем создать макет, который применяется только к страницам, расположенным ниже /settings
(при этом останется и корневой макет с навигацией):
/// file: src/routes/settings/__layout.svelte
<h1>Настройки</h1>
<div class="submenu">
<a href="/settings/profile">Профиль</a>
<a href="/settings/notifications">Уведомления</a>
</div>
<slot></slot>
Именованные макеты
Некоторым частям вашего приложения может понадобиться что-то отличное от макета по умолчанию. В этих случаях можно создать именованные макеты...
/// file: src/routes/__layout-foo.svelte
<div class="foo">
<slot></slot>
</div>
...а затем используйте их, ссылаясь на имя макета (foo
, в примере выше) в имени файла:
/// file: src/routes/my-special-page@foo.svelte
<h1>I am inside __layout-foo</h1>
Область применения
Именованные макеты могут быть созданы на любой глубине и будут применяться к любым компонентам в том же поддереве. Например, __layout-foo
будет применяться к /x/one
и /x/two
, но не /x/three
или /four
:
src/routes/
├ x/
│ ├ __layout-foo.svelte
│ ├ one@foo.svelte # ✅ page has `@foo`
│ ├ two@foo.svelte # ✅ page has `@foo`
│ └ three.svelte # ❌ page does not have `@foo`
└ four@foo.svelte # ❌ page has `@foo`, but __layout-foo is not 'in scope'
Цепи наследования
Макеты сами могут наследовать от именованных макетов, из того же каталога или родительского каталога. Например, x/y/__layout@root.svelte
является макетом по умолчанию для /x/y
(что означает /x/y/one
, /x/y/two
и /x/y/three
наследуют от него), потому что у него нет имени. Поскольку он указывает @root
, он унаследует непосредственно от ближайшего __layout-root.svelte
, пропуская __layout.svelte
и x/__layout.svelte
.
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
├ __layout.svelte
└ __layout-root.svelte
В случае, когда
__layout-root.svelte
содержит только<slot />
, это фактически означает, что можно 'сбросить' на пустой макет для любой страницы или вложенного макета в приложении, добавив@root
.
Если родитель не указан, макет унаследует от ближайшего макета по умолчанию (т.е. безымянного) макета above в дереве. В некоторых случаях полезно, чтобы именованный макет унаследовал от макета по умолчанию наряду с ним в дереве, например, __layout-root.svelte
, наследующий от __layout.svelte
. Можно сделать это, явно указав @default
, разрешив /x/y/one
и братьям и сестрам использовать макет приложения по умолчанию без использования x/__layout.svelte
:
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
├ __layout.svelte
-└ __layout-root.svelte
+└ __layout-root@default.svelte
default
является зарезервированным именем - другими словами, нельзя назвать файл__layout-default.svelte
.
Страницы ошибок
Если страница не смогла загрузиться (см Загрузка данных), SvelteKit отобразит страницу ошибки. Вы можете настроить вид этой страницы, создав компонент __error.svelte
рядом с вашим макетом и страницами:
Например, если не удалось загрузить src/routes/settings/notifications/index.svelte
, SvelteKit отрисует src/routes/settings/notifications/__error.svelte
в том же макете, если он существует. В противном случае он отрисует src/routes/settings/__error.svelte
в родительском макете или src/routes/__error.svelte
в корневом макете.
В SvelteKit есть страница ошибок по умолчанию, если он не найдет файла
src/routes/__error.svelte
, но рекомендуется сделать свою.
Если в компоненте__error.svelte
есть функция load
, она будет вызываться со свойствами error
и status
:
<script context="module">
/** @type {import('@sveltejs/kit').Load} */
export function load({ error, status }) {
return {
props: {
title: `${status}: ${error.message}`
}
};
}
</script>
<script>
export let title;
</script>
<h1>{title}</h1>
Макеты также имеют доступ к
error
иstatus
через хранилище страницВо избежание того, чтобы пользователям стала доступна чувствительная информация, текст ошибок будет очищен от технических подробностей в продакшн режиме работы приложения.
404s
Вложенные страницы ошибок отображаются только тогда, когда возникает ошибка при рендеринге определенной страницы. В случае запроса, который не соответствует ни одному существующему маршруту, SvelteKit вместо этого отобразит общий 404. Например, учитывая эти маршруты...
src/routes/
├ __error.svelte
├ marx-brothers/
│ ├ __error.svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
...Файл marx-brothers/__error.svelte
не будет отображаться, если вы посетите /marx-brothers/karl
. Если вы хотите отобразить вложенную страницу ошибки, вы должны создать маршрут, соответствующий любому запросу /marx-brothers/*
, и вернуть из него 404:
src/routes/
├ __error.svelte
├ marx-brothers/
│ ├ __error.svelte
+│ ├ [...path].svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
/// file: src/routes/marx-brothers/[...path].svelte
<script context="module">
/** @type {import('./__types/[...path]').Load} */
export function load({ params }) {
return {
status: 404,
error: new Error(`Not found: /marx-brothers/${params.path}`)
};
}
</script>
Routing permalink
At the heart of SvelteKit is a filesystem-based router. This means that the structure of your application is defined by the structure of your codebase — specifically, the contents of src/routes
.
You can change this to a different directory by editing the project config.
There are two types of route — pages and endpoints.
Pages typically generate HTML to display to the user (as well as any CSS and JavaScript needed for the page). By default, pages are rendered on both the client and server, though this behaviour is configurable.
Endpoints run only on the server (or when you build your site, if prerendering). This means it's the place to do things like access databases or APIs that require private credentials or return data that lives on a machine in your production network. Pages can request data from endpoints. Endpoints return JSON by default, though may also return data in other formats.
Pages
Pages are Svelte components written in .svelte
files (or any file with an extension listed in config.extensions
). By default, when a user first visits the application, they will be served a server-rendered version of the page in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel where the common portions in the layout do not need to be rerendered.
The filename determines the route. For example, src/routes/index.svelte
is the root of your site:
/// file: src/routes/index.svelte
<svelte:head>
<title>Welcome</title>
</svelte:head>
<h1>Hello and welcome to my site!</h1>
<a href="/about">About my site</a>
A file called either src/routes/about.svelte
or src/routes/about/index.svelte
would correspond to the /about
route:
/// file: src/routes/about.svelte
<svelte:head>
<title>About</title>
</svelte:head>
<h1>About this site</h1>
<p>TODO...</p>
<a href="/">Home</a>
Note that SvelteKit uses
<a>
elements to navigate between routes, rather than a framework-specific<Link>
component.
Dynamic parameters are encoded using [brackets]
. For example, a blog post might be defined by src/routes/blog/[slug].svelte
. These parameters can be accessed in a load
function or via the page
store.
A route can have multiple dynamic parameters, for example src/routes/[category]/[item].svelte
or even src/routes/[category]-[item].svelte
. (Parameters are 'non-greedy'; in an ambiguous case like x-y-z
, category
would be x
and item
would be y-z
.)
Endpoints
Endpoints are modules written in .js
(or .ts
) files that export request handler functions corresponding to HTTP methods. Request handlers make it possible to read and write data that is only available on the server (for example in a database, or on the filesystem).
Their job is to return a { status, headers, body }
object representing the response.
/// file: src/routes/random.js
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function GET() {
return {
status: 200,
headers: {
'access-control-allow-origin': '*'
},
body: {
number: Math.random()
}
};
}
status
is an HTTP status code:2xx
— successful response (default is200
)3xx
— redirection (should be accompanied by alocation
header)4xx
— client error5xx
— server error
headers
can either be a plain object, as above, or an instance of theHeaders
classbody
can be a plain object or, if something goes wrong, anError
. It will be serialized as JSON
A GET
or HEAD
response must include a body
, but beyond that restriction all three properties are optional.
Page endpoints
If an endpoint has the same filename as a page (except for the extension), the page gets its props from the endpoint — via fetch
during client-side navigation, or via direct function call during SSR. (If a page uses syntax for named layouts or matchers in its filename then the corresponding page endpoint's filename must also include them.)
For example, you might have a src/routes/items/[id].svelte
page...
/// file: src/routes/items/[id].svelte
<script>
// populated with data from the endpoint
export let item;
</script>
<h1>{item.title}</h1>
...paired with a src/routes/items/[id].js
endpoint (don't worry about the $lib
import, we'll get to that later):
/// file: src/routes/items/[id].js
// @filename: ambient.d.ts
type Item = {};
declare module '$lib/database' {
export const get: (id: string) => Promise<Item>;
}
// @filename: __types/[id].d.ts
import type { RequestHandler as GenericRequestHandler } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<{ id: string }, Body>;
// @filename: index.js
// ---cut---
import db from '$lib/database';
/** @type {import('./__types/[id]').RequestHandler} */
export async function GET({ params }) {
// `params.id` comes from [id].js
const item = await db.get(params.id);
if (item) {
return {
status: 200,
headers: {},
body: { item }
};
}
return {
status: 404
};
}
The type of the
GET
function above comes from./__types/[id].d.ts
, which is a file generated by SvelteKit (inside youroutDir
, using therootDirs
option) that provides type safety when accessingparams
. See the section on generated types for more detail.
To get the raw data instead of the page, you can include an accept: application/json
header in the request, or — for convenience — append /__data.json
to the URL, e.g. /items/[id]/__data.json
.
Standalone endpoints
Most commonly, endpoints exist to provide data to the page with which they're paired. They can, however, exist separately from pages. Standalone endpoints have slightly more flexibility over the returned body
type — in addition to objects and Error
instances, they can return a Uint8Array
or a ReadableStream
.
Standalone endpoints can be given a file extension if desired, or accessed directly if not:
filename | endpoint |
---|---|
src/routes/data/index.json.js | /data.json |
src/routes/data.json.js | /data.json |
src/routes/data/index.js | /data |
src/routes/data.js | /data |
POST, PUT, PATCH, DELETE
Endpoints can handle any HTTP method — not just GET
— by exporting the corresponding function:
// @noErrors
export function POST(event) {...}
export function PUT(event) {...}
export function PATCH(event) {...}
export function DELETE(event) {...}
These functions can, like GET
, return a body
that will be passed to the page as props. Whereas 4xx/5xx responses from GET
will result in an error page rendering, similar responses to non-GET requests do not, allowing you to do things like render form validation errors:
/// file: src/routes/items.js
// @filename: ambient.d.ts
type Item = {
id: string;
};
type ValidationError = {};
declare module '$lib/database' {
export const list: () => Promise<Item[]>;
export const create: (request: Request) => Promise<[Record<string, ValidationError>, Item]>;
}
// @filename: __types/items.d.ts
import type { RequestHandler as GenericRequestHandler } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<{}, Body>;
// @filename: index.js
// ---cut---
import * as db from '$lib/database';
/** @type {import('./__types/items').RequestHandler} */
export async function GET() {
const items = await db.list();
return {
body: { items }
};
}
/** @type {import('./__types/items').RequestHandler} */
export async function POST({ request }) {
const [errors, item] = await db.create(request);
if (errors) {
// return validation errors
return {
status: 400,
body: { errors }
};
}
// redirect to the newly created item
return {
status: 303,
headers: {
location: `/items/${item.id}`
}
};
}
/// file: src/routes/items.svelte
<script>
// The page always has access to props from `GET`...
export let items;
// ...plus props from `POST` when the page is rendered
// in response to a POST request, for example after
// submitting the form below
export let errors;
</script>
{#each items as item}
<Preview item={item}/>
{/each}
<form method="post">
<input name="title">
{#if errors?.title}
<p class="error">{errors.title}</p>
{/if}
<button type="submit">Create item</button>
</form>
Body parsing
The request
object is an instance of the standard Request class. As such, accessing the request body is easy:
// @filename: ambient.d.ts
declare global {
const create: (data: any) => any;
}
export {};
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').RequestHandler} */
export async function POST({ request }) {
const data = await request.formData(); // or .json(), or .text(), etc
await create(data);
return { status: 201 };
}
Setting cookies
Endpoints can set cookies by returning a headers
object with set-cookie
. To set multiple cookies simultaneously, return an array:
// @filename: ambient.d.ts
const cookie1: string;
const cookie2: string;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').RequestHandler} */
export function GET() {
return {
headers: {
'set-cookie': [cookie1, cookie2]
}
};
}
HTTP method overrides
HTML <form>
elements only support GET
and POST
methods natively. You can allow other methods, like PUT
and DELETE
, by specifying them in your configuration and adding a _method=VERB
parameter (you can configure the name) to the form's action
:
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
methodOverride: {
allowed: ['PUT', 'PATCH', 'DELETE']
}
}
};
export default config;
<form method="post" action="/todos/{id}?_method=PUT">
<!-- form elements -->
</form>
Using native
<form>
behaviour ensures your app continues to work when JavaScript fails or is disabled.
Private modules
Files and directories with a leading _
or .
(other than .well-known
) are private by default, meaning that they do not create routes (but can be imported by files that do). You can configure which modules are considered public or private with the routes
configuration.
Advanced routing
Rest parameters
If the number of route segments is unknown, you can use rest syntax — for example you might implement GitHub's file viewer like so...
/[org]/[repo]/tree/[branch]/[...file]
...in which case a request for /sveltejs/kit/tree/master/documentation/docs/01-routing.md
would result in the following parameters being available to the page:
// @noErrors
{
org: 'sveltejs',
repo: 'kit',
branch: 'master',
file: 'documentation/docs/01-routing.md'
}
src/routes/a/[...rest]/z.svelte
will match/a/z
(i.e. there's no parameter at all) as well as/a/b/z
and/a/b/c/z
and so on. Make sure you check that the value of the rest parameter is valid, for example using a matcher.
Matching
A route like src/routes/archive/[page]
would match /archive/3
, but it would also match /archive/potato
. We don't want that. You can ensure that route parameters are well-formed by adding a matcher — which takes the parameter string ("3"
or "potato"
) and returns true
if it is valid — to your params
directory...
/// file: src/params/integer.js
/** @type {import('@sveltejs/kit').ParamMatcher} */
export function match(param) {
return /^\d+$/.test(param);
}
...and augmenting your routes:
-src/routes/archive/[page]
+src/routes/archive/[page=integer]
If the pathname doesn't match, SvelteKit will try to match other routes (using the sort order specified below), before eventually returning a 404.
Matchers run both on the server and in the browser.
Sorting
It's possible for multiple routes to match a given path. For example each of these routes would match /foo-abc
:
src/routes/[...catchall].svelte
src/routes/[a].js
src/routes/[b].svelte
src/routes/foo-[c].svelte
src/routes/foo-abc.svelte
SvelteKit needs to know which route is being requested. To do so, it sorts them according to the following rules...
- More specific routes are higher priority (e.g. a route with no parameters is more specific than a route with one dynamic parameter, and so on)
- Standalone endpoints have higher priority than pages with the same specificity
- Parameters with matchers (
[name=type]
) are higher priority than those without ([name]
) - Rest parameters have lowest priority
- Ties are resolved alphabetically
...resulting in this ordering, meaning that /foo-abc
will invoke src/routes/foo-abc.svelte
, and /foo-def
will invoke src/routes/foo-[c].svelte
rather than less specific routes:
src/routes/foo-abc.svelte
src/routes/foo-[c].svelte
src/routes/[a].js
src/routes/[b].svelte
src/routes/[...catchall].svelte
Encoding
Filenames are URI-decoded, meaning that (for example) a filename like %40[username].svelte
would match characters beginning with @
:
// @filename: ambient.d.ts
declare global {
const assert: {
equal: (a: any, b: any) => boolean;
};
}
export {};
// @filename: index.js
// ---cut---
assert.equal(
decodeURIComponent('%40[username].svelte'),
'@[username].svelte'
);
To express a %
character, use %25
, otherwise the result will be malformed.
Layouts permalink
So far, we've treated pages as entirely standalone components — upon navigation, the existing component will be destroyed, and a new one will take its place.
But in many apps, there are elements that should be visible on every page, such as top-level navigation or a footer. Instead of repeating them in every page, we can use layout components.
To create a layout that applies to every page, make a file called src/routes/__layout.svelte
. The default layout (the one that SvelteKit uses if you don't bring your own) looks like this...
<slot></slot>
...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a <slot>
for the page content. For example, let's add a nav bar:
/// file: src/routes/__layout.svelte
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/settings">Settings</a>
</nav>
<slot></slot>
If we create pages for /
, /about
and /settings
...
/// file: src/routes/index.svelte
<h1>Home</h1>
/// file: src/routes/about.svelte
<h1>About</h1>
/// file: src/routes/settings.svelte
<h1>Settings</h1>
...the nav will always be visible, and clicking between the three pages will only result in the <h1>
being replaced.
Nested layouts
Suppose we don't just have a single /settings
page, but instead have nested pages like /settings/profile
and /settings/notifications
with a shared submenu (for a real-life example, see github.com/settings).
We can create a layout that only applies to pages below /settings
(while inheriting the root layout with the top-level nav):
/// file: src/routes/settings/__layout.svelte
<h1>Settings</h1>
<div class="submenu">
<a href="/settings/profile">Profile</a>
<a href="/settings/notifications">Notifications</a>
</div>
<slot></slot>
Named layouts
Some parts of your app might need something other than the default layout. For these cases you can create named layouts...
/// file: src/routes/__layout-foo.svelte
<div class="foo">
<slot></slot>
</div>
...and then use them by referencing the layout name (foo
, in the example above) in the filename:
/// file: src/routes/my-special-page@foo.svelte
<h1>I am inside __layout-foo</h1>
Named layouts are very powerful, but it can take a minute to get your head round them. Don't worry if this doesn't make sense all at once.
Scoping
Named layouts can be created at any depth, and will apply to any components in the same subtree. For example, __layout-foo
will apply to /x/one
and /x/two
, but not /x/three
or /four
:
src/routes/
├ x/
│ ├ __layout-foo.svelte
│ ├ one@foo.svelte # ✅ page has `@foo`
│ ├ two@foo.svelte # ✅ page has `@foo`
│ └ three.svelte # ❌ page does not have `@foo`
└ four@foo.svelte # ❌ page has `@foo`, but __layout-foo is not 'in scope'
Inheritance chains
Layouts can themselves choose to inherit from named layouts, from the same directory or a parent directory. For example, x/y/__layout@root.svelte
is the default layout for /x/y
(meaning /x/y/one
, /x/y/two
and /x/y/three
all inherit from it) because it has no name. Because it specifies @root
, it will inherit directly from the nearest __layout-root.svelte
, skipping __layout.svelte
and x/__layout.svelte
.
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
├ __layout.svelte
└ __layout-root.svelte
In the case where
__layout-root.svelte
contains a lone<slot />
, this effectively means we're able to 'reset' to a blank layout for any page or nested layout in the app by adding@root
.
If no parent is specified, a layout will inherit from the nearest default (i.e. unnamed) layout above it in the tree. In some cases, it's helpful for a named layout to inherit from a default layout alongside it in the tree, such as __layout-root.svelte
inheriting from __layout.svelte
. We can do this by explicitly specifying @default
, allowing /x/y/one
and siblings to use the app's default layout without using x/__layout.svelte
:
src/routes/
├ x/
│ ├ y/
│ │ ├ __layout@root.svelte
│ │ ├ one.svelte
│ │ ├ two.svelte
│ │ └ three.svelte
│ └ __layout.svelte
├ __layout.svelte
-└ __layout-root.svelte
+└ __layout-root@default.svelte
default
is a reserved name — in other words, you can't have a__layout-default.svelte
file.
Error pages
If a page fails to load (see Loading), SvelteKit will render an error page. You can customise this page by creating __error.svelte
components alongside your layouts and pages.
For example, if src/routes/settings/notifications/index.svelte
failed to load, SvelteKit would render src/routes/settings/notifications/__error.svelte
in the same layout, if it existed. If not, it would render src/routes/settings/__error.svelte
in the parent layout, or src/routes/__error.svelte
in the root layout.
SvelteKit provides a default error page in case you don't supply
src/routes/__error.svelte
, but it's recommended that you bring your own.
If an error component has a load
function, it will be called with error
and status
properties:
<script context="module">
/** @type {import('@sveltejs/kit').Load} */
export function load({ error, status }) {
return {
props: {
title: `${status}: ${error.message}`
}
};
}
</script>
<script>
export let title;
</script>
<h1>{title}</h1>
Layouts also have access to
error
andstatus
via the page storeServer-side stack traces will be removed from
error
in production, to avoid exposing privileged information to users.
404s
Nested error pages are only rendered when an error occurs while rendering a specific page. In the case of a request that doesn't match any existing route, SvelteKit will render a generic 404 instead. For example, given these routes...
src/routes/
├ __error.svelte
├ marx-brothers/
│ ├ __error.svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
...the marx-brothers/__error.svelte
file will not be rendered if you visit /marx-brothers/karl
. If you want to render the nested error page, you should create a route that matches any /marx-brothers/*
request, and return a 404 from it:
src/routes/
├ __error.svelte
├ marx-brothers/
│ ├ __error.svelte
+│ ├ [...path].svelte
│ ├ chico.svelte
│ ├ harpo.svelte
│ └ groucho.svelte
/// file: src/routes/marx-brothers/[...path].svelte
<script context="module">
/** @type {import('./__types/[...path]').Load} */
export function load({ params }) {
return {
status: 404,
error: new Error(`Not found: /marx-brothers/${params.path}`)
};
}
</script>
Загрузка данных permalink
Компонент, определяющий страницу или макет, может экспортировать функцию load
, которая запускается до создания компонента. Эта функция выполняется как во время рендеринга на стороне сервера, так и в клиенте и позволяет извлекать данные и манипулировать ими до рендеринга страницы, что позволяет обойтись без индикаторов загрузки на странице.
Функция load
может не понадобиться, если данные для страницы поставляются с её эндпоинта. Это полезно, когда нужно больше гибкости, например, для загрузки данных с внешнего API, которая может выглядеть так:
/// file: src/routes/blog/[slug].svelte
<script context="module">
/** @type {import('./__types/[slug]').Load} */
export async function load({ params, fetch, session, stuff }) {
const url = `https://cms.example.com/article/${params.slug}.json`;
const response = await fetch(url);
return {
status: response.status,
props: {
article: response.ok && (await response.json())
}
};
}
</script>
Обратите внимание на
<script context="module">
— это необходимо, потому чтоload
выполняется до визуализации компонента. Код для каждого экземпляра компонента должен быть размещен во втором теге<script>
.
Как и в случае с эндпоинтами, страницы могут импортировать сгенерированные типы - ./[slug]
в приведенном выше примере - чтобы убедиться, что params
правильно набраны.
load
в SvelteKit является эквивалентом функциям getStaticProps
или getServerSideProps
в Next.js или asyncData
в Nuxt.js, за исключением того, что она работает как на сервере, так и на клиенте. В приведенном выше примере, если пользователь нажимает на ссылку на эту страницу, данные будут загуржены с cms.example.com
, не проходя через наш сервер.
Функция load
получает в аргументах метод fetch
, который имеет следующие специальные свойства:
- имеет доступ к файлам cookie на сервере
- может делать запросы к собственным эндпоинтам приложения без выполнения HTTP-запроса
- при использовании делает копию ответа и встраивает её в страницу при первом запросе для гидратации
load
может применяться только в компонентах страниц и макетов (но не в компонентах, которые они импортируют) и по умолчанию работает как на сервере, так и в браузере.
Код, который вызывается внутри функции
load
:
- должен использовать только свой метод
fetch
, а не нативныйfetch
- не должен ссылаться на
window
,document
или любые другие объекты, специфичные для браузера- не должен содержать каких-либо ключей для API или иных секретов, которые будут доступны клиенту, а вместо этого вызывать эндпоинт, который использует любые необходимые секреты
Рекомендуется не хранить состояние каждого запроса в глобальных переменных, а вместо этого использовать их только для межсекторальных проблем, таких как кэширование и хранение подключений к базе данных.
Мутирование любого общего состояния на сервере повлияет на всех клиентов, а не только на текущего.
Получаемые значения
Функция load
получает объект, содержащий 8 полей — url
, params
, props
, fetch
, session
, stuff
, status
, и error
. Функция load
является реактивной и будет повторно запущена при изменении значений её параметров, но только в том случае, если они используются в теле функции. В частности, если в функции используются url
, session
или stuff
, она будут повторно запущена всякий раз, когда их значения изменятся. Также это произойдет при изменении любых отдельных свойств объекта params
.
Обратите внимание, что деструктурирование параметров в объявлении функции уже означает их использование в функции.
url
url
- это экземпляр URL
, содержащий такие свойства, как origin
, hostname
, pathname
и searchParams
(который содержит разобранную строку запроса в виде объекта URLSearchParams
). url.hash
недоступен во время load
, так как он недоступен на сервере.
В некоторых средах этот параметр получается из заголовков запроса во время рендеринга на стороне сервера.Если вы используете adapter-node, например, вам может потребоваться настроить адаптер, чтобы URL был правильным.
params
params
получается из url.pathname
и имени файла маршрута.
Например, для имени файла маршрута src/routes/a/[b]/[...c]
и значении url.pathname
равным /a/x/y/z
, объект params
будет выглядеть следующим образом:
{
"b": "x",
"c": "y/z"
}
props
Если страница, которую вы загружаете, имеет эндпоинт, то возвращаемые из него данные для свойств страницы доступны внутри функции load
как объект props
. Для компонентов макета и страниц без эндпоинтов props
будет пустым объектом.
fetch
fetch
эквивалентен родному веб-API fetch
, с несколькими дополнительными функциями:
- его можно использовать для выполнения авторизованных запросов на сервере, так как он наследует заголовки
cookie
иauthorization
для запроса страницы - он может делать относительные запросы на сервере (обычно
fetch
требует URL-адрес с источником при использовании в контексте сервера) - запросы на эндпоинты поступают непосредственно в функцию обработчика во время рендеринга на стороне сервера, без накладных расходов на HTTP-вызов
- во время рендеринга на стороне сервера ответ будет захвачен и встроен в визуализированный HTML
- во время гидратации ответ будет считываться из HTML, гарантируя согласованность и предотвращая дополнительный сетевой запрос
Cookie будут переданы только в том случае, если целевой хост совпадает с хостом текущего приложения SvelteKit или его поддоменом.
session
session
может использоваться для передачи данных от сервера в текущий запрос, например идентификатор авторизованного пользователя. По умолчанию значение равно undefined
. См. getSession
в разделе Хуки
, чтобы узнать как использовать этот объект.
stuff
Объект stuff
передаётся из макетов дочерним макетам и страницам, и может содержать то, что нужно сделать доступным ниже. Для корневого компонента __layout.svelte
он будет равен {}
, но если функция load
этого компонента возвращает объект со свойством stuff
, оно будет доступно для всех функций load
из дочерних компонентов.
status
status
- это код состояния HTTP при отображении страницы ошибки или null
в противном случае.
error
error
- это ошибка, которая была выдана (или возвращена из предыдущей load
) при отображении страницы ошибки или null
в противном случае.
Возвращаемые значения
Если из load
возвращается промис, страница не будет отображаться, пока промис не исполнится. У возвращаемого объекта может быть несколько свойств, все они опциональны:
status
,error
,redirect
иcache
игнорируются при отображении страниц ошибок.
status
Код ответа HTTP сервера. Если возвращается error
– он должен быть из диапазонов 4xx
или 5xx
; при возвращении свойства redirect
код нужно установить в диапазон 3xx
. По умолчанию код ответа равен 200
.
error
Если при выполнении функции load
что-то пошло не так, поместите в это свойство объект Error
или просто строку, описывающую проблему, не забыв указать код ответа в свойстве status
равным числу в диапазонах 4xx
или 5xx
.
redirect
Если страница должна перенаправить пользователя на другую страницу (например, эта страница устарела, или пользователь должен сначала авторизоваться или ещё что-то), поместите в это свойство строку, содержащую путь по которому нужно переместить пользователя. Не забудьте указать код ответа в свойстве status
равным числу в диапазоне 3xx
.
Строка redirect
должна быть правильно закодированным URI. Допустимы как абсолютные, так и относительные URI.
cache
cache: {
"maxage": 300,
"private": false
}
Чтобы кэшировать страницы, верните объект cache
, содержащий свойство maxage
, установленное в number
, описывающий максимальный возраст страницы в секундах. При необходимости также включите свойство boolean
private
, указывающее, должен ли результирующий заголовок Cache-Control
быть private
или public
(это означает, что он может быть кэширован CDN в дополнение к отдельным браузерам).
Если
cache.private
являетсяundefined
, SvelteKit установит его автоматически, используя следующую эвристику: если функцияload
делаетfetch
учетных данных или страница используетsession
, она считается частной.
Это свойство может быть использовано только для страниц, но не для макетов.
props
Если функция load
возвращает объект props
, то он будет передан компоненту как его свойства, когда он будет отрисован.
stuff
Поля из этого объекта будут добавлены к существующим полям объекта stuff
, который будет предан в функции load
всех дочерних компонентов страниц и макетов.
Полный объект stuff
можно использовать в компонентах используя $page.stuff
из хранилища страницы. Таким образом для страниц обеспечивается механизм передачи данных "вверх", в макеты.
dependencies
Массив строк, представляющих URL-адреса, от которых зависит страница, которые впоследствии могут быть использованы с invalidate
, чтобы вызвать повторный запуск load
. Вам нужно добавить их в зависимости
, только если вы используете пользовательский API-клиент; URL-адреса, загруженные с предоставленной функцией fetch
, добавляются автоматически.
URL-адреса могут быть абсолютными или относительно загружаемой страницы и должны быть [закодированы] (https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding).
Хуки permalink
Необязательный файл src/hooks.js
(или src/hooks.ts
, или src/hooks/index.js
) может экспортировать четыре функции, которые будут запускаться на сервере — handle
, handleError
, getSession
и externalFetch
.
Расположение этого файла может быть настроено в опции
config.kit.files.hooks
handle
Эта функция запускается каждый раз, когда сервер SvelteKit получает request и формирует response. Это может происходить во время работы приложения или во время предварительной отрисовки. Она получает объект event
, представляющий запрос, и функцию resolve
, которая вызывает маршрутизатор SvelteKit и генерирует ответ (отображает страницу или вызывает эндпоинт). Это позволяет изменять заголовки или тело ответов или полностью обойти SvelteKit (например, для программной реализации эндпоинтов).
/// file: src/hooks.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
if (event.url.pathname.startsWith('/custom')) {
return new Response('custom response');
}
const response = await resolve(event);
return response;
}
Запросы статический ресурсов, включая предварительно отрисованные страницы, не обрабатываются SvelteKit.
Если не реализовано, по умолчанию используется ({ event, resolve }) => resolve(event)
. Чтобы добавить пользовательские данные к запросу, который передается конечным точкам, заполните объект event.locals
, как показано ниже.
/// file: src/hooks.js
// @filename: ambient.d.ts
type User = {
name: string;
}
declare namespace App {
interface Locals {
user: User;
}
interface Platform {}
interface Session {}
interface Stuff {}
}
const getUserInformation: (cookie: string | null) => Promise<User>;
// declare global {
// const getUserInformation: (cookie: string) => Promise<User>;
// }
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
event.locals.user = await getUserInformation(event.request.headers.get('cookie'));
const response = await resolve(event);
response.headers.set('x-custom-header', 'potato');
return response;
}
Можно добавить вызов нескольких функций handle
используя хелпер sequence
.
В resolve
можно передать второй необязательный параметр, который даёт больше контроля над тем, как будет отображаться ответ. Этот параметр является объектом, который может иметь следующие поля:
ssr: boolean
(defaulttrue
) - еслиfalse
, отображает пустую страницу 'shell' вместо рендеринга на стороне сервераtransformPage(opts: { html: string }): string
— применяет пользовательские преобразования к HTML
/// file: src/hooks.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
ssr: !event.url.pathname.startsWith('/admin'),
transformPage: ({ html }) => html.replace('old', 'new')
});
return response;
}
Отключение отрисовки на стороне сервера фактически превращает приложение SvelteKit в одностраничное приложение или SPA. В большинстве ситуаций это не рекомендуется (см. термин SSR). Решите, действительно ли уместно его полностью отключать или сделайте это выборочно, а не для всех запросов.
handleError
Если ошибка возникает во время рендеринга, эта функция будет вызвана с параметрами error
и event
. Это позволяет отправлять данные в сервис отслеживания ошибок или форматировать сообщение для вывода в консоли.
Если, в режиме разработки, возникает синтаксическая ошибка в коде Svelte, будет добавлен параметр frame
, указывающий на местоположение ошибки.
Если данный хук не задан, SvelteKit отобразит ошибку с форматированием по умолчанию.
/// file: src/hooks.js
// @filename: ambient.d.ts
const Sentry: any;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').HandleError} */
export async function handleError({ error, event }) {
// пример интеграции с https://sentry.io/
Sentry.captureException(error, { event });
}
handleError
вызывается только в случае, если ошибка не была поймана ранее в коде. Также хук не вызывается, когда страницы и эндпоинты явно отвечают кодами состояния 4xx и 5xx.
getSession
Эта функция принимает объект event
и возвращает объект session
, который доступен на клиенте и, следовательно, должен быть безопасным для предоставления пользователям. Он запускается всякий раз, когда SvelteKit выполняет рендеринг страницы на сервере.
Если функция не задана, объект сессии будет равен {}
.
/// file: src/hooks.js
// @filename: ambient.d.ts
declare namespace App {
interface Locals {
user: {
name: string;
email: string;
avatar: string;
token: string;
}
}
interface Session {
user?: {
name: string;
email: string;
avatar: string;
}
}
}
type MaybePromise<T> = T | Promise<T>;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').GetSession} */
export function getSession(event) {
return event.locals.user
? {
user: {
// передайте только поля нужные на клиенте —
// исключите любые другие поля объекта user
// вроде токенов, паролей и т.п.
name: event.locals.user.name,
email: event.locals.user.email,
avatar: event.locals.user.avatar
}
}
: {};
}
Объект
session
должен быть сериализуемым, то есть не должен содержать вещей вроде функций или классов, только встроенные в JavaScript типы данных.
externalFetch
Эта функция позволяет изменять (или заменять) запрос fetch
для внешнего ресурса внутри функции load
, которая выполняется на сервере (или во время предварительной отрисовки).
Например, когда есть страница с функцией load
, которая на клиенте делает запрос на публичный URL-адрес(например https://api.yourapp.com
) какого-либо внутреннего сервиса, то во время отрисовки на сервере имеет смысл выполнить запрос к сервису локально, минуя прокси-серверы и балансировщики.
/** @type {import('@sveltejs/kit').ExternalFetch} */
export async function externalFetch(request) {
if (request.url.startsWith('https://api.yourapp.com/')) {
// копируем исходный запрос, но заменяем URL-адрес
request = new Request(
request.url.replace('https://api.yourapp.com/', 'http://localhost:9999/'),
request
);
}
return fetch(request);
}
Loading permalink
A component that defines a page or a layout can export a load
function that runs before the component is created. This function runs both during server-side rendering and in the client, and allows you to fetch and manipulate data before the page is rendered, thus preventing loading spinners.
If the data for a page comes from its endpoint, you may not need a load
function. It's useful when you need more flexibility, for example loading data from an external API, which might look like this:
/// file: src/routes/blog/[slug].svelte
<script context="module">
/** @type {import('./__types/[slug]').Load} */
export async function load({ params, fetch, session, stuff }) {
const url = `https://cms.example.com/article/${params.slug}.json`;
const response = await fetch(url);
return {
status: response.status,
props: {
article: response.ok && (await response.json())
}
};
}
</script>
Note the
<script context="module">
— this is necessary becauseload
runs before the component is rendered. Code that is per-component instance should go into a second<script>
tag.
As with endpoints, pages can import generated types — the ./[slug]
in the example above — to ensure that params
are correctly typed.
load
is similar to getStaticProps
or getServerSideProps
in Next.js, except that load
runs on both the server and the client. In the example above, if a user clicks on a link to this page the data will be fetched from cms.example.com
without going via our server.
SvelteKit's load
receives an implementation of fetch
, which has the following special properties:
- it has access to cookies on the server
- it can make requests against the app's own endpoints without issuing an HTTP call
- it makes a copy of the response when you use it, and then sends it embedded in the initial page load for hydration
load
only applies to page and layout components (not components they import), and runs on both the server and in the browser with the default rendering options.
Code called inside
load
blocks:
- should use the SvelteKit-provided
fetch
wrapper rather than using the nativefetch
- should not reference
window
,document
, or any browser-specific objects- should not directly reference any API keys or secrets, which will be exposed to the client, but instead call an endpoint that uses any required secrets
It is recommended that you not store per-request state in global variables, but instead use them only for cross-cutting concerns such as caching and holding database connections.
Mutating any shared state on the server will affect all clients, not just the current one.
Input
The load
function receives an object containing eight fields — url
, params
, props
, fetch
, session
, stuff
, status
, and error
. The load
function is reactive, and will re-run when its parameters change, but only if they are used in the function. Specifically, if url
, session
or stuff
are used in the function, they will be re-run whenever their value changes, and likewise for the individual properties of params
.
Note that destructuring parameters in the function declaration is enough to count as using them.
url
url
is an instance of URL
, containing properties like the origin
, hostname
, pathname
and searchParams
(which contains the parsed query string as a URLSearchParams
object). url.hash
cannot be accessed during load
, since it is unavailable on the server.
In some environments this is derived from request headers during server-side rendering. If you're using adapter-node, for example, you may need to configure the adapter in order for the URL to be correct.
params
params
is derived from url.pathname
and the route filename.
For a route filename example like src/routes/a/[b]/[...c]
and a url.pathname
of /a/x/y/z
, the params
object would look like this:
{
"b": "x",
"c": "y/z"
}
props
If the page you're loading has an endpoint, the data returned from it is accessible inside the leaf component's load
function as props
. For layout components and pages without endpoints, props
will be an empty object.
fetch
fetch
is equivalent to the native fetch
web API, with a few additional features:
- it can be used to make credentialed requests on the server, as it inherits the
cookie
andauthorization
headers for the page request - it can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context) - requests for endpoints go direct to the handler function during server-side rendering, without the overhead of an HTTP call
- during server-side rendering, the response will be captured and inlined into the rendered HTML
- during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request
Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.
session
session
can be used to pass data from the server related to the current request, e.g. the current user. By default it is undefined
. See getSession
to learn how to use it.
stuff
stuff
is passed from layouts to descendant layouts and pages, and can be filled with anything else you need to make available. For the root __layout.svelte
component, it is equal to {}
, but if that component's load
function returns an object with a stuff
property, it will be available to subsequent load
functions.
status
status
is the HTTP status code when rendering an error page, or null
otherwise.
error
error
is the error that was thrown (or returned from a previous load
) when rendering an error page, or null
otherwise.
Output
If you return a Promise from load
, SvelteKit will delay rendering until the promise resolves. The return value has several properties listed below, all of which are optional (as is the return value itself).
status
,error
,redirect
andcache
are ignored when rendering error pages.
status
The HTTP status code for the page. If returning an error
this must be a 4xx
or 5xx
response; if returning a redirect
it must be a 3xx
response. The default is 200
.
error
If something goes wrong during load
, return an Error
object or a string
describing the error alongside a 4xx
or 5xx
status code.
redirect
If the page should redirect (because the page is deprecated, or the user needs to be logged in, or whatever else) return a string
containing the location to which they should be redirected alongside a 3xx
status code.
The redirect
string should be a properly encoded URI. Both absolute and relative URIs are acceptable.
cache
cache: {
"maxage": 300,
"private": false
}
To cause pages to be cached, return a cache
object containing a maxage
property set to a number
describing the page's max age in seconds. Optionally, also include a boolean
private
property indicating whether the resulting Cache-Control
header should be private
or public
(meaning it can be cached by CDNs in addition to individual browsers).
If
cache.private
isundefined
, SvelteKit will set it automatically using the following heuristic: if aload
function makes a credentialledfetch
, or the page usessession
, the page is considered private.
This only applies to pages, not layouts.
props
If the load
function returns a props
object, the props will be passed to the component when it is rendered.
stuff
This will be merged with any existing stuff
and passed to the load
functions of subsequent layout and page components.
The combined stuff
is available to components using the page store as $page.stuff
, providing a mechanism for pages to pass data 'upward' to layouts.
dependencies
An array of strings representing URLs the page depends on, which can subsequently be used with invalidate
to cause load
to rerun. You only need to add them to dependencies
if you're using a custom API client; URLs loaded with the provided fetch
function are added automatically.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Hooks permalink
An optional src/hooks.js
(or src/hooks.ts
, or src/hooks/index.js
) file exports four functions, all optional, that run on the server — handle
, handleError
, getSession
, and externalFetch
.
The location of this file can be configured as
config.kit.files.hooks
handle
This function runs every time the SvelteKit server receives a request — whether that happens while the app is running, or during prerendering — and determines the response. It receives an event
object representing the request and a function called resolve
, which invokes SvelteKit's router and generates a response (rendering a page, or invoking an endpoint) accordingly. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing endpoints programmatically, for example).
/// file: src/hooks.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
if (event.url.pathname.startsWith('/custom')) {
return new Response('custom response');
}
const response = await resolve(event);
return response;
}
Requests for static assets — which includes pages that were already prerendered — are not handled by SvelteKit.
If unimplemented, defaults to ({ event, resolve }) => resolve(event)
. To add custom data to the request, which is passed to endpoints, populate the event.locals
object, as shown below.
/// file: src/hooks.js
// @filename: ambient.d.ts
type User = {
name: string;
}
declare namespace App {
interface Locals {
user: User;
}
interface Platform {}
interface Session {}
interface Stuff {}
}
const getUserInformation: (cookie: string | null) => Promise<User>;
// declare global {
// const getUserInformation: (cookie: string) => Promise<User>;
// }
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
event.locals.user = await getUserInformation(event.request.headers.get('cookie'));
const response = await resolve(event);
response.headers.set('x-custom-header', 'potato');
return response;
}
You can add call multiple handle
functions with the sequence
helper function.
resolve
also supports a second, optional parameter that gives you more control over how the response will be rendered. That parameter is an object that can have the following fields:
ssr: boolean
(defaulttrue
) — iffalse
, renders an empty 'shell' page instead of server-side renderingtransformPage(opts: { html: string }): string
— applies custom transforms to HTML
/// file: src/hooks.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
ssr: !event.url.pathname.startsWith('/admin'),
transformPage: ({ html }) => html.replace('old', 'new')
});
return response;
}
Disabling server-side rendering effectively turns your SvelteKit app into a single-page app or SPA. In most situations this is not recommended (see appendix). Consider whether it's truly appropriate to disable it, and do so selectively rather than for all requests.
handleError
If an error is thrown during rendering, this function will be called with the error
and the event
that caused it. This allows you to send data to an error tracking service, or to customise the formatting before printing the error to the console.
During development, if an error occurs because of a syntax error in your Svelte code, a frame
property will be appended highlighting the location of the error.
If unimplemented, SvelteKit will log the error with default formatting.
/// file: src/hooks.js
// @filename: ambient.d.ts
const Sentry: any;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').HandleError} */
export async function handleError({ error, event }) {
// example integration with https://sentry.io/
Sentry.captureException(error, { event });
}
handleError
is only called in the case of an uncaught exception. It is not called when pages and endpoints explicitly respond with 4xx and 5xx status codes.
getSession
This function takes the event
object and returns a session
object that is accessible on the client and therefore must be safe to expose to users. It runs whenever SvelteKit server-renders a page.
If unimplemented, session is {}
.
/// file: src/hooks.js
// @filename: ambient.d.ts
declare namespace App {
interface Locals {
user: {
name: string;
email: string;
avatar: string;
token: string;
}
}
interface Session {
user?: {
name: string;
email: string;
avatar: string;
}
}
}
type MaybePromise<T> = T | Promise<T>;
// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').GetSession} */
export function getSession(event) {
return event.locals.user
? {
user: {
// only include properties needed client-side —
// exclude anything else attached to the user
// like access tokens etc
name: event.locals.user.name,
email: event.locals.user.email,
avatar: event.locals.user.avatar
}
}
: {};
}
session
must be serializable, which means it must not contain things like functions or custom classes, just built-in JavaScript data types
externalFetch
This function allows you to modify (or replace) a fetch
request for an external resource that happens inside a load
function that runs on the server (or during pre-rendering).
For example, your load
function might make a request to a public URL like https://api.yourapp.com
when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).
/** @type {import('@sveltejs/kit').ExternalFetch} */
export async function externalFetch(request) {
if (request.url.startsWith('https://api.yourapp.com/')) {
// clone the original request, but change the URL
request = new Request(
request.url.replace('https://api.yourapp.com/', 'http://localhost:9999/'),
request
);
}
return fetch(request);
}
Модули permalink
В SvelteKit есть несколько модулей, которые доступны в приложении.
$app/env
/// <reference types="@sveltejs/kit" />
// ---cut---
import { amp, browser, dev, mode, prerendering } from '$app/env';
amp
равен либоtrue
, либоfalse
в зависимости от соответствующего значения в конфигурации проектаbrowser
будет равенtrue
илиfalse
если приложение запущено соответственно в браузере или на сервереdev
равенtrue
в режиме разработки,false
в рабочем режимеmode
- это Vite mode, по-умолчаниюdevelopment
в режиме разработки илиproduction
во время сборки, если иное не настроено вconfig.kit.vite.mode
.prerendering
равенtrue
во время предварительной отрисовки, иначеfalse
$app/navigation
/// <reference types="@sveltejs/kit" />
// ---cut---
import {
afterNavigate,
beforeNavigate,
disableScrollHandling,
goto,
invalidate,
prefetch,
prefetchRoutes
} from '$app/navigation';
afterNavigate(({ from, to }: { from: URL, to: URL }) => void)
- функция жизненного цикла, которая запускается при первоначальной отрисовке компонента, а также при каждой последующей навигации, пока компонент остается в отрисованным.beforeNavigate(({ from, to, cancel }: { from: URL, to: URL | null, cancel: () => void }) => void)
— функция, которая запускается всякий раз, когда происходит навигация, будь то нажатие на ссылку, вызовgoto
или перемещение по истории браузера. Также она будет запущена и при переходе на внешние сайты. Если пользователь закрывает страницу, то вto
будет значениеnull
. Вызовcancel
остановит выполнение перехода.disableScrollHandling
запретит SvelteKit применить его обычное управление прокруткой страницы, если вызывается когда страница обновляется после перехода (например, вonMount
или действии). Лучше избегать использования этой функции, чтобы не дезориентировать пользователей.goto(href, { replaceState, noscroll, keepfocus, state })
возвращаетPromise
, который резолвится при навигации SvelteKit к указанномуhref
(ошибка в навигации отклоняет промис). Второй аргумент является необязательным:replaceState
(boolean, по умолчаниюfalse
) Еслиtrue
, заменит текущую записьhistory
, а не создаст новую черезpushState
noscroll
(boolean, по умолчаниюfalse
) Еслиtrue
, браузер сохранит свое положение прокрутки, а не прокрутит в верхнюю часть страницы после навигацииkeepfocus
(boolean, по умолчаниюfalse
) Еслиtrue
, текущий сфокусированный элемент сохранит фокус после навигации. В противном случае фокус будет сброшенstate
(объект, по умолчанию{}
) Состояние новой/обновленной записи истории
invalidate(href)
перезапускает все функцииload
, которые нужны для текущей активной страницы для повторной загрузки необходимых ресурсов. Возвращает объектPromise
, который разрешается, когда страница обновится новыми данными.prefetch(href)
программно выполняет упреждающую загрузку указанной страницы, что означает: а) обеспечение полной загрузки кода для страницы и б) вызов методаload
страницы с соответствующими параметрами. Это поведение, аналогично случаю, когда пользователь касается на сенсорном экране или проводит курсором над элементом<a>
с установленным атрибутом sveltekit:prefetch. Если следующий переход будет по путиhref
, то будет использовано значение, которое вернула функцияload
, что сделает перемещение мгновенным. Возвращает объектPromise
, который разрешается, когда упреждающая загрузка будет завершена.prefetchRoutes(routes)
— программно выполняет упреждающую загрузку кода для маршрутов, которые ещё не были загружены до этого. Обычно используется для ускорения переходов по нижестоящим маршрутам. Если не передавать аргументов, то будут предзагружены все маршруты, но можете указать маршруты по любому подходящему пути, например,/about
(дляsrc/routes/about.svelte
) или/blog/*
(дляsrc/routes/blog/[slug].svelte
). В отличие отprefetch
не вызывает функциюload
для каждой из загружаемых страниц. Возвращает объектPromise
, который разрешается, когда упреждающая загрузка всех маршрутов будет завершена.
$app/paths
/// <reference types="@sveltejs/kit" />
// ---cut---
import { base, assets } from '$app/paths';
base
— строка с путём, относительно корня (т.е. начинается с/
), которая соответствует параметруconfig.kit.paths.base
в конфигурации проектаassets
— путь от корня или абсолютный путь который соответствует параметруconfig.kit.paths.assets
(после его разрешения относительноbase
)
Если указано значение
config.kit.paths.assets
, во время выполненияsvelte-kit dev
илиsvelte-kit preview
оно будет подменяться на'/_svelte_kit_assets'
, так как статические ресурсы ещё не размещены по их окончательному URL-адресу.
$app/stores
/// <reference types="@sveltejs/kit" />
// ---cut---
import { getStores, navigating, page, session, updated } from '$app/stores';
Эти хранилища зависят от контекста, так как они добавляются в контекст корневого компонента приложения. Это значит, что хранилища session
и page
будут уникальны для каждого запроса на сервер и не будут предоставлять одну и ту же информацию в нескольких запросах сразу. Поэтому можно безопасно хранить в session
данные конкретного пользователя.
По этой причине доступ к хранилищу можно получить только во время инициализации компонента, как и в случае с любой функцией, которая использует метод getContext
внутри.
getStores
— это удобная функция-оболочка вокругgetContext
, которая возвращает{ navigating, page, session, updated }
. Её необходимо вызывать на верхнем уровне или синхронно во время инициализации компонента или страницы.
Хранилища сами определяют нужный контекст, когда выполняется подписка на них, что означает, что вы можете импортировать и использовать их непосредственно в компонентах без лишней обвязки. Тем не менее, их его всё ещё нужно вызывать синхронно при инициализации компонента или страницы, когда не используется префикс $
. Вместо этого используйте getStores
, чтобы безопасно асинхронно выполнить .subscribe
.
navigating
- это хранилище. В процессе перехода при навигации его значением становится объект{ from, to }
, гдеfrom
иto
являются экземплярамиURL
. Когда переход завершается, его значение возвращается кnull
.page
содержит объект с текущимиurl
,params
,stuff
,status
иerror
.session
– хранилище, начальное значение которого получается из функцииgetSession
. Значение в хранилище можно изменять, но эти изменения не будут сохранены на сервере – при необходимости это нужно имплементировать самостоятельно.updated
- это хранилище, начальное значение которого равноfalse
. Если в конфигурации заданversion.pollInterval
, SvelteKit будет периодически проверять новую версию приложения на сервере и как только обнаружит её, обновит значение хранилища доtrue
. Вызов методаupdated.check()
принудительно проверит новую версию на сервере, независимо от настроек опроса.
$lib
Это простой псевдоним для директории src/lib
, или иной директории указанной в config.kit.files.lib
. Он позволит обращаться к общим компонентам и утилитам без использования множества ../../../../
в путях импорта.
$service-worker
Этот модуль доступен только в сервис-воркерах.
/// <reference types="@sveltejs/kit" />
// ---cut---
import { build, files, timestamp } from '$service-worker';
build
– массив строк URL-путей до файлов сгенерированных Vite, используется для кеширования при помощи функцииcache.addAll(build)
files
- это массив строк URL, представляющих файлы в вашем каталогеstatic
или любой другой каталог, указанныйconfig.kit.files.assets
. Вы можете настроить, какие файлы включаются из каталогаstatic
, используяconfig.kit.serviceWorker.files
timestamp
– результат вызова функцииDate.now()
во время сборки. Полезно для генерации уникальных имён для кешей внутри сервис-воркера, что позволит инвалидировать устаревшие кеши у клиентов при запуске новой версии приложения.
@sveltejs/kit/hooks
Этот модуль содержит хелпер-функцию sequence
для создания последовательности из нескольких вызовов в handle
.
/// file: src/hooks.js
/// <reference types="@sveltejs/kit" />
// ---cut---
import { sequence } from '@sveltejs/kit/hooks';
/** @type {import('@sveltejs/kit').Handle} */
async function first({ event, resolve }) {
console.log('первая пред-обработка');
const result = await resolve(event);
console.log('первая пост-обработка');
return result;
}
/** @type {import('@sveltejs/kit').Handle} */
async function second({ event, resolve }) {
console.log('вторая пред-обработка');
const result = await resolve(event);
console.log('вторая пост-обработка');
return result;
}
export const handle = sequence(first, second);
Пример выше распечатает:
первая пред-обработка
вторая пред-обработка
вторая пост-обработка
первая пост-обработка
Modules permalink
SvelteKit makes a number of modules available to your application.
EXPORTS
Сервис-воркеры permalink
Сервис-воркеры выступают в роли прокси-серверов, которые обрабатывают сетевые запросы внутри вашего приложения. Это позволяет сделать приложение, которое сможет работать в Offline-режиме, но даже если поддержка работы без сети не требуется(или она невозможна из-за особенностей работы приложения), то сервис-воркер может ускорить навигацию кешированием JS и CSS файлов приложения.
Если в проекте SvelteKit есть файл src/service-worker.js
(или src/service-worker.ts
, или src/service-worker/index.js
) он будет собран в Vite и автоматически зарегистрирован. Вы можете отключить автоматическую регистрацию, если вам нужно зарегистрировать сервис-воркера со своей собственной логикой (например, запросить у пользователя обновление, настроить периодические обновления, использовать workbox
и т. д.).
Вы можете изменить местоположение сервис-воркера и отключить автоматическую регистрацию в конфигурации вашего проекта.
Внутри сервис-воркера есть доступ к модулю $service-worker
.
Файл сервис-воркера должен пройти через процесс сборки, поскольку браузеры ещё не поддерживают import
в этом контексте. Кроме того сервис-воркер зависит от манифеста сборки клиентской части приложения. В следствие чего, сервис-воркеры работают только в рабочей сборке, но не в режиме разработки. Чтобы протестировать его работу локально, запустите проект командой svelte-kit preview
.
Атрибуты ссылок permalink
sveltekit:prefetch
SvelteKit использует разделение кода, чтобы разбить приложение на небольшие фрагменты (по одному на маршрут), обеспечивая быстрое время запуска.
Для динамических маршрутов, таких как src/routes/blog/[slug].svelte
, этого недостаточно. Чтобы отобразить сообщение в блоге, нужно получить для него данные, и мы не сможем этого сделать, пока не узнаем значение slug
. В худшем случае это может вызвать задержку, поскольку браузер будет ждать данные от сервера.
Сгладить ситуацию можно предварительно собрав данные, добавив атрибут sveltekit:prefetch
...
<a sveltekit:prefetch href="blog/what-is-sveltekit">Что такое SvelteKit?</a>
...который заставит SvelteKit запустить функцию load
как только пользователь наведёт курсор мыши на ссылку или коснётся её на мобильном устройстве, вместо того, чтобы дожидаться события click
, которое выполнит переход на страницу. Обычно это даст нам дополнительную пару сотен миллисекунд, что как раз является той разницей, которая существует между быстрым пользовательским интерфейсом, и тем, который кажется медленным.
Обратите внимание, что предварительная загрузка данных не будет работать, если значение router
установлено в false
.
Вы также можете программно вызвать prefetch
из $app/navigation
.
sveltekit:reload
По умолчанию среда выполнения SvelteKit перехватывает клики по элементам <a>
и блокирует обычную навигацию браузера для относительных URL-адресов, соответствующих одному из маршрутов страниц. Иногда нужно сообщить SvelteKit, что определённые ссылки должны обрабатываться с помощью обычной навигации браузера. Примерами этого могут быть ссылка на другую страницу в вашем домене, которая не является частью вашего приложения SvelteKit, или ссылка на эндпоинт.
Добавление атрибута sveltekit:reload
к ссылке...
<a sveltekit:reload href="path">Path</a>
... запустит навигацию браузера с перезагрузкой страницы при нажатии на ссылку.
Ссылки с атрибутом rel="external"
получат такую же обработку. Кроме того, они будут проигнорированы во время пререндера.
sveltekit:noscroll
При переходе по внутренним ссылкам SvelteKit придерживается поведения навигации браузера по умолчанию: он изменяет положение прокрутки на 0,0, чтобы пользователь находился в самом верхнем левом углу страницы (если только ссылка не содержит #hash
, тогда он перейдёт к элементу с соответствующим идентификатором).
В некоторых случаях такое поведение нежелательно. Добавление атрибута sveltekit:noscroll
...
<a href="path" sveltekit:noscroll>Path</a>
... предотвратит прокрутку после перехода по ссылке.
Service workers permalink
Service workers act as proxy servers that handle network requests inside your app. This makes it possible to make your app work offline, but even if you don't need offline support (or can't realistically implement it because of the type of app you're building), it's often worth using service workers to speed up navigation by precaching your built JS and CSS.
In SvelteKit, if you have a src/service-worker.js
file (or src/service-worker.ts
, or src/service-worker/index.js
, etc) it will be built with Vite and automatically registered. You can disable automatic registration if you need to register the service worker with your own logic (e.g. prompt user for update, configure periodic updates, use workbox
, etc).
You can change the location of your service worker and disable automatic registration in your project configuration.
Inside the service worker you have access to the $service-worker
module.
Because it needs to be bundled (since browsers don't yet support import
in this context), and depends on the client-side app's build manifest, service workers only work in the production build, not in development. To test it locally, use vite preview
.
Anchor options permalink
sveltekit:prefetch
SvelteKit uses code splitting to break your app into small chunks (one per route), ensuring fast startup times.
For dynamic routes, such as our src/routes/blog/[slug].svelte
example, that's not enough. In order to render the blog post, we need to fetch the data for it, and we can't do that until we know what slug
is. In the worst case, that could cause lag as the browser waits for the data to come back from the server.
We can mitigate that by prefetching the data. Adding a sveltekit:prefetch
attribute to a link...
<a sveltekit:prefetch href="blog/what-is-sveltekit">What is SvelteKit?</a>
...will cause SvelteKit to run the page's load
function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the click
event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy.
Note that prefetching will not work if the router
setting is false
.
You can also programmatically invoke prefetch
from $app/navigation
.
sveltekit:reload
By default, the SvelteKit runtime intercepts clicks on <a>
elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be handled by normal browser navigation. Examples of this might be linking to another page on your domain that's not part of your SvelteKit app or linking to an endpoint.
Adding a sveltekit:reload
attribute to a link...
<a sveltekit:reload href="path">Path</a>
...will cause browser to navigate via a full page reload when the link is clicked.
Links with a rel="external"
attribute will receive the same treatment. In addition, they will be ignored during prerendering.
sveltekit:noscroll
When navigating to internal links, SvelteKit mirrors the browser's default navigation behaviour: it will change the scroll position to 0,0 so that the user is at the very top left of the page (unless the link includes a #hash
, in which case it will scroll to the element with a matching ID).
In certain cases, you may wish to disable this behaviour. Adding a sveltekit:noscroll
attribute to a link...
<a href="path" sveltekit:noscroll>Path</a>
...will prevent scrolling after the link is clicked.
События permalink
SvelteKit по команде sveltekit:start
запускает пользовательские события на объекте window
после гидратации приложения:
Возможно, вам не понадобится их использовать, но они могут быть полезны, например, в интеграционных тестах.
Адаптеры permalink
Прежде чем развернуть готовое приложение SvelteKit на сервере или сервисе, его необходимо адаптировать под то окружение, в котором оно будет работать. Адаптеры - это небольшие плагины, которые на вход принимают созданное приложение и на выходе генерируют приложение, подготовленное для развертывания в определенном окружении.
По умолчанию проекты настроены на использование @sveltejs/adapter-auto
, который сам определяет окружение и выбирает соответствующий адаптер, где это возможно. Если же требуемая платформа пока не поддерживается, можно подключить один из адаптеров от сообщества или написать свой.
См. adapter-auto README для получения информации о добавлении поддержки новых окружений.
Поддерживаемые платформы
SvelteKit предлагает ряд официально поддерживаемых адаптеров.
Вы можете выполнить развертывание на следующих платформах с адаптером по умолчанию, adapter-auto
:
- Cloudflare Pages через
adapter-cloudflare
- [Netlify] (https://netlify.com) через
adapter-netlify
- Vercel через
adapter-vercel
Node.js
Чтобы создать простой Node-сервер, установите пакет @sveltejs/adapter-node
и обновите svelte.config.js
:
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-node';
После этого svelte-kit build сгенерирует автономное приложение Node в директории build
. Вы можете передать адаптерам параметры, например указать директорию для полученного приложения:
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default {
kit: {
- adapter: adapter()
+ adapter: adapter({ out: 'my-output-directory' })
}
};
Статические сайты
Большинство адаптеров будут генерировать статический HTML для любых страниц, которые возможно предварительно отрисовать. В некоторых случаях, когда можно предварительно отрисовать всё приложение, используйте @sveltejs/adapter-static
для генерации статического HTML кода для всех страниц. Полностью статический сайт может быть размещен на самых разных платформах и хостингах, включая GitHub Pages.
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-static';
Также adapter-static
можно использовать для создания одностраничных приложений (SPA), указав корневую страницу.
Вы должны убедиться, что
trailingSlash
настроен соответствующим образом для вашей среды. Если ваш хост не отображает/a.html
при получении запроса на/a
, вам нужно будет установитьtrailingSlash: 'always'
для создания/a/index.html
.
Контекст платформы
Некоторые адаптеры могут иметь доступ к дополнительной информации о запросе. Например, Cloudflare Workers может получить доступ к объекту env
, содержащему пространства имен KV и т. д. Эта информация может быть передана как свойство platform
в объекте RequestEvent
, который используется в хуках и эндпоинтах. Ознакомьтесь с документацией нужного адаптера, чтобы узнать больше.
Адаптеры сообщества
Для других платформ существуют дополнительные адаптеры от сообщества. После установки соответствующего адаптера с помощью менеджера пакетов обновите svelte.config.js
:
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from 'svelte-adapter-[x]';
Создание адаптера
Мы рекомендуем скопировать и взять за основу адаптер для платформы, которая близка к нужной.
Пакеты адаптеров должны реализовывать следующий API, который создает Adapter
:
// @filename: ambient.d.ts
const AdapterSpecificOptions = any;
// @filename: index.js
// ---cut---
/** @param {AdapterSpecificOptions} options */
export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
const adapter = {
name: 'adapter-package-name',
async adapt(builder) {
// имплементация адаптера
}
};
return adapter;
}
Типы для Adapter
и его параметры доступны в types/config.d.ts.
Есть ряд вещей, которые должны быть выполнены внутри метода adapt
:
- Очищает директорию готовой сборки
- Записывает вывод SvelteKit с помощью
builder.writeClient
,builder.writePrerendered
,builder.writeServer
иbuilder.writeStatic
- Создаёт код, который:
- Импортирует
Server
из${builder.getServerDirectory()}/index.js
- Создаёт экземпляр приложения со сгенерированным методом
builder.generateManifest({ relativePath })
манифестом. - Слушает запросы с платформы и преобразует их в стандартный Request, при необходимости вызывает функцию
server.respond(request, { getClientAddress })
для создания Response и отвечает ей - Глобально настроит
fetch
для работы на целевой платформе. SvelteKit предоставляет хелпер@sveltejs/kit/install-fetch
для платформ, которые могут использоватьnode-fetch
- Импортирует
- При необходимости, соберает модули приложения в единый бандл, чтобы избежать установки зависимостей на целевой платформе
- Помещает статические файлы пользователя и сгенерированные JS/CSS в правильное место для целевой платформы
При возможности, мы рекомендуем помещать готовое приложение в директорию build/
, а любые промежуточные данные в директории '.svelte-kit/' + имя_адаптера
.
API адаптера может меняться до версии 1.0.
Events permalink
SvelteKit emits a sveltekit:start
CustomEvent on the window
object once the app has hydrated.
You probably won't need to use it, but it can be useful in the context of (for example) integration tests.
Adapters permalink
Before you can deploy your SvelteKit app, you need to adapt it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment.
By default, projects are configured to use @sveltejs/adapter-auto
, which detects your production environment and selects the appropriate adapter where possible. If your platform isn't (yet) supported, you may need to install a custom adapter or write one.
See the adapter-auto README for information on adding support for new environments.
Supported environments
SvelteKit offers a number of officially supported adapters.
You can deploy to the following platforms with the default adapter, adapter-auto
:
Node.js
To create a simple Node server, install the @sveltejs/adapter-node
package and update your svelte.config.js
:
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-node';
With this, vite build
will generate a self-contained Node app inside the build
directory. You can pass options to adapters, such as customising the output directory:
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default {
kit: {
- adapter: adapter()
+ adapter: adapter({ out: 'my-output-directory' })
}
};
Static sites
Most adapters will generate static HTML for any prerenderable pages of your site. In some cases, your entire app might be prerenderable, in which case you can use @sveltejs/adapter-static
to generate static HTML for all your pages. A fully static site can be hosted on a wide variety of platforms, including static hosts like GitHub Pages.
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-static';
You can also use adapter-static
to generate single-page apps (SPAs) by specifying a fallback page.
You must ensure
trailingSlash
is set appropriately for your environment. If your host does not render/a.html
upon receiving a request for/a
then you will need to settrailingSlash: 'always'
to create/a/index.html
instead.
Platform-specific context
Some adapters may have access to additional information about the request. For example, Cloudflare Workers can access an env
object containing KV namespaces etc. This can be passed to the RequestEvent
used in hooks and endpoints as the platform
property — consult each adapter's documentation to learn more.
Community adapters
Additional community-provided adapters exist for other platforms. After installing the relevant adapter with your package manager, update your svelte.config.js
:
/// file: svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from 'svelte-adapter-[x]';
Writing custom adapters
We recommend looking at the source for an adapter to a platform similar to yours and copying it as a starting point.
Adapters packages must implement the following API, which creates an Adapter
:
// @filename: ambient.d.ts
const AdapterSpecificOptions = any;
// @filename: index.js
// ---cut---
/** @param {AdapterSpecificOptions} options */
export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
const adapter = {
name: 'adapter-package-name',
async adapt(builder) {
// adapter implementation
}
};
return adapter;
}
The types for Adapter
and its parameters are available in types/config.d.ts.
Within the adapt
method, there are a number of things that an adapter should do:
- Clear out the build directory
- Write SvelteKit output with
builder.writeClient
,builder.writePrerendered
,builder.writeServer
, andbuilder.writeStatic
- Output code that:
- Imports
Server
from${builder.getServerDirectory()}/index.js
- Instantiates the app with a manifest generated with
builder.generateManifest({ relativePath })
- Listens for requests from the platform, converts them to a standard Request if necessary, calls the
server.respond(request, { getClientAddress })
function to generate a Response and responds with it - expose any platform-specific information to SvelteKit via the
platform
option passed toserver.respond
- Globally shims
fetch
to work on the target platform, if necessary. SvelteKit provides a@sveltejs/kit/install-fetch
helper for platforms that can usenode-fetch
- Imports
- Bundle the output to avoid needing to install dependencies on the target platform, if necessary
- Put the user's static files and the generated JS/CSS in the correct location for the target platform
Where possible, we recommend putting the adapter output under the build/
directory with any intermediate output placed under .svelte-kit/[adapter-name]
.
The adapter API may change before 1.0.
Параметры страницы permalink
По умолчанию SvelteKit сначала отрисовывает любой компонент на сервере и отправляет его клиенту в формате HTML. Затем он снова отрисует компонент в браузере, чтобы сделать его интерактивным в процессе, который называется гидратация. Поэтому необходимо следить, чтобы компоненты могли работать как на сервере, так и в браузере. В конце SvelteKit инициализирует клиентский роутер, который берет на себя последующие переходы между страниц.
Каждый из этих шагов можно контролировать как во всём приложении сразу, так и отдельно для каждой страницы. Обратите внимание, что все настройки, которые указываются для конкретных страниц, помещаются в блок script
с атрибутом context="module"
и применяются только к страницам, но не к макетам.
В случае конфликта глобальных настроек и настроек отдельной страницы, последние будут иметь приоритет.
router
В SvelteKit есть клиентский роутер, который отслеживает переходы (клик по ссылке или по кнопкам истории браузера) и обновляет содержимое страницы, при этом не происходит перезагрузки страницы, как при обычной навигации в браузере.
В некоторых случаях может потребоваться отключить клиентский роутер параметром browser.router
в конфигурации приложения или для отдельной страницы, экспортировав router
:
<script context="module">
export const router = false;
</script>
Это отключит роутер для всех переходов с текущей страницы, даже если он уже используется в приложении.
hydrate
По умолчанию SvelteKit гидратирует полученный с сервера HTML, чтобы получить интерактивную страницу. Некоторым страницам совершенно не нужен JavaScript – например, различного рода посты в блоге или страницы 'О сайте'. В таких случаях можно отключить гидратацию при загрузке приложения глобальным параметром browser.hydrate
в конфигурации или для конкретной страницы, экспортировав константу hydrate
:
<script context="module">
export const hydrate = false;
</script>
Если и
hydrate
иrouter
будут оба равныfalse
, SvelteKit вообще не добавит на страницу никакого JavaScript кода. Если рендеринг на стороне сервера отключен вhandle
,hydrate
должен бытьtrue
, иначе содержимое не будет отображаться.
prerender
Иногда некоторые страницы приложения могут быть представлены в виде простого HTML-файла, созданного во время сборки. Эти страницы могут быть предварительно отрисованы выбранным адаптером.
Предварительная отрисовка происходит автоматически для любой страницы с аннотацией prerender
:
<script context="module">
export const prerender = true;
</script>
Кроме того, вы можете установить config.kit.prerender.default
в true
и предварительно отрисовать все, кроме страниц, которые явно помечены как not prerenderable:
<script context="module">
export const prerender = false;
</script>
Если все ваше приложение подходит для предварительного рендеринга, вы можете использовать
adapter-static
, который выведет файлы, подходящие для использования с любым статическим веб-сервером.
Отрисовка начнется с корня приложения и будут сгенерированы HTML-файлы для всех найденных страниц, подходящих для пререндера. Каждая страница сканируется на предмет элементов <a>
, которые указывают на другие страницы, которые тоже могут быть отрисованы - поэтому нет необходимости явно указывать какие именно страницы нужно обработать. При необходимости, список страниц, которые должны быть предварительно отрисованы, можно задать в параметре entries
в разделе конфигурации prerender
.
Когда не делать пререндер
Основное правило таково: для того, чтобы страница могла быть предварительно отрисована, любые два пользователя, попадающие на одну и ту же страницу приложения, должны получать с сервера одно и то же содержимое.
Не все страницы подходят для пререндеринга. Любое содержимое, которое отрисовано таким образом, видно всем пользователям. Конечно, можно получать персональные данные в
onMount
на такой странице, но это может ухудшить пользовательский опыт, поскольку придется дожидаться получения данных, наблюдая индикатор загрузки.
Обратите внимание, что предварительную отрисовка всё ещё можно сделать для приложения с динамическими маршрутами, как в нашем примере src/routes/blog/[slug].svelte
. Адаптер adapter-static будет обрабатывать запросы к серверу внутри функций load
, поэтому данные, поступающие из src/routes/blog/[slug].json.js
тоже будут сохранены.
Во время предварительной отрисовки нет доступа к объекту url.searchParams
. Если его необходимо использовать на странице, убедитесь, что обращение к нему происходит только в браузере (например, в функции onMount
).
Конфликты маршрутов
Поскольку пререндер создаёт отражение всех маршрутов в виде файлового дерева, то невозможно иметь два эндпоинта, где возникает ситуация, что директория и файл в одном и том же месте будут иметь одинаковое имя. Например, src/routes/foo/index.js
и src/routes/foo/bar.js
будут пытаться создать файлы foo
и foo/bar
, что приведёт к ошибке.
По этой причине, рекомендуется всегда добавлять расширение к имени файла — например, src/routes/foo/index.json.js
и src/routes/foo/bar.json.js
будут сохранены как foo.json
и foo/bar.json
, которые не будут мешать друг другу.
Для маршрутов страниц этой проблемы не возникает, поскольку создаётся файл foo/index.html
, а не foo
.
Создание пакетов permalink
svelte-kit package
в настоящее время является экспериментальным и не подпадает под действие правил семантического управления версиями. Несовместимые с обратной связью изменениями могут произойти в любом будущем выпуске.
Кроме создания web-приложений SvelteKit можно использовать также и для библиотек компонентов.
Содержимое папки src/routes
является основой для приложения. А папка src/lib
просто хранит файлы внутренних библиотек.
Библиотека компонентов в SvelteKit имеет точно такую же структуру папок, но src/lib
становится основой библиотеки, а src/routes
может быть использована для документации или демо-сайта, показывающего работу библиотеки. Также можно использовать эту папку как "песочницу" во время разработки компонента.
Запуск команды svelte-kit package
сгенерирует пакет в новой папке package
(которую можно настроить), содержащий следующие файлы:
- Все файлы из папки
src/lib
, если не указаны какие-либо параметрыinclude
/exclude
. Компоненты Svelte будут предварительно обработаны, файлы TypeScript будут преобразованы в JavaScript. - Определения типов (файлы
d.ts
), которые генерируются для файлов Svelte, JavaScript и TypeScript. Для этого вам нужно установитьtypescript >= 4.0.0
иsvelte2tsx >= 0.4.1
. Определения типов размещаются рядом с их реализацией, рукописные файлыd.ts
копируются как есть. Можно отключить генерацию этих файлов, но мы настоятельно рекомендуем не делать этого. - Файл
package.json
, скопированный из корня проекта, со всеми полями, кроме поля"scripts"
. Список зависимостей"dependencies"
тоже будет скопирован, поэтому добавляйте пакеты, которые нужны для документации или демо-сайта, в поле"devDependencies"
. Также будут добавлены поля"type": "module"
и"exports"
, если в исходном файле их нет.
Поле "exports"
содержит файлы, которые будут доступны из модуля. По умолчанию сюда попадут все файлы из папкиsrc/lib
, только если их имя(или имя папки, в которых они содержатся) не начинаются с символа нижнего подчёркивания. Это поведение можно изменить. Если имеется файл src/lib/index.js
или src/lib/index.svelte
, то он станет корнем пакета.
Например, если имеется компонент src/lib/Foo.svelte
и модуль src/lib/index.js
, который реэкспортирует его, то пользователь вашего пакета сможет импортировать компонент любым из двух способов:
// @filename: ambient.d.ts
declare module 'your-library';
// @filename: index.js
// ---cut---
import { Foo } from 'your-library';
// @filename: ambient.d.ts
declare module 'your-library/Foo.svelte';
// @filename: index.js
// ---cut---
import Foo from 'your-library/Foo.svelte';
Публикация
Для публикации полученного пакета выполните команду:
npm publish ./package
Приведенный выше package
относится к сгенерированному имени каталога, измените его соответствующим образом, если вы указываете иную директорию в package.dir
.
Ограничения
Это относительно экспериментальная функция, которая ещё не полностью реализована. Все файлы, кроме файлов Svelte (предварительно обработанных) и файлов TypeScript (переработанных в JavaScript), копируются как есть.
Page options permalink
By default, SvelteKit will render any component first on the server and send it to the client as HTML. It will then render the component again in the browser to make it interactive in a process called hydration. For this reason, you need to ensure that components can run in both places. SvelteKit will then initialise a router that takes over subsequent navigations.
You can control each of these on a per-app or per-page basis. Note that each of the per-page settings use context="module"
, and only apply to pages, not layouts.
If both are specified, per-page settings override per-app settings in case of conflicts.
router
SvelteKit includes a client-side router that intercepts navigations (from the user clicking on links, or interacting with the back/forward buttons) and updates the page contents, rather than letting the browser handle the navigation by reloading.
In certain circumstances you might need to disable client-side routing with the app-wide browser.router
config option or the page-level router
export:
<script context="module">
export const router = false;
</script>
Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active.
hydrate
Ordinarily, SvelteKit hydrates your server-rendered HTML into an interactive page. Some pages don't require JavaScript at all — many blog posts and 'about' pages fall into this category. In these cases you can skip hydration when the app boots up with the app-wide browser.hydrate
config option or the page-level hydrate
export:
<script context="module">
export const hydrate = false;
</script>
If
hydrate
androuter
are bothfalse
, SvelteKit will not add any JavaScript to the page at all. If server-side rendering is disabled inhandle
,hydrate
must betrue
or no content will be rendered.
prerender
It's likely that at least some pages of your app can be represented as a simple HTML file generated at build time. These pages can be prerendered.
Prerendering happens automatically for any page with the prerender
annotation:
<script context="module">
export const prerender = true;
</script>
Alternatively, you can set config.kit.prerender.default
to true
and prerender everything except pages that are explicitly marked as not prerenderable:
<script context="module">
export const prerender = false;
</script>
If your entire app is suitable for prerendering, you can use
adapter-static
, which will output files suitable for use with any static webserver.
The prerenderer will start at the root of your app and generate HTML for any prerenderable pages it finds. Each page is scanned for <a>
elements that point to other pages that are candidates for prerendering — because of this, you generally don't need to specify which pages should be accessed. If you do need to specify which pages should be accessed by the prerenderer, you can do so with the entries
option in the prerender configuration.
When not to prerender
The basic rule is this: for a page to be prerenderable, any two users hitting it directly must get the same content from the server.
Not all pages are suitable for prerendering. Any content that is prerendered will be seen by all users. You can of course fetch personalized data in
onMount
in a prerendered page, but this may result in a poorer user experience since it will involve blank initial content or loading indicators.
Note that you can still prerender pages that load data based on the page's parameters, like our src/routes/blog/[slug].svelte
example from earlier. The prerenderer will intercept requests made inside load
, so the data served from src/routes/blog/[slug].json.js
will also be captured.
Accessing url.searchParams
during prerendering is forbidden. If you need to use it, ensure you are only doing so in the browser (for example in onMount
).
Route conflicts
Because prerendering writes to the filesystem, it isn't possible to have two endpoints that would cause a directory and a file to have the same name. For example, src/routes/foo/index.js
and src/routes/foo/bar.js
would try to create foo
and foo/bar
, which is impossible.
For that reason among others, it's recommended that you always include a file extension — src/routes/foo/index.json.js
and src/routes/foo/bar.json.js
would result in foo.json
and foo/bar.json
files living harmoniously side-by-side.
For pages, we skirt around this problem by writing foo/index.html
instead of foo
.
svelte-kit CLI permalink
SvelteKit включает в себя утилиту для создания и запуска вашего приложения.
В шаблоне проекта по умолчанию команды svelte-kit dev
, svelte-kit build
, svelte-kit preview
имеют псевдонимы – соответственно npm run dev
, npm run build
и npm start
. Также можно вызвать CLI-утилиту с помощью npx:
npx svelte-kit dev
svelte-kit dev
Запускает сервер для разработки. Принимает следующие параметры:
-p
/--port
— порт, на котором запустить сервер-o
/--open
— открыть вкладку браузера после запуска сервера--host
— открыть доступ к серверу из сети.
Используйте это с осторожностью!
--https
— запустить HTTPS-сервер используя самоподписанный SSL сертификат. Полезно для тестирования функций, поддерживающих только HTTPS, на внешнем устройстве.
Эта команда завершится неудачей, если указанный (или по умолчанию) порт недоступен. Чтобы использовать альтернативный порт вместо сбоя, установите параметр
config.kit.vite.server.strictPort
вfalse
.
svelte-kit build
Создаёт готовую к работе версию приложения и запускает нужный адаптер, если он указан в файле конфигурации. Команда принимает один параметр:
--verbose
— выводить больше информации
svelte-kit preview
После сборки приложения командой svelte-kit build
, можно запустить его локально с помощью команды svelte-kit preview
(вне зависимости от используемого адаптера). Эта команда предназначена для тестирования собранного приложения локально. При запуске приложения на рабочем сервере вы всегда должны использовать адаптер.
Как и svelte-kit dev
, эта команда принимает следующие параметры:
-p
/--port
-o
/--open
--host
--https
svelte-kit package
svelte-kit package
в настоящее время является экспериментальным и не подпадает под действие правил семантического управления версиями. Несовместимые с обратной связью изменениями могут произойти в любом будущем выпуске.
Для авторов пакетов см. Создание пакетов. Скрипт svelte-kit package
принимает следующие опции:
-w
/--watch
— наблюдать изменения файлов в папкеsrc/lib
и пересобирать пакет.
Packaging permalink
svelte-kit package
is currently experimental and is not subject to Semantic Versioning rules. Non-backward compatible changes may occur in any future release.
You can use SvelteKit to build component libraries as well as apps.
When you're creating an app, the contents of src/routes
is the public-facing stuff; src/lib
contains your app's internal library.
A SvelteKit component library has the exact same structure as a SvelteKit app, except that src/lib
is the public-facing bit. src/routes
might be a documentation or demo site that accompanies the library, or it might just be a sandbox you use during development.
Running svelte-kit package
will take the contents of src/lib
and generate a package
directory (which can be configured) containing the following:
- All the files in
src/lib
, unless you configure custominclude
/exclude
options. Svelte components will be preprocessed, TypeScript files will be transpiled to JavaScript. - Type definitions (
d.ts
files) which are generated for Svelte, JavaScript and TypeScript files. You need to installtypescript >= 4.0.0
andsvelte2tsx >= 0.4.1
for this. Type definitions are placed next to their implementation, hand-writtend.ts
files are copied over as is. You can disable generation, but we strongly recommend against it. - A
package.json
copied from the project root with all fields but the"scripts"
field. The"dependencies"
field is included, which means you should add packages that you only need for your documentation or demo site to"devDependencies"
. A"type": "module"
and an"exports"
field will be added if it's not defined in the original file.
The "exports"
field contains the package's entry points. By default, all files in src/lib
will be treated as an entry point unless they start with (or live in a directory that starts with) an underscore, but you can configure this behaviour. If you have a src/lib/index.js
or src/lib/index.svelte
file, it will be treated as the package root.
For example, if you had a src/lib/Foo.svelte
component and a src/lib/index.js
module that re-exported it, a consumer of your library could do either of the following:
// @filename: ambient.d.ts
declare module 'your-library';
// @filename: index.js
// ---cut---
import { Foo } from 'your-library';
// @filename: ambient.d.ts
declare module 'your-library/Foo.svelte';
// @filename: index.js
// ---cut---
import Foo from 'your-library/Foo.svelte';
Publishing
To publish the generated package:
npm publish ./package
The ./package
above is referring to the directory name generated, change accordingly if you configure a custom package.dir
.
Caveats
This is a relatively experimental feature and is not yet fully implemented. All files except Svelte files (preprocessed) and TypeScript files (transpiled to JavaScript) are copied across as-is.
Command Line Interface permalink
SvelteKit projects use Vite, meaning you'll mostly use its CLI (albeit via npm run dev/build/preview
scripts):
vite dev
— start a development servervite build
— build a production version of your appvite preview
— run the production version locally
However SvelteKit includes its own CLI for creating distributable packages and initialising your project:
svelte-kit package
svelte-kit package
is currently experimental and is not subject to Semantic Versioning rules. Non-backward compatible changes may occur in any future release.
See packaging. svelte-kit package
accepts the following options:
-w
/--watch
— watch files insrc/lib
for changes and rebuild the package
svelte-kit sync
svelte-kit sync
creates the generated files for your project such as types and a tsconfig.json
. When you create a new project, it is listed as the prepare
script and will be run automatically as part of the npm lifecycle, so you should not ordinarily have to run this command.
Конфигурация permalink
Конфигурация проекта находится в файле svelte.config.js
. Все значения необязательны. Полный список параметров со значениями по умолчанию показан здесь:
/** @type {import('@sveltejs/kit').Config} */
const config = {
// параметры для svelte.compile (https://svelte.dev/docs#svelte_compile)
compilerOptions: {},
// массив расширений, которые будут считаться компонентами Svelte
extensions: ['.svelte'],
kit: {
adapter: undefined,
appDir: '_app',
browser: {
hydrate: true,
router: true
},
csp: {
mode: 'auto',
directives: {
'default-src': undefined
// ...
}
},
files: {
assets: 'static',
hooks: 'src/hooks',
lib: 'src/lib',
params: 'src/params',
routes: 'src/routes',
serviceWorker: 'src/service-worker',
template: 'src/app.html'
},
floc: false,
inlineStyleThreshold: 0,
methodOverride: {
parameter: '_method',
allowed: []
},
outDir: '.svelte-kit',
package: {
dir: 'package',
// кроме файлов .d.ts и начинающихся с нижнего подчеркивания
exports: (filepath) => !/^_|\/_|\.d\.ts$/.test(filepath),
files: () => true,
emitTypes: true
},
paths: {
assets: '',
base: ''
},
prerender: {
concurrency: 1,
crawl: true,
default: false,
enabled: true,
entries: ['*'],
onError: 'fail'
},
routes: (filepath) => !/(?:(?:^_|\/_)|(?:^\.|\/\.)(?!well-known))/.test(filepath),
serviceWorker: {
register: true,
files: (filepath) => !/\.DS_Store/.test(filepath)
},
trailingSlash: 'never',
version: {
name: Date.now().toString(),
pollInterval: 0
},
vite: () => ({})
},
// SvelteKit использует vite-plugin-svelte. Здесь можно указать его параметры.
// Список параметров см. на https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md
// Параметры для svelte.preprocess (https://svelte.dev/docs#svelte_preprocess)
preprocess: null
};
export default config;
adapter
Требуется при запуске svelte-kit build
и определяет, как преобразуется вывод для разных платформ. См. Адаптеры.
alias
Объект, содержащий ноль или более псевдонимов, используемых для замены значений в инструкциях import
. Эти псевдонимы автоматически передаются в Vite и TypeScript.
Например, вы можете добавить псевдонимы в папку components
и utils
:
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
alias: {
$components: 'src/components',
$utils: 'src/utils'
}
}
};
Встроенный псевдоним
$lib
контролируетсяconfig.kit.files.lib
, поскольку он используется для упаковки.
appDir
Директория относительно paths.assets
в которой будут находиться скомпилированные JS/CSS файлы и импортированные статические ресурсы. Имена файлов в этой директории будут содержать хеши на основе их содержимого, то есть эти файлы можно кэшировать на неопределённый срок. Значение параметра не должно начинаться или заканчиваться на /
.
browser
Объект, содержащий ноль или более из следующих значений типа boolean
:
hydrate
— следует ли гидратировать серверный HTML с помощью клиентского приложения. Устанавливайте этот параметр вfalse
только в исключительных случаях.router
- включает или отключает клиентский роутер по всему приложению.
csp
Объект, содержащий ноль или более из следующих значений:
mode
- 'hash', 'nonce' или 'auto'directives
— объект, содержащий пары[директива]: значения[]
.
Настройка Content Security Policy. CSP помогает защитить пользователей от XSS-атак, ограничивая места, из которых могут загружаться ресурсы. Например, такая конфигурация...
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
csp: {
directives: {
'script-src': ['self']
}
}
}
}
export default config;
...позволит предотвратить загрузку скриптов с внешних сайтов. Для любых инлайновых стилей и генерируемых скриптов SvelteKit автоматически дополнит указанные директивы нужным хешем(в зависимости от mode
).
При предварительной отрисовке страниц заголовок CSP добавляется с помощью тега <meta http-equiv>
(учтите, что в этом случае директивы frame-ancestors
, report-uri
и sandbox
будут игнорироваться).
При значении
mode: 'auto'
, SvelteKit будет использовать аттрибуты nonce для динамических страниц и аттрибуты hashe для предварительно отрисованных. Использование аттрибута nonce с предварительно отрисованными страницами небезопасно а, значит, запретно.
endpointExtensions
Массив расширений файлов, которые SvelteKit будет рассматривать как эндпоинты. Файлы с расширениями, которые не соответствуют ни config.extensions
, ни config.kit.endpointExtensions
, будут игнорироваться маршрутизатором.
files
Объект, содержащий следующие строковые параметры(все опциональны):
assets
— место для размещения статических файлов, которые должны иметь стабильные URL-адреса и не подвергаться обработке, напримерfavicon.ico
иmanifest.json
hooks
— путь к файлу хуков (см. Хуки)lib
— внутренняя библиотека вашего приложения, доступная во всей кодовой базе как$lib
params
- каталог, содержащий сопоставление параметровroutes
— файлы, которые определяют структуру вашего приложения (Маршруты)serviceWorker
— файл сервис-воркераtemplate
— расположение шаблона для HTML-ответов сервера
floc
Google FLoC — это технология таргетированной рекламы, которую Electronic Frontier Foundation сочла вредной для конфиденциальности пользователей. Браузеры, отличные от Chrome отказались её реализовать.
SvelteKit по умолчанию отключает использование FLoC в приложении, также как это делают другие сервисы, например GitHub Pages. Если для параметра floc
не установлено значение true
, к ответу сервера будет добавлен такой заголовок:
Permissions-Policy: Interest-cohort = ()
Это может применяться только при серверном рендеринге — заголовки для предварительно отрисованных страниц (например, созданных с помощью adapter-static) определяются платформой хостинга.
inlineStyleThreshold
Встраивание CSS-стилей на странице внутри блока <style>
в теге <head>
. Параметр указывает максимальный размер файла, который будет встроен в страницу. Содержимое всех CSS-файлов, которые необходимы данной странице и по размеру меньше указанного значения, будет слито и помещено в блок <style>
.
Установка данного параметра приведет к меньшему количеству первоначальных запросов и может улучшить метрику Первой Отрисовки Контента. Но при этом получаемый HTML возрастает в размере, а эффективность кэширования в браузере снижается.
methodOverride
См. HTTP методы. Объект, содержащий ноль или более из следующего:
parameter
- имя параметра запроса, используемое для передачи требуемого значения методаallowed
- массив методов HTTP, которые могут быть использованы при переопределении исходного метода запроса
outDir
Каталог, в который SvelteKit записывает файлы во время dev
и build
. Вы должны исключить этот каталог из системы управления версиями.
package
Опции, связанные с созданием пакетов.
dir
- директория для готового пакетаemitTypes
- по умолчаниюsvelte-kit package
автоматически сгенерирует файлы определений типов.d.ts
для пакета. Хоть этот параметр и можно отключить, но мы считаем, что для качества экосистемы нужно всегда генерировать файлы определений типов. Убедитесь, что есть веская причина устанавливать значение равнымfalse
(например, если имеются определения типов, написанные вручную).exports
- функция вида(filepath: string) => boolean
. Когда возвращаетtrue
, путь к файлу будет включён в полеexports
вpackage.json
. Любые существующие значения в исходномpackage.json
будут объединены с полученными изexports
значениямиfiles
- функция вида(filepath: string) => boolean
. Когда возвращаетtrue
, файл по указанному пути будет обработан и скопирован в папку, определенной в параметреdir
Для удобного сопоставления путей в функциях значений exports
и files
, можно использовать различные внешние библиотеки:
// @filename: ambient.d.ts
declare module 'micromatch';
/// file: svelte.config.js
// @filename: index.js
// ---cut---
import mm from 'micromatch';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
package: {
exports: (filepath) => {
if (filepath.endsWith('.d.ts')) return false;
return mm.isMatch(filepath, ['!**/_*', '!**/internal/**'])
},
files: mm.matcher('!**/build.*')
}
}
};
export default config;
paths
Объект, содержащий следующие строковые параметры(все опциональны):
assets
— абсолютный путь, откуда будут загружаться статические файлы приложения. Это может быть полезно в случае, когда эти файлы находятся в каком-либо внешнем хранилище.base
— путь относительно корня, который должен начинаться, но не заканчиваться на/
(например,/base-path
), если только это не пустая строка. Указывает, где будет находиться приложение и позволяет запускать приложение из поддиректории основного домена.
prerender
См. Предварительная отрисовка. Объект, содержащий следующие параметры(все опциональны):
-
concurrency
- сколько страниц может отрисовываться одновременно. Хоть JS и однопоточный, но в случаях, когда производительность отрисовки зависит от сети (например, загрузка контента с удалённой CMS), это поможет ускорить процесс, поскольку во время ожидания ответа сети будут обрабатываться другие задачи. -
crawl
— определяет, должен ли SvelteKit находить страницы для предварительной отрисовки, переходя по ссылкам с исходных страниц -
default
- установите значениеtrue
для предварительной отрисовки страниц не содержащихexport const prerender = false
-
enabled
— установите вfalse
, чтобы полностью отключить предварительную отрисовку -
entries
— массив страниц для предварительной отрисовки или начала сканирования (приcrawl: true
). Строка*
включает все нединамические маршруты (т.е. страницы без[параметр]
) -
onError
-
'fail'
— (по умолчанию) прерывает сборку при обнаружении ошибки маршрутизации при переходе по ссылке -
'continue'
— позволяет продолжить сборку, несмотря на ошибки маршрутизации -
function
— пользовательский обработчик ошибок, в котором можно вывести сообщение, вызвать исключение или прервать сборку, а также совершить любые другие действия, основываясь на полученных аргументахimport static from '@sveltejs/adapter-static'; /** @type {import('@sveltejs/kit').PrerenderErrorHandler} */ const handleError = ({ status, path, referrer, referenceType }) => { if (path.startsWith('/blog')) throw new Error('Missing a blog page!'); console.warn(`${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`); };
/** @type {import('@sveltejs/kit').Config} */ const config = { kit: { adapter: static(), prerender: { onError: handleError } } };
export default config;
-
routes
Функция вида (filepath: string) => boolean
, которая определяет, какие файлы создают маршруты, а какие рассматриваются как приватные модули.
serviceWorker
Объект, содержащий ноль или более из следующих значений:
register
- если установлено значениеfalse
, отключит автоматическую регистрацию сервис-воркераfiles
- функция вида(filepath: string) => boolean
. Когда возвращаетtrue
, запрошенный файл будет доступен в$service-worker.files
.
trailingSlash
Следует ли удалять, добавлять или игнорировать конечные слэши при разрешении URL-адресов (обратите внимание, что это относится только к страницам, а не к эндпоинтам).
'never'
- перенаправит/x/
на/x
'always'
- перенаправит/x
на/x/
'ignore'
- ничего не делать./x
и/x/
будут рассматриваться эквивалентно
Этот параметр влияет также и на предварительную отрисовку. Для соответствия с работой web-серверов при сохранении отрисованной страницы с адресом /about
, когда параметр trailingSlash
имеет значение always
, будет создана директория с индексным файлом about/index.html
, в иных случаях просто файл about.html
.
Игнорирование конечных слэшей не рекомендуется — семантика относительных путей в двух случаях различается (
./y
от/x
будет/y
, а от/x/
станет/x/y
). Кроме того,/x
и/x/
рассматриваются как отдельные URL-адреса, что вредно для SEO. При использовании этой опции, убедитесь, что логика добавления или удаления конечных слэшей изrequest.path
реализована в функцииhandle
.
version
Объект, содержащий ноль или более из следующих значений:
name
- текущая весрия приложения в виде строкиpollInterval
- интервал в миллисекундах для опроса новой версии
Навигация на стороне клиента может сбоить, когда на сервер загружена новая версия приложения, а люди всё ещё используют ранее загруженную версию. Если данные для следующей страницы уже загружены с сервера, они могут быть устаревшими. В таком случае может быть запрошен более не существующий JavaScript-файл. SvelteKit решает эту проблему, отключая клиентский роутер и выполняя переход с перезагрузкой страницы, когда обнаруживает, что значение версии приложения, указанное в name
, изменилось (по умолчанию в качестве версии используется метка времени сборки).
При установке значения pollInterval
отличным от ноля, SvelteKit будет периодически опрашивать сервер на наличие новой версии и установит значение хранилища updated
в true
, когда она будет обнаружена.
vite
Объект конфигурации Vite или функция, которая его возвращает. Вы можете использовать плагины Vite и Rollup в параметре plugins
для более продвинутой сборки приложения,например, использовав оптимизацию изображений, Tauri, WASM, Workbox и прочее. Некоторые параметры сборки установить невозможно, они используются внутри SvelteKit и определяются его параметрами.
Configuration permalink
Your project's configuration lives in a svelte.config.js
file. All values are optional. The complete list of options, with defaults, is shown here:
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
// options passed to svelte.compile (https://svelte.dev/docs#compile-time-svelte-compile)
compilerOptions: {},
// an array of file extensions that should be treated as Svelte components
extensions: ['.svelte'],
kit: {
adapter: undefined,
alias: {},
appDir: '_app',
browser: {
hydrate: true,
router: true
},
csp: {
mode: 'auto',
directives: {
'default-src': undefined
// ...
}
},
moduleExtensions: ['.js', '.ts'],
files: {
assets: 'static',
hooks: 'src/hooks',
lib: 'src/lib',
params: 'src/params',
routes: 'src/routes',
serviceWorker: 'src/service-worker',
template: 'src/app.html'
},
inlineStyleThreshold: 0,
methodOverride: {
parameter: '_method',
allowed: []
},
outDir: '.svelte-kit',
package: {
dir: 'package',
emitTypes: true,
// excludes all .d.ts and files starting with _ as the name
exports: (filepath) => !/^_|\/_|\.d\.ts$/.test(filepath),
files: () => true
},
paths: {
assets: '',
base: ''
},
prerender: {
concurrency: 1,
crawl: true,
default: false,
enabled: true,
entries: ['*'],
onError: 'fail',
origin: 'http://sveltekit-prerender'
},
routes: (filepath) => !/(?:(?:^_|\/_)|(?:^\.|\/\.)(?!well-known))/.test(filepath),
serviceWorker: {
register: true,
files: (filepath) => !/\.DS_Store/.test(filepath)
},
trailingSlash: 'never',
version: {
name: Date.now().toString(),
pollInterval: 0
}
},
// options passed to svelte.preprocess (https://svelte.dev/docs#compile-time-svelte-preprocess)
preprocess: null
};
export default config;
adapter
Run when executing vite build
and determines how the output is converted for different platforms. See Adapters.
alias
An object containing zero or more aliases used to replace values in import
statements. These aliases are automatically passed to Vite and TypeScript.
For example, you can add aliases to a components
and utils
folder:
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
alias: {
$components: 'src/components',
$utils: 'src/utils'
}
}
};
The built-in
$lib
alias is controlled byconfig.kit.files.lib
as it is used for packaging.
appDir
The directory relative to paths.assets
where the built JS and CSS (and imported assets) are served from. (The filenames therein contain content-based hashes, meaning they can be cached indefinitely). Must not start or end with /
.
browser
An object containing zero or more of the following boolean
values:
hydrate
— whether to hydrate the server-rendered HTML with a client-side app. (It's rare that you would set this tofalse
on an app-wide basis.)router
— enables or disables the client-side router app-wide.
csp
An object containing zero or more of the following values:
mode
— 'hash', 'nonce' or 'auto'directives
— an object of[directive]: value[]
pairsreportOnly
— an object of[directive]: value[]
pairs for CSP report-only mode
Content Security Policy configuration. CSP helps to protect your users against cross-site scripting (XSS) attacks, by limiting the places resources can be loaded from. For example, a configuration like this...
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
csp: {
directives: {
'script-src': ['self']
},
reportOnly: {
'script-src': ['self']
}
}
}
};
export default config;
...would prevent scripts loading from external sites. SvelteKit will augment the specified directives with nonces or hashes (depending on mode
) for any inline styles and scripts it generates.
When pages are prerendered, the CSP header is added via a <meta http-equiv>
tag (note that in this case, frame-ancestors
, report-uri
and sandbox
directives will be ignored).
When
mode
is'auto'
, SvelteKit will use nonces for dynamically rendered pages and hashes for prerendered pages. Using nonces with prerendered pages is insecure and therefore forbidden.
Note that most Svelte transitions work by creating an inline
<style>
element. If you use these in your app, you must either leave thestyle-src
directive unspecified or addunsafe-inline
.
moduleExtensions
An array of file extensions that SvelteKit will treat as modules. Files with extensions that match neither config.extensions
nor config.kit.moduleExtensions
will be ignored by the router.
files
An object containing zero or more of the following string
values:
assets
— a place to put static files that should have stable URLs and undergo no processing, such asfavicon.ico
ormanifest.json
hooks
— the location of your hooks module (see Hooks)lib
— your app's internal library, accessible throughout the codebase as$lib
params
— a directory containing parameter matchersroutes
— the files that define the structure of your app (see Routing)serviceWorker
— the location of your service worker's entry point (see Service workers)template
— the location of the template for HTML responses
inlineStyleThreshold
Inline CSS inside a <style>
block at the head of the HTML. This option is a number that specifies the maximum length of a CSS file to be inlined. All CSS files needed for the page and smaller than this value are merged and inlined in a <style>
block.
This results in fewer initial requests and can improve your First Contentful Paint score. However, it generates larger HTML output and reduces the effectiveness of browser caches. Use it advisedly.
methodOverride
See HTTP Method Overrides. An object containing zero or more of the following:
parameter
— query parameter name to use for passing the intended method valueallowed
- array of HTTP methods that can be used when overriding the original request method
outDir
The directory that SvelteKit writes files to during dev
and build
. You should exclude this directory from version control.
package
Options related to creating a package.
dir
- output directoryemitTypes
- by default,svelte-kit package
will automatically generate types for your package in the form of.d.ts
files. While generating types is configurable, we believe it is best for the ecosystem quality to generate types, always. Please make sure you have a good reason when setting it tofalse
(for example when you want to provide handwritten type definitions instead)exports
- a function with the type of(filepath: string) => boolean
. Whentrue
, the filepath will be included in theexports
field of thepackage.json
. Any existing values in thepackage.json
source will be merged with values from the originalexports
field taking precedencefiles
- a function with the type of(filepath: string) => boolean
. Whentrue
, the file will be processed and copied over to the final output folder, specified indir
For advanced filepath
matching, you can use exports
and files
options in conjunction with a globbing library:
// @filename: ambient.d.ts
declare module 'micromatch';
/// file: svelte.config.js
// @filename: index.js
// ---cut---
import mm from 'micromatch';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
package: {
exports: (filepath) => {
if (filepath.endsWith('.d.ts')) return false;
return mm.isMatch(filepath, ['!**/_*', '!**/internal/**']);
},
files: mm.matcher('!**/build.*')
}
}
};
export default config;
paths
An object containing zero or more of the following string
values:
assets
— an absolute path that your app's files are served from. This is useful if your files are served from a storage bucket of some kindbase
— a root-relative path that must start, but not end with/
(e.g./base-path
), unless it is the empty string. This specifies where your app is served from and allows the app to live on a non-root path
prerender
See Prerendering. An object containing zero or more of the following:
-
concurrency
— how many pages can be prerendered simultaneously. JS is single-threaded, but in cases where prerendering performance is network-bound (for example loading content from a remote CMS) this can speed things up by processing other tasks while waiting on the network response -
crawl
— determines whether SvelteKit should find pages to prerender by following links from the seed page(s) -
default
— set totrue
to prerender encountered pages not containingexport const prerender = false
-
enabled
— set tofalse
to disable prerendering altogether -
entries
— an array of pages to prerender, or start crawling from (ifcrawl: true
). The*
string includes all non-dynamic routes (i.e. pages with no[parameters]
) -
onError
-
'fail'
— (default) fails the build when a routing error is encountered when following a link -
'continue'
— allows the build to continue, despite routing errors -
function
— custom error handler allowing you to log,throw
and fail the build, or take other action of your choosing based on the details of the crawlimport adapter from '@sveltejs/adapter-static'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { adapter: adapter(), prerender: { onError: ({ status, path, referrer, referenceType }) => { if (path.startsWith('/blog')) throw new Error('Missing a blog page!'); console.warn( `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}` ); } } } }; export default config;
-
-
origin
— the value ofurl.origin
during prerendering; useful if it is included in rendered content
routes
A (filepath: string) => boolean
function that determines which files create routes and which are treated as private modules.
serviceWorker
An object containing zero or more of the following values:
register
- if set tofalse
, will disable automatic service worker registrationfiles
- a function with the type of(filepath: string) => boolean
. Whentrue
, the given file will be available in$service-worker.files
, otherwise it will be excluded.
trailingSlash
Whether to remove, append, or ignore trailing slashes when resolving URLs (note that this only applies to pages, not endpoints).
'never'
— redirect/x/
to/x
'always'
— redirect/x
to/x/
'ignore'
— don't automatically add or remove trailing slashes./x
and/x/
will be treated equivalently
This option also affects prerendering. If trailingSlash
is always
, a route like /about
will result in an about/index.html
file, otherwise it will create about.html
, mirroring static webserver conventions.
Ignoring trailing slashes is not recommended — the semantics of relative paths differ between the two cases (
./y
from/x
is/y
, but from/x/
is/x/y
), and/x
and/x/
are treated as separate URLs which is harmful to SEO. If you use this option, ensure that you implement logic for conditionally adding or removing trailing slashes fromrequest.path
inside yourhandle
function.
version
An object containing zero or more of the following values:
name
- current app version stringpollInterval
- interval in milliseconds to poll for version changes
Client-side navigation can be buggy if you deploy a new version of your app while people are using it. If the code for the new page is already loaded, it may have stale content; if it isn't, the app's route manifest may point to a JavaScript file that no longer exists. SvelteKit solves this problem by falling back to traditional full-page navigation if it detects that a new version has been deployed, using the name
specified here (which defaults to a timestamp of the build).
If you set pollInterval
to a non-zero value, SvelteKit will poll for new versions in the background and set the value of the updated
store to true
when it detects one.
Types permalink
@sveltejs/kit
Все API в Sveltekit полностью типизированны. Следующие типы могут быть импортированы из @sveltejs/kit
TYPES
App
namespace
Можно сказать Sveltekit, как тизировать объекты внутри вашего приложения, объявив пространство имен App
. По умолчанию новый проект будет иметь файл под названием src/app.d.ts
, содержащий следующее:
/// <reference types="@sveltejs/kit" />
declare namespace App {
interface Locals {}
interface Platform {}
interface Session {}
interface Stuff {}
}
После заполнения этих интерфейсов, вы получите безопасное использование типов в event.locals
, event.platform
, session
и stuff
:
App.Locals
Интерфейс, который определяет event.locals
, доступ к которому можно получить в хуках (handle
, handleError
и getSession
) и эндпоинтах.
App.Platform
Если текущий адаптер предоставляет контекст платформы через event.platform
, укажите его здесь.
App.Session
Интерфейс, который определяет объект session
, как аргумента для функций load
, так и значения хранилища session.
App.Stuff
Интерфейс, который определяет объект stuff
во входных и выходных данных функции load
, а так же в значении свойства stuff
в хранилище page.
Сгенерированные типы
Типы RequestHandler
и Load
принимают аргумент Params
, позволяя вам ввести объект params
. Например, этот эндпоинт ожидает параметры foo
, bar
и baz
:
/// file: src/routes/[foo]/[bar]/[baz].js
// @errors: 2355
/** @type {import('@sveltejs/kit').RequestHandler<{
* foo: string;
* bar: string;
* baz: string
* }>} */
export async function get({ params }) {
// ...
}
Излишне говорить, что это громоздко записывать и менее портативно (если бы вы переименовали каталог [foo]
в [qux]
, тип больше не отражал бы реальность).
Чтобы решить эту проблему, SvelteKit генерирует файлы .d.ts
для каждой из ваших конечных точек и страниц:
/// file: .svelte-kit/types/src/routes/[foo]/[bar]/__types/[baz].d.ts
/// link: false
import type { RequestHandler as GenericRequestHandler, Load as GenericLoad } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<
{ foo: string; bar: string; baz: string },
Body
>;
export type Load<
InputProps extends Record<string, any> = Record<string, any>,
OutputProps extends Record<string, any> = InputProps
> = GenericLoad<{ foo: string; bar: string; baz: string }, InputProps, OutputProps>;
Эти файлы можно импортировать в конечные точки и страницы в качестве братьев и сестер благодаря опции rootDirs
в конфигурации TypeScript:
/// file: src/routes/[foo]/[bar]/[baz].js
// @filename: __types/[baz].d.ts
import type { RequestHandler as GenericRequestHandler, Load as GenericLoad } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<
{ foo: string, bar: string, baz: string },
Body
>;
// @filename: index.js
// @errors: 2355
// ---cut---
/** @type {import('./__types/[baz]').RequestHandler} */
export async function get({ params }) {
// ...
}
<script context="module">
/** @type {import('./__types/[baz]').Load} */
export async function load({ params, fetch, session, stuff }) {
// ...
}
</script>
Чтобы это сработало, ваш собственный
tsconfig.json
илиjsconfig.json
должен расширяться от сгенерированного.svelte-kit/tsconfig.json
(где.svelte-kit
- вашoutDir
):{ "extends": "./.svelte-kit/tsconfig.json" }
tsconfig.json
Сгенерированный файл .svelte-kit/tsconfig.json
содержит смесь опций. Некоторые из них генерируются программно на основе конфигурации вашего проекта и, как правило, не должны быть переопределены без уважительной причины:
// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
"baseUrl": "..",
"paths": {
"$lib": "src/lib",
"$lib/*": "src/lib/*"
},
"rootDirs": ["..", "./types"]
},
"include": ["../src/**/*.js", "../src/**/*.ts", "../src/**/*.svelte"],
"exclude": ["../node_modules/**", "./**"]
}
Другие необходимы для правильной работы SvelteKit, а также должны оставаться нетронутыми, если вы не знаете, что делаете:
// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
// это гарантирует, что типы явно
// импортируется с `import type`, который
// необходимо, так как svelte-preprocess не может
// в противном случае правильно компилируйте компоненты
"importsNotUsedAsValues": "error",
// Vite компилирует один модуль TypeScript
// за раз, а не компилировать
// весь график модуля
"isolatedModules": true,
// TypeScript не может "видеть", когда вы
// используйте импортированное значение в вашем
// разметка, поэтому нам это нужно
"preserveValueImports": true,
// Настройки для праивильной работы
// `svelte-kit build` и `svelte-kit package`
"lib": ["esnext", "DOM"],
"moduleResolution": "node",
"module": "esnext",
"target": "esnext"
}
}
SEO permalink
Самым важным аспектом SEO является создание высококачественного контента, который широко связан со всем Интернетом. Тем не менее, есть несколько технических соображений для создания сайтов, которые хорошо ранжируются.
Из коробки
SSR
В то время как поисковые системы в последние годы стали лучше индексировать контент, отображаемый с помощью клиентского JavaScript, контент, отображаемый на стороне сервера, индексируется чаще и надежнее. SvelteKit использует SSR по умолчанию, и хотя вы можете отключить его в handle
, вы должны оставить его включенным, если у вас нет веской причины не делать этого.
Рендеринг SvelteKit легко настраивается, и при необходимости вы можете реализовать динамический рендеринг. Обычно это не рекомендуется, поскольку SSR имеет и другие преимущества помимо SEO.
Производительность
Такие сигналы, как Core Web Vitals, влияют на ранжирование в поисковых системах. Поскольку Svelte и SvelteKit создают минимальные накладные расходы, проще создавать высокопроизводительные сайты. Вы можете проверить производительность своего сайта с помощью Google PageSpeed Insights или Lighthouse.
Нормализованные URL
SvelteKit перенаправляет пути с косой чертой в конце на пути без косой черты (или наоборот, в зависимости от вашей конфигурации), поскольку повторяющиеся URL-адреса вредны для SEO.
Ручная настройка
<title> and <meta>
Каждая страница должна иметь хорошо написанные и уникальные элементы <title>
и <meta name="description">
внутри <svelte:head>
. Руководство по написанию описательных заголовков и описаний, а также другие рекомендации по обеспечению понятности контента для поисковых систем можно найти в документации Google [Lighthouse SEO-аудиты] (https://web.dev/lighthouse-seo/).
Распространенным шаблоном является возврат связанных с SEO
stuff
из функций загрузки страницы, а затем их использование (как$page.stuff
) в<svelte:head>
в вашем корневом макете.
Структурированные данные
Структурированные данные помогают поисковым системам понять содержание страницы. Если вы используете структурированные данные вместе с svelte-preprocess
, вам нужно будет явно сохранить данные ld+json
(это может измениться в будущем ):
/// file: svelte.config.js
// @filename: ambient.d.ts
declare module 'svelte-preprocess';
// @filename: index.js
// ---cut---
import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: preprocess({
preserve: ['ld+json'],
// ...
})
};
export default config;
Карта сайта
Карта сайта помогает поисковым системам определять приоритетность страниц вашего сайта, особенно если у вас большой объем контента. Вы можете создать карту сайта динамически, используя эндпоинт:
/// file: src/routes/sitemap.xml.js
export async function get() {
return {
headers: {
'Content-Type': 'application/xml'
},
body: `
<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="https://www.w3.org/1999/xhtml"
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"
>
<!-- <url> elements go here -->
</urlset>
`.trim()
};
}
AMP
Печальная реальность современной веб-разработки заключается в том, что иногда необходимо создать Ускоренную мобильную страницу (AMP) версию вашего сайта. В SvelteKit это можно сделать, принудив следующие параметры конфигурация...
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// комбинация этих опций
// отключает JavaScript
browser: {
hydrate: false,
router: false
},
// так как <link rel="stylesheet"> не
// разрешено, все стили инлайнятся
inlineStyleThreshold: Infinity
}
};
export default config;
...и преобразование HTML с помощью transformPage
вместе с transform
, импортированным из @sveltejs/amp
:
import * as amp from '@sveltejs/amp';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
return resolve(event, {
transformPage: ({ html }) => amp.transform(html)
});
}
Рекомендуется использовать хук
handle
для проверки преобразованного HTML с помощьюamphtml-validator
, но только если вы предварительно отрисовываете страницы, так как это очень медленно.
false permalink
TYPES
Generated types
The RequestHandler
and Load
types both accept a Params
argument allowing you to type the params
object. For example this endpoint expects foo
, bar
and baz
params:
/// file: src/routes/[foo]/[bar]/[baz].js
// @errors: 2355
/** @type {import('@sveltejs/kit').RequestHandler<{
* foo: string;
* bar: string;
* baz: string
* }>} */
export async function GET({ params }) {
// ...
}
Needless to say, this is cumbersome to write out, and less portable (if you were to rename the [foo]
directory to [qux]
, the type would no longer reflect reality).
To solve this problem, SvelteKit generates .d.ts
files for each of your endpoints and pages:
/// file: .svelte-kit/types/src/routes/[foo]/[bar]/__types/[baz].d.ts
/// link: false
import type { RequestHandler as GenericRequestHandler, Load as GenericLoad } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<
{ foo: string; bar: string; baz: string },
Body
>;
export type Load<
InputProps extends Record<string, any> = Record<string, any>,
OutputProps extends Record<string, any> = InputProps
> = GenericLoad<{ foo: string; bar: string; baz: string }, InputProps, OutputProps>;
These files can be imported into your endpoints and pages as siblings, thanks to the rootDirs
option in your TypeScript configuration:
/// file: src/routes/[foo]/[bar]/[baz].js
// @filename: __types/[baz].d.ts
import type { RequestHandler as GenericRequestHandler, Load as GenericLoad } from '@sveltejs/kit';
export type RequestHandler<Body = any> = GenericRequestHandler<
{ foo: string, bar: string, baz: string },
Body
>;
// @filename: index.js
// @errors: 2355
// ---cut---
/** @type {import('./__types/[baz]').RequestHandler} */
export async function GET({ params }) {
// ...
}
<script context="module">
/** @type {import('./__types/[baz]').Load} */
export async function load({ params, fetch, session, stuff }) {
// ...
}
</script>
For this to work, your own
tsconfig.json
orjsconfig.json
should extend from the generated.svelte-kit/tsconfig.json
(where.svelte-kit
is youroutDir
):{ "extends": "./.svelte-kit/tsconfig.json" }
Default tsconfig.json
The generated .svelte-kit/tsconfig.json
file contains a mixture of options. Some are generated programmatically based on your project configuration, and should generally not be overridden without good reason:
/// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
"baseUrl": "..",
"paths": {
"$lib": "src/lib",
"$lib/*": "src/lib/*"
},
"rootDirs": ["..", "./types"]
},
"include": ["../src/**/*.js", "../src/**/*.ts", "../src/**/*.svelte"],
"exclude": ["../node_modules/**", "./**"]
}
Others are required for SvelteKit to work properly, and should also be left untouched unless you know what you're doing:
/// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
// this ensures that types are explicitly
// imported with `import type`, which is
// necessary as svelte-preprocess cannot
// otherwise compile components correctly
"importsNotUsedAsValues": "error",
// Vite compiles one TypeScript module
// at a time, rather than compiling
// the entire module graph
"isolatedModules": true,
// TypeScript cannot 'see' when you
// use an imported value in your
// markup, so we need this
"preserveValueImports": true,
// This ensures both `vite build`
// and `svelte-kit package` work correctly
"lib": ["esnext", "DOM"],
"moduleResolution": "node",
"module": "esnext",
"target": "esnext"
}
}
Файлы ресурсов permalink
Импортирование
Vite автоматически обработает импортированные файлы для повышения производительности. Хэши будут добавлены к именам файлов, чтобы их можно было кэшировать, а ресурсы, меньшие, чем assetsInlineLimit
, будут встроены.
<script>
import logo from '$lib/assets/logo.png';
</script>
<img alt="The project logo" src={logo} />
Если вы предпочитаете ссылаться на файлы ресурсов непосредственно в разметке, можно использовать препроцессор, такой как [svelte-preprocess-import-assets] (https://github.com/bluwy/svelte-preprocess-import-assets) или [svelte-image] (https://github.com/matyunya/svelte-image).
Для файлов ресурсов, включенных через CSS функцию url()
, можно найти опцию experimental.useVitePreprocess
:
// svelte.config.js
export default {
experimental: {
useVitePreprocess: true
}
};
Оптимизация
Можно использовать сжатые форматы изображений, такие как .webp
или .avif
, или отзывчивые изображения, которые отдают разные размеры в зависимости от экрана вашего устройства. Для изображений, которые статически включены в проект, можно использовать препроцессор, такой как [svelte-image] (https://github.com/matyunya/svelte-image) или плагин Vite, такой как [vite-imagetools](https://github.com/JonasKruckenberg/
false permalink
The most important aspect of SEO is to create high-quality content that is widely linked to from around the web. However, there are a few technical considerations for building sites that rank well.
Out of the box
SSR
While search engines have got better in recent years at indexing content that was rendered with client-side JavaScript, server-side rendered content is indexed more frequently and reliably. SvelteKit employs SSR by default, and while you can disable it in handle
, you should leave it on unless you have a good reason not to.
SvelteKit's rendering is highly configurable and you can implement dynamic rendering if necessary. It's not generally recommended, since SSR has other benefits beyond SEO.
Performance
Signals such as Core Web Vitals impact search engine ranking. Because Svelte and SvelteKit introduce minimal overhead, it's easier to build high performance sites. You can test your site's performance using Google's PageSpeed Insights or Lighthouse.
Normalized URLs
SvelteKit redirects pathnames with trailing slashes to ones without (or vice versa depending on your configuration), as duplicate URLs are bad for SEO.
Manual setup
<title> and <meta>
Every page should have well-written and unique <title>
and <meta name="description">
elements inside a <svelte:head>
. Guidance on how to write descriptive titles and descriptions, along with other suggestions on making content understandable by search engines, can be found on Google's Lighthouse SEO audits documentation.
A common pattern is to return SEO-related
stuff
from pageload
functions, then use it (as$page.stuff
) in a<svelte:head>
in your root layout.
Structured data
Structured data helps search engines understand the content of a page. If you're using structured data alongside svelte-preprocess
, you will need to explicitly preserve ld+json
data (this may change in future):
/// file: svelte.config.js
// @filename: ambient.d.ts
declare module 'svelte-preprocess';
// @filename: index.js
// ---cut---
import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: preprocess({
preserve: ['ld+json']
// ...
})
};
export default config;
Sitemaps
Sitemaps help search engines prioritize pages within your site, particularly when you have a large amount of content. You can create a sitemap dynamically using an endpoint:
/// file: src/routes/sitemap.xml.js
export async function GET() {
return {
headers: {
'Content-Type': 'application/xml'
},
body: `
<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="https://www.w3.org/1999/xhtml"
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"
>
<!-- <url> elements go here -->
</urlset>
`.trim()
};
}
AMP
An unfortunate reality of modern web development is that it is sometimes necessary to create an Accelerated Mobile Pages (AMP) version of your site. In SvelteKit this can be done by enforcing the following configuration options...
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// the combination of these options
// disables JavaScript
browser: {
hydrate: false,
router: false
},
// since <link rel="stylesheet"> isn't
// allowed, inline all styles
inlineStyleThreshold: Infinity
}
};
export default config;
...and transforming the HTML using transformPage
along with transform
imported from @sveltejs/amp
:
import * as amp from '@sveltejs/amp';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
return resolve(event, {
transformPage: ({ html }) => amp.transform(html)
});
}
It's a good idea to use the
handle
hook to validate the transformed HTML usingamphtml-validator
, but only if you're prerendering pages since it's very slow.
Asset handling permalink
Importing
Vite will automatically process imported assets for improved performance. Hashes will be added to the filenames so that they can be cached and assets smaller than assetsInlineLimit
will be inlined.
<script>
import logo from '$lib/assets/logo.png';
</script>
<img alt="The project logo" src={logo} />
If you prefer to reference assets directly in the markup, you can use a preprocessor such as svelte-preprocess-import-assets or svelte-image.
For assets included via the CSS url()
function, you may find the experimental.useVitePreprocess
option useful:
// svelte.config.js
export default {
experimental: {
useVitePreprocess: true
}
};
Optimization
You may wish to utilize compressed image formats such as .webp
or .avif
or responsive images that serve a different size based on your device's screen. For images that are included statically in your project you may use a preprocessor like svelte-image or a Vite plugin such as vite-imagetools.
Переход с Sapper permalink
SvelteKit является преемником Sapper и разделяет многие элементы своего дизайна.
Если у вас есть существующее приложение Sapper, которое вы планируете перенести на SvelteKit, вам нужно будет внести ряд изменений. Возможно, вам будет полезно просмотреть некоторые примеры во время миграции.
package.json
type: "module"
Добавьте "type": "module"
в свой package.json
. Вы можете сделать этот шаг отдельно от остальных в рамках инкрементной миграции, если вы используете Sapper 0.29.3
Или новее.
dependencies
Удалите polka
или express
, если вы используете один из них, и любое промежуточное программное обеспечение, такое как sirv
или compression
.
devDependencies
Удалите sapper
из вашего devDependencies
и замените его на @sveltejs/kit
и любой адаптер, который вы планируете использовать (см. следующий раздел).
scripts
Любые скрипты, которые ссылаются на sapper
, должны быть обновлены:
sapper build
должен стать [svelte-kit build
](-sapper export
должен статьsvelte-kit build
с помощью статического адаптера
) с помощью узла адаптер
sapper export
должен статьsvelte-kit build
с помощью статического адаптераsapper dev
должен статьsvelte-kit dev
node __sapper__/build
должен статьnode build
Файлы проекта
Основная часть вашего приложения в src/routes
может быть оставлена там, где оно находится, но несколько файлов проекта необходимо будет переместить или обновить.
Конфигурация
Ваш webpack.config.js
или rollup.config.js
следует заменить на svelte.config.js
, как описано здесь. Параметры препроцессора Svelte следует переместить в config.preprocess
.
Вам нужно будет добавить адаптер. sapper build
примерно эквивалентен adapter-node, в то время как sapper export
примерно эквивалентен adapter-static, хотя вы можете предпочесть использовать адаптер, предназначенный для платформы, на которую развертываете.
Если вы использовали плагины для типов файлов, которые не обрабатываются автоматически Vite, вам нужно будет найти эквиваленты Vite и добавить их в Vite config.
src/client.js
Этот файл не имеет эквивалента в SvelteKit. Любая пользовательская логика (помимо sapper.start(...)
) должна быть выражена в файле __layout.svelte
внутри обратного вызова onMount
.
src/server.js
При использовании adapter-node
эквивалентом является пользовательский сервер. В противном случае этот файл не имеет прямого эквивалента, так как приложения SvelteKit могут работать в бессерверных средах. Тем не менее, вы можете использовать хуки для реализации логики сеанса.
src/service-worker.js
Большинство импортов из @sapper/service-worker
имеют эквиваленты в $service-worker
:
файлы
не изменилисьroutes
был удаленshell
теперьbuild
timestamp
теперьversion
src/template.html
Файл src/template.html
должен быть переименован в src/app.html
.
Удалите %sapper.base%
, %sapper.scripts%
и %sapper.styles%
. Замените %sapper.head%
на %sveltekit.head%
и %sapper.html%
на %sveltekit.body%
. <div id="sapper">
больше не нужен.
src/node_modules
Распространенным шаблоном в приложениях Sapper является размещение внутренней библиотеки в каталоге внутри src/node_modules
. Это не работает с Vite, поэтому вместо этого мы используем src/lib
.
Страницы и макеты
Переименованные файлы
Ваш пользовательский компонент страницы ошибок должен быть переименован с _error.svelte
в __error.svelte
. Любые файлы _layout.svelte
также должны быть переименованы в __layout.svelte
. Префикс двойного подчеркивания зарезервирован для SvelteKit; ваши собственные приватные модули по-прежнему обозначаются одним префиксом _
(настраивается через конфигурацию routes
).
Импорты
Импорт goto
, prefetch
и prefetchRoutes
из @sapper/app
должен быть заменен идентичным импортом из $app/navigation
.
Импорт stores
из @sapper/app
должен быть заменен — см. раздел Хранилища ниже.
Любые файлы, которые вы ранее импортировали из каталогов в src/node_modules
, необходимо будет заменить импортом $lib
.
Предзагрузка
Как и раньше, страницы и макеты могут экспортировать функцию, которая позволяет загружать данные до начала рендеринга.
Эта функция была переименована с preload
в load
, и ее API изменился. Вместо двух аргументов — «page» и «session» — есть один аргумент, который включает в себя оба, а также fetch
(который заменяет this.fetch
), так и новый объект stuff
.
Больше нет объекта this
, и, следовательно, нет this.fetch
, this.error
или this.redirect
. Вместо того, чтобы возвращать реквизит напрямую, load
теперь возвращает объект, который содержит props
, наряду с различными другими вещами.
Наконец, если на вашей странице есть метод «load», обязательно верните что-то, иначе вы получите «Не найдено».
Хранилища
В Sapper вы получите ссылки на предоставленные магазины следующим образом:
// @filename: ambient.d.ts
declare module '@sapper/app';
// @filename: index.js
// ---cut---
import { stores } from '@sapper/app';
const { preloading, page, session } = stores();
Хранилища page
и session
все еще существуют; preloading
было заменено хранилищем navigating
, которое содержит свойства from
и to
. page
теперь имеет свойства url
и params
, но не имеет path
или query
.
Вы получаете к ним доступ по-разному в SvelteKit. stores
теперь getStores
, но в большинстве случаев это не нужно, так как вы можете импортировать navigating
, page
и session
непосредственно из $app/stores
.
Маршрутизация
Маршруты Regex больше не поддерживаются. Вместо этого используйте сопоставление маршрутов.
Сегменты
Ранее компоненты макета получал свойство segment
, указывающее на дочерний сегмент. Это было удалено; теперь можно использовать более гибкое значение $page.url.pathname
, чтобы получить сегмент.
URLs
В Sapper все относительные URL-адреса разрешались по базовому URL-адресу — обычно /
, если не использовалась опция basepath
, а не по отношению к текущей странице.
Это вызвало проблемы и в SvelteKit относительные URL-адреса разрешаются для текущей страницы (или целевой страницы для URL-адресов fetch
в функциях load
). В большинстве случаев проще использовать URL-адреса относительно корня (т.е. начинается с /
), так как их значение не зависит от контекста.
Атрибуты ссылок
sapper:prefetch
теперьsveltekit:prefetch
sapper:noscroll
теперьsveltekit:noscroll
Эндпоинты
В Sapper «маршруты сервера», теперь называемые эндпоинтами, получили объекты req
и res
, предоставляемые модулем Node http
(или дополненными версиями, предоставляемыми такими фреймворками, как Polka и Express).
SvelteKit разработан так, чтобы быть независимым в отношении того, где работает приложение - оно может работать на сервере Node, но в равной степени может работать на бессерверной платформе или в Cloudflare Worker. По этой причине вы больше не взаимодействуете напрямую с req
и res
. Ваши конечные точки должны быть обновлены в соответствии с новой подписью.
Для поддержки этого поведения, независимого от среды, fetch
теперь доступен в глобальном контексте, поэтому вам не нужно импортировать node-fetch
, cross-fetch
или аналогичные реализации выборки на стороне сервера, чтобы использовать его.
Интеграции
Подробную информацию об интеграциях см. в разделе FAQ.
HTML minifier
Sapper по умолчанию включает html-minifier
. SvelteKit не включает это, но его можно добавить в качестве хука:
// @filename: ambient.d.ts
/// <reference types="@sveltejs/kit" />
declare module 'html-minifier';
// @filename: index.js
// ---cut---
import { minify } from 'html-minifier';
import { prerendering } from '$app/env';
const minification_options = {
collapseBooleanAttributes: true,
collapseWhitespace: true,
conservativeCollapse: true,
decodeEntities: true,
html5: true,
ignoreCustomComments: [/^#/],
minifyCSS: true,
minifyJS: false,
removeAttributeQuotes: true,
removeComments: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true
};
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event);
if (prerendering && response.headers.get('content-type') === 'text/html') {
return new Response(minify(await response.text(), minification_options), {
status: response.status,
headers: response.headers
});
}
return response;
}
Обратите внимание, что prerendering
имеет значение false
при использовании svelte-kit preview
для тестирования производственной сборки сайта, поэтому для проверки результатов минимизирования вам нужно будет напрямую проверить собранные HTML-файлы.
Дополнительные ресурсы permalink
FAQ
Прочтите SvelteKit FAQ, чтобы найти решения типичных проблем, а также полезные советы и рекомендации.
Svelte FAQ и vite-plugin-svelte
FAQ также могут быть полезны для вопросов, касающихся этих библиотек.
Примеры
Мы написали и опубликовали несколько различных сайтов на Sveltekit в качестве примеров:
sveltejs/realworld
пример блога- директория
sites/kit.svelte.dev
содержит код этого сайта sveltejs/sites
содержит код svelte.dev и клона HackerNews
Пользователи SvelteKit также опубликовали множество примеров на GitHub с тегами #sveltekit и #sveltekit-template, а также на сайте Svelte Society. Имейте ввиду, что некоторые из этих сайтов могут быть уже устаревшими
Интеграции
svelte-preprocess
автоматически преобразует код в шаблонах Svelte, чтобы обеспечить поддержку TypeScript, PostCSS, Scss/Sass, Less и многих других подобных технологий (кроме CoffeeScript, который не поддерживается SvelteKit). Первым шагом настройки является добавление svelte-preprocess
в svelte.config.js
. Этот файл уже существует в TypeScript шаблоне, а если используется шаблон JavaScript, нужно будет создать его. После этого обычно нужно только установить соответствующую библиотеку, например npm install -D sass
или npm install -D less
. Дополнительную информацию ищите в документации svelte-preprocess
.
Дополнения Svelte позволяют настроить множество различных сложных интеграций, таких как Tailwind, PostCSS, Firebase, GraphQL, mdsvex и многое другое, с помощью одной команды. Полный список шаблонов, компонентов и инструментов, доступных для использования со Svelte и SvelteKit, ищите на сайте sveltesociety.dev.
В SvelteKit FAQ также есть раздел об интеграции, который может быть полезен, если вы столкнетесь с какими-либо проблемами.
Поддержка
Вы можете обратиться за помощью в русскоязычный канал Telegram, Discord и StackOverflow. Пожалуйста, сначала поищите информацию, касающуюся вашей проблемы, в FAQ, Google или другой поисковой системе, в Issue на GitHub и историях чатов, чтобы не отнимать время у других. Это поможет сообществу развиваться быстрее, потому, что людей, задающих вопросы, гораздо больше, чем отвечающих на них.
Термины permalink
Ядро SvelteKit обеспечивает полностью настраиваемый механизм отрисовки. В этом разделе описаны некоторые термины, используемые при обсуждении отрисовки. Описание настроек этих опций ищете в документации выше.
SSR
Отрисовка на стороне сервера (SSR) - это генерация содержимого страницы на сервере. SSR, как правило, предпочтительнее для SEO. Хотя некоторые поисковые системы могут индексировать контент, который динамически генерируется на стороне клиента, но даже в этих случаях понадобится больше времени для индексации. Кроме того отрисовка на сервере улучшать производительность и делает приложение доступным для пользователей, если у них не работает или отключен JavaScript(что происходит чаще, чем вы, вероятно, думаете).
CSR и SPA
Отрисовка на стороне клиента (CSR) - это генерация содержимого страницы в веб-браузере с использованием JavaScript. Одностраничное приложение (SPA) - это приложение, в котором все запросы к серверу загружают единственный HTML-файл, который затем выполняет отрисовку запрошенного содержимого на основе текущего URL-адреса. Все переходы между страниц обрабатываются на стороне клиента в процессе, называемом маршрутизацией на стороне клиента, при этом обновляется содержимое каждой страницы, а общие элементы макета остаются на месте. SPA не могут предоставить преимуществ SSR, описанных выше. Однако на некоторых приложениях не сильно сказывается отсутствие этих преимуществ, например для сложного бизнес-приложения с авторизацией, где SEO не будет иметь никакого значения и известно, что пользователи будут получать доступ к приложению из известного окружения.
Предварительная отрисовка
Предварительная отрисовка означает вычисление содержимого страницы во время сборки и сохранение в HTML-файл для последующего показа пользователю. Этот подход имеет те же преимущества, что и традиционные страницы, отрисованные на сервере, но позволяет избежать перевысчисления содержимого страницы для каждого посетителя и поэтому, по мере увеличения количества посетителей, масштабируются почти бесплатно. Компромис заключается в том, что процесс сборки является более дорогим, а предварительно отрисованный контент может быть обновлен только путем создания и развертывания новой версии приложения.
Не все страницы могут быть предварительно отрисованы. Основное правило заключается в следующем: чтобы страница могла быть предварительно отрисована, любые два пользователя, заходящих на эту страницу, должны получить один и тот же контент с сервера. Обратите внимание, что всё ещё можно предварительно отрисовать содержимое, загруженное на основе параметров страницы, если все пользователи будут видеть одно и то же содержимое.
Предварительно отрисованные страницы не ограничиваются статическим контентом. Вы можете создавать персонализированные страницы, если пользовательские данные извлекаются и визуализируются на стороне клиента. Следует упомянуть, что в этом случае такой контент не будет иметь преимуществ SSR, описанных выше.
SSG
Статическая генерация сайтов (SSG) - это термин, который относится к сайту, где каждая страница предварительно отрисована. Это то, что делает adapter-static
для SvelteKit. SvelteKit, в отличие от специализированных инструментов, был создан не только для генерации статических сайтов, и поэтому может терять производительность при отрисовке очень большого количества страниц. Однако, в отличие от большинства SSG инструментов, SvelteKit прекрасно позволяет смешивать различные типы отрисовки на разных страницах приложения. Одним из преимуществ полной предварительной отрисовки сайта является то, что не придётся платить за серверы для выполнения SSR и обслуживать их. После создания сайт может загружаться с обычного хостинга или из CDN, что приводит к отличной метрике "время до первого байта". Такой метод развертывания сайта ещё называют JAMstack.
Гидратация
Компоненты Svelte хранят некоторое состояние и обновляют DOM при обновлении этого состояния. При получении данных во время SSR по умолчанию SvelteKit будет сохранять эти данные и передавать их клиенту вместе с серверным HTML кодом. Затем компоненты могут быть инициализированы на клиенте с этими данными без повторного вызова эндпоинтов API. Далее Svelte проверит, находится ли DOM в ожидаемом состоянии, и присоединит к нужным элементам слушателей событий. Весь этот процесс называется гидратацией. После того, как компоненты полностью гидратированы, они могут реагировать на изменения своих свойств так же, как и любой недавно созданный компонент Svelte.
Маршрутизация
По умолчанию при переходе на новую страницу (нажав на ссылку или используя кнопки истории браузера) SvelteKit перехватит это событие и обработает его вместо того, чтобы позволить браузеру отправить запрос следующей страницы на сервер. Затем SvelteKit обновит текущий контент страницы, отрисовав содержимое для новой страницы, при этом могут быть получены необходимые данные из API. Этот процесс обновления страницы на клиенте в ответ на попытку перехода называется маршрутизацией на стороне клиента.