По умолчанию SvelteKit будет рендерить (или пререндерить) любой компонент сначала на сервере и отправлять его на клиент в формате HTML. Затем он снова отрендерит компонент в браузере, чтобы сделать его интерактивным в процессе, называемом гидратация. По этой причине необходимо убедиться, что компоненты могут работать в обоих местах. Затем SvelteKit инициализирует маршрутизатор, который берет на себя последующую навигацию.
Вы можете управлять каждой из них в отдельности, экспортируя опции из +page.js
или +page.server.js
, или для групп страниц, используя общий +layout.js
или +layout.server.js
. Чтобы определить параметр для всего приложения, экспортируйте его из корневого макета. Дочерние макеты и страницы переопределяют значения, установленные в родительских макетах, поэтому, например, вы можете включить пререндеринг для всего приложения и отключить его для страниц, которые должны быть динамически отображены.
Вы можете смешивать и сочетать эти опции в различных областях вашего приложения. Например, вы можете сделать пререндер маркетинговой страницы для максимальной скорости, серверный рендеринг динамических страниц для SEO и доступности и перевести раздел администрирования в SPA, сделав его рендеринг только на клиенте. Это делает SvelteKit очень универсальным.
Вполне вероятно, что по крайней мере некоторые маршруты вашего приложения могут быть представлены в виде простого HTML-файла, создаваемого во время сборки. Эти маршруты могут быть пререндерены.
+page.js/+page.server.js/+server.js
export const prerender = true;
В качестве альтернативы, вы можете установить export const prerender = true
в вашем корне +layout.js
или +layout.server.js
и пререндерить все, кроме страниц, которые явно помечены как не пререндерируемые:
+page.js/+page.server.js/+server.js
export const prerender = false;
Маршруты с prerender = true
будут исключены из манифестов, используемых для динамического SSR, что сделает ваш сервер (или функции serverless/edge) меньше. В некоторых случаях вы можете захотеть пререндерить маршрут, но также включить его в манифест (например, маршрут типа /blog/[slug]
, где вы хотите пререндерить ваш самый свежий/популярный контент, но сервер рендерит длинный хвост) - для таких случаев есть третья опция, 'auto':
+page.js/+page.server.js/+server.js
export const prerender = 'auto';
Если все ваше приложение подходит для пререндеринга, вы можете использовать
adapter-static
, который выведет файлы, пригодные для использования с любым статическим веб-сервером.
Пререндер запускается в корне вашего приложения и генерирует файлы для всех страниц с возможностью пререндера или маршрутов +server.js
, которые он находит. Каждая страница сканируется на наличие элементов <a>
, указывающих на другие страницы, которые являются кандидатами на пререндеринг — поэтому обычно не нужно указывать, какие страницы должны быть доступны. Если вам необходимо указать, какие страницы должны быть доступны пререндеру, вы можете сделать это с помощью опции entries
в конфигурации prerender configuration.
При пререндеринге значение building
, импортированного из $app/environment
, будет равно true
.
В отличие от других опций страниц, prerender
также применяется к файлам +server.js
. Эти файлы не зависят от макетов, но наследуют значения по умолчанию от страниц, которые получают данные из них, если таковые имеются. Например, если +page.js
содержит такую функцию load
...
+page.js
export const prerender = true;
/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
const res = await fetch('/my-server-route.json');
return await res.json();
}
+page.ts
import type { PageLoad } from './$types';
export const prerender = true;
export const load = (async ({ fetch }) => {
const res = await fetch('/my-server-route.json');
return await res.json();
}) satisfies PageLoad;
...тогда src/routes/my-server-route.json/+server.js
будет рассматриваться как пререндерируемый, если он не содержит собственного export const prerender = false
.
Основное правило таково: чтобы страница была пререндерируемой, любые два пользователя, обратившиеся к ней напрямую, должны получить от сервера одинаковое содержимое.
Не все страницы подходят для предварительного рендеринга. Любое содержимое, которое отображается с помощью пререндера, будет видно всем пользователям. Конечно, вы можете получить персонализированные данные в
onMount
на странице с пререндерингом, но это может привести к ухудшению пользовательского опыта, поскольку будет включать пустой начальный контент или индикаторы загрузки.
Обратите внимание, что вы все еще можете пререндерить страницы, которые загружают данные на основе параметров страницы, например, маршрут src/routes/blog/[slug]/+page.svelte
.
Обращение к url.searchParams
во время пререндеринга запрещено. Если вам необходимо его использовать, убедитесь, что вы делаете это только в браузере (например, в onMount
).
Страницы с actions не могут быть пререндерены, поскольку сервер должен быть способен обрабатывать запросы POST
.
Если вы установите опцию ssr в false
, каждый запрос будет приводить к одной и той же пустой HTML-оболочке. Поскольку это приведет к ненужной работе, SvelteKit по умолчанию выполняет предпросмотр всех найденных страниц, для которых prerender
не установлен в явном виде в false
.
Поскольку пререндеринг записывает данные в файловую систему, невозможно иметь две конечные точки, в которых каталог и файл будут иметь одинаковое имя. Например, src/routes/foo/+server.js
и src/routes/foo/bar/+server.js
попытались бы создать foo
и foo/bar
, что невозможно.
По этой и другим причинам рекомендуется всегда указывать расширение файла — src/routes/foo.json/+server.js
и src/routes/foo/bar.json/+server.js
приведут к тому, что файлы foo.json
и foo/bar.json
будут гармонично жить рядом.
Для страниц мы обходим эту проблему, записывая foo/index.html
вместо foo
.
Обратите внимание, что это отключит маршрутизацию на стороне клиента для любой навигации с этой страницы, независимо от того, активен ли уже маршрутизатор.
Если вы столкнулись с ошибкой типа 'The following routes were marked as prerenderable, but were not prerendered' ("Следующие маршруты были отмечены как пригодные для пререндеринга, но не были пререндерены"), это связано с тем, что данный маршрут (или родительский макет, если это страница) имеет export const prerender = true
, но страница на самом деле не была пререндерена, потому что до нее не добрался обходчик пререндера.
Поскольку эти маршруты не могут быть динамически рендерены сервером, это приведет к ошибкам, когда люди попытаются получить доступ к рассматриваемому маршруту. Есть два способа исправить это:
- Убедитесь, что SvelteKit может найти маршрут по ссылкам из
config.kit.prerender.entries
. Добавьте ссылки на динамические маршруты (т.е. страницы с[параметрами]
) в эту опцию, если они не найдены при просмотре других точек входа, иначе они не пререндерятся, потому что SvelteKit не знает какое значение должны иметь параметры. Страницы, не помеченные как пререндеренные, будут игнорироваться, а их ссылки на другие страницы не будут просмотрены, даже если некоторые из них будут пререндеренными. - Замените
export const prerender = true
наexport const prerender = 'auto'
. Маршруты с'auto'
могут динамически рендериться сервером
Обычно SvelteKit сначала отображает вашу страницу на сервере и отправляет этот HTML на клиент, где он гидратируется. Если вы установите ssr
в false
, вместо этого будет отображаться пустая страница-"оболочка". Это полезно, если ваша страница не может быть отрисована на сервере (например, из-за использования глобальных файлов только для браузера, таких как document
), но в большинстве ситуаций это не рекомендуется (см. приложение).
+page.js
export const ssr = false;
Если вы добавите export const ssr = false
в корень +layout.js
, всё ваше приложение будет отображаться только на клиенте - что по сути означает превращение вашего приложения в SPA.
Обычно SvelteKit гидратирует ваш серверный HTML в интерактивную страницу с клиентским рендерингом (CSR). Некоторые страницы вообще не требуют JavaScript - многие сообщения в блогах и страницы "о себе" попадают в эту категорию. В этих случаях вы можете отключить CSR:
+page.js
export const csr = false;
Если
ssr
иcsr
равныfalse
, ничего не будет отображено!
По умолчанию SvelteKit удаляет косую черту из URL-адресов - если вы посетите сайт /about/
, он ответит перенаправлением на /about
. Вы можете изменить это поведение с помощью опции trailingSlash
, которая может быть одной из 'never'
(по умолчанию), 'always'
или 'ignore'
.
Как и другие параметры страницы, вы можете экспортировать это значение из файла +layout.js
или +layout.server.js
, и оно будет применяться ко всем дочерним страницам. Вы также можете экспортировать конфигурацию из файлов +server.js
.
src/routes/+layout.js
export const trailingSlash = 'always';
Этот параметр также влияет на prerendering. Если trailingSlash
имеет значение always
, маршрут типа /about
приведет к созданию файла about/index.html
, в противном случае будет создан about.html
, зеркально отражая статические соглашения веб-сервера.
Игнорировать косые черты не рекомендуется - семантика относительных путей отличается в двух случаях (
./y
из/x
- это/y
, а из/x/
- это/x/y
), и/x
и/x/
рассматриваются как отдельные URL, что вредит SEO.
Благодаря концепции адаптеров SvelteKit может работать на различных платформах. Каждая из них может иметь специфическую конфигурацию для дальнейшей настройки развертывания - например, на Vercel вы можете выбрать развертывание некоторых частей вашего приложения на границе, а других - в бессерверных средах.
config
- это объект с парами ключ-значение на верхнем уровне. После этого конкретная форма зависит от используемого адаптера. Каждый адаптер должен предоставлять интерфейс Config
для импорта в целях обеспечения безопасности типов. Для получения дополнительной информации обратитесь к документации вашего адаптера.
ambient.d.ts
declare module 'some-adapter' {
export interface Config { runtime: string }
}
src/routes/+page.js
/** @type {import('some-adapter').Config} */
export const config = {
runtime: 'edge'
};
ambient.d.ts
declare module 'some-adapter' {
export interface Config { runtime: string }
}
src/routes/+page.ts
import type { Config } from 'some-adapter';
export const config: Config = {
runtime: 'edge'
};
Объекты config
объединяются на верхнем уровне (но не на более глубоких уровнях). Это означает, что вам не нужно повторять все значения в +page.js
, если вы хотите переопределить только некоторые значения в верхнем +layout.js
. Например, эта конфигурация макета...
src/routes/+layout.js
export const config = {
runtime: 'edge',
regions: 'all',
foo: {
bar: true
}
}
...отменяется этой конфигурацией страницы...
src/routes/+page.js
export const config = {
regions: ['us1', 'us2'],
foo: {
baz: true
}
}
...что приводит к значению конфигурации { runtime: 'edge', regions: ['us1', 'us2'], foo: { baz: true } }
для этой страницы.