Svelte
Опции страницы: ssr, csr, prerender
Маркетинговый лендинг компании и личный кабинет с балансом живут в одном SvelteKit-приложении. Лендинг должен открываться мгновенно из CDN и индексироваться поисковиками, его контент не меняется неделями. Кабинет содержит приватные данные одного пользователя, и рендерить его на сервере в общий HTML опасно. SvelteKit позволяет задать разный режим рендеринга для каждого из этих маршрутов одной строкой экспорта, и это решение принимается прямо в файле маршрута.
- Документация Svelte (svelte.dev): статьи целиком пререндерятся в HTML и раздаются как статика, поиск работает на клиенте
- Vercel-дашборды: страницы настроек проекта рендерятся на сервере для скорости первого экрана, но приватные части идут как SPA
- Блоги на SvelteKit: список постов пререндерится при сборке, а форма комментариев отключает prerender и работает динамически
- Внутренние админ-панели: SSR часто выключают целиком (ssr=false), оставляя чистый SPA за авторизацией, где SEO не нужен
Предварительные знания
- Понимание разницы между SSR (рендеринг HTML на сервере) и CSR (рендеринг в браузере)
- Знание файловой маршрутизации SvelteKit: +page.svelte, +page.js, +layout.js
- Базовое представление о том, что такое prerendering и зачем нужна статика на CDN
Где живут опции страницы и как они каскадируются
SvelteKit читает четыре именованных экспорта из модулей маршрута: ssr, csr, prerender и trailingSlash. Они объявляются как обычные константы в +page.js, +page.server.js, +layout.js или +layout.server.js. Это не рантайм-код, а декларация: компилятор и адаптер используют эти значения при сборке и при обработке запроса, чтобы решить, какой HTML и какой JavaScript отправить браузеру.
Опция, заданная в +layout.js, действует как значение по умолчанию для всего поддерева маршрутов под этим макетом. Маршрут ниже может переопределить её собственным экспортом. Это даёт удобный приём: выставить prerender=true в корневом макете, а затем выключить его в тех немногих маршрутах, которым нужна динамика.
| Опция | Тип | Что контролирует |
|---|---|---|
| ssr | boolean | Рендерить ли HTML страницы на сервере |
| csr | boolean | Отправлять ли клиентский JavaScript для гидрации и навигации |
| prerender | boolean | 'auto' | Генерировать ли HTML на этапе сборки как статику |
| trailingSlash | 'never' | 'always' | 'ignore' | Как обрабатывать завершающий слеш в URL |
Опции читаются статически: SvelteKit парсит их при сборке, а не вычисляет в рантайме. Значение нельзя получить из условия или переменной окружения внутри выражения присваивания. Допустимо только литеральное значение или простое константное выражение.
Опция prerender=true задана в src/routes/+layout.js, а в src/routes/dashboard/+page.js стоит export const prerender = false. Что произойдёт с маршрутом /dashboard?
ssr и csr: четыре комбинации режима
Флаги ssr и csr независимы, и их сочетание задаёт четыре поведения. ssr=true, csr=true это значение по умолчанию: сервер отдаёт готовый HTML, браузер его гидрирует и дальше работает как SPA. ssr=false, csr=true даёт пустую оболочку с сервера и всю отрисовку в браузере, то есть классический SPA. ssr=true, csr=false отдаёт статический HTML без клиентского JS. Комбинация ssr=false, csr=false почти не имеет смысла, так как страница не отрендерится нигде.
| ssr | csr | Результат | Когда применять |
|---|---|---|---|
| true | true | SSR с гидрацией, дальше SPA | Дефолт: SEO и интерактив одновременно |
| false | true | Чистый клиентский SPA | Приватные экраны за логином, где SEO не нужен |
| true | false | Статический HTML без JS | Контентные страницы без интерактива |
| false | false | Ничего не рендерится | Практически не используется |
При ssr=false первый экран это пустая оболочка, пока не загрузится и не выполнится клиентский бандл. Это ухудшает метрику First Contentful Paint и делает страницу невидимой для поисковых роботов, которые не исполняют JavaScript. Выключать SSR стоит осознанно и только там, где SEO и скорость первого экрана не важны.
Выключение csr полезно, когда страница состоит из статичного контента: текст, изображения, ссылки. Без клиентского JavaScript бандл не грузится вообще, страница работает даже при отключённом JS, а навигация идёт обычными переходами браузера вместо клиентского роутера.
Разработчику нужно отдать страницу с условиями использования: длинный статичный текст, без форм и интерактива, но она должна индексироваться поисковиком. Какая комбинация опций подходит лучше всего?
prerender и trailingSlash: статика и форма URL
Опция prerender=true говорит SvelteKit сгенерировать HTML маршрута на этапе сборки, а не при каждом запросе. Результат это статический файл, который раздаётся с CDN без рантайма на сервере. Пререндер подходит для контента, одинакового для всех посетителей: документация, статьи блога, лендинги. Маршрут не должен зависеть от заголовков запроса, cookies или параметров сессии, потому что во время сборки этих данных не существует.
Чтобы пререндерить динамические маршруты вроде /blog/[slug], SvelteKit должен знать список всех значений slug. Он находит их, обходя ссылки со стартовых страниц, либо через явный список в опции prerender.entries конфигурации. Значение prerender='auto' пререндерит страницу, но при этом оставляет её доступной и для динамического рендеринга, что полезно при гибридных стратегиях.
Опция trailingSlash управляет тем, как нормализуется завершающий слеш в URL. Значение 'never' (по умолчанию) убирает слеш: /about/ редиректит на /about. Значение 'always' добавляет его. Эта настройка важна именно для пререндера, потому что определяет имя генерируемого файла: about.html против about/index.html, и рассогласование приводит к 404 на статическом хостинге.
| trailingSlash | /about запишется как | Поведение |
|---|---|---|
| 'never' | about.html | Слеш на конце убирается редиректом |
| 'always' | about/index.html | Слеш на конце добавляется редиректом |
| 'ignore' | зависит от запроса | Без нормализации, не рекомендуется с пререндером |
Если внутри load пререндерируемого маршрута читать cookies или request.headers, SvelteKit прервёт сборку с ошибкой. Это защита: данные, привязанные к конкретному пользователю, нельзя зашить в общий статический HTML, который получат все посетители.
Команда пытается пререндерить маршрут /account, а его load читает session-cookie, чтобы показать имя пользователя. Что произойдёт при сборке?
Связь с другими темами
Опции страницы это управляющий слой над механизмами рендеринга. Дальше они комбинируются с загрузкой данных:
- SSR и CSR — Опции ssr и csr напрямую переключают режимы, разобранные в предыдущем уроке
- Стриминг данных из load — Стриминг возможен только при ssr=true, поэтому опция ssr предшествует теме стриминга
- Load-функции — prerender накладывает ограничения на load: данные не должны зависеть от заголовков запроса
Итог
- Режим рендеринга задаётся на уровне маршрута через export const ssr, csr, prerender и trailingSlash в +page.js или +layout.js
- ssr=false убирает серверный HTML и превращает маршрут в чистый клиентский SPA, что подходит для приватных экранов без SEO
- csr=false убирает клиентский JavaScript и оставляет статический HTML, что годится для контента без интерактива
- prerender=true генерирует HTML на этапе сборки, и его можно раздавать как статику с CDN без рантайма на сервере
- Опции в +layout.js становятся значением по умолчанию для всех вложенных маршрутов, а +page.js переопределяет их точечно
Связанные уроки
- sv-25-ssr-csr — Опции страницы управляют именно теми режимами SSR и CSR, которые разбирались раньше. Без понимания самих режимов настройки бессмысленны
- sv-29-streaming — Стриминг данных работает только при включённом SSR, поэтому понимание опции ssr идёт прямо перед стримингом
- sv-19-load-functions — Опция prerender требует, чтобы load возвращал данные без зависимости от конкретного запроса, что меняет дизайн load-функций