Пре-рендеринг (pre-rendering) в контексте Vite представляет собой процесс генерации статических HTML-страниц на этапе сборки приложения. В отличие от классического SSR, где HTML формируется на каждый запрос, или CSR, где страница собирается полностью в браузере, здесь результат фиксируется заранее и отдаётся как готовая статическая разметка.
Основная цель такого подхода — снизить нагрузку на сервер, ускорить первичную отрисовку и улучшить SEO без необходимости поддерживать полноценный серверный рендеринг в runtime.
Статическая генерация в Vite опирается на идею выполнения рендеринга приложения в Node.js окружении во время build-фазы. В этот момент приложение:
Фактически происходит «симуляция браузера» на этапе сборки, где приложение проходит те же шаги инициализации, что и при SSR, но без реального HTTP-запроса.
Ключевым результатом становится набор файлов:
dist/
index.html
about/index.html
products/item-1/index.html
При чистом CSR:
Недостаток — медленный first contentful paint и слабая SEO-оптимизация.
При SSR:
Проблема — высокая стоимость и сложность масштабирования.
При pre-rendering:
Это делает подход близким к JAMstack архитектуре.
Vite сам по себе не является полноценным SSG-инструментом, но предоставляет инфраструктуру:
На базе этого строятся решения:
Процесс генерации статических страниц обычно включает следующие этапы.
Vite выполняет стандартный build:
Результат используется как клиентская часть для гидратации.
Для pre-rendering требуется отдельная точка входа:
// entry-server.js
import { createApp } from './app'
export async function render(url) {
const { app, router } = createApp()
router.push(url)
await router.isReady()
return {
html: await renderToString(app)
}
}
Эта функция позволяет отрисовать приложение в Node.js среде.
Pre-rendering требует заранее известного набора страниц.
Варианты получения маршрутов:
Пример:
const routes = [
'/',
'/about',
'/products/1'
]
Каждый маршрут проходит цикл:
for (const url of routes) {
const { html } = await render(url)
writeFile(`${outDir}${url}/index.html`, html)
}
Для корректной гидратации клиент должен получить состояние, использованное при SSR:
<script>
window.__INITIAL_STATE__ = {...}
</script>
Это позволяет избежать повторного запроса данных на клиенте.
Vite предоставляет нативный SSR API, который используется как основа для pre-rendering:
import { createServer } from 'vite'
const vite = await createServer({
server: { middlewareMode: true }
})
const { render } = await vite.ssrLoadModule('/src/entry-server.js')
Этот механизм позволяет:
Наиболее сложная часть pre-rendering — динамические страницы.
/products/1
/products/2
/products/3
Генерируются через API или mock данные.
const products = await fetchProducts()
const routes = products.map(p => `/products/${p.id}`)
/products/:id
/blog/:slug
Во время pre-rendering такие маршруты разворачиваются в конкретные URL.
Pre-rendering требует строгого контроля асинхронных зависимостей.
export async function render(url) {
const data = await fetchData(url)
return renderToString(app(data))
}
Данные сериализуются в HTML:
window.__DATA__ = {...}
Данные загружаются один раз при сборке:
Часто используется vite-plugin-ssg:
Используется комбинация:
Поддерживает compile-time рендеринг:
Типичный результат:
dist/
assets/
index.html
about/
index.html
blog/
post-1/
index.html
Каждая страница уже содержит:
После загрузки страницы происходит:
hydrateRoot(document.getElementById('app'), App)
Ключевая проблема — совпадение серверного и клиентского HTML. Несовпадение приводит к полной перерисовке.
Pre-rendering улучшает:
HTML уже содержит контент, поэтому поисковые роботы получают готовую страницу.
Страница фиксируется на момент build.
При большом количестве маршрутов build может быть медленным.
Без регенерации контент не обновляется.
Все зависимости должны быть предсказуемыми.
Для ускорения сборки применяются:
На практике часто используется гибрид:
Vite позволяет объединять эти модели через SSR API и плагинную систему.
Типичная структура:
src/
entry-client.js
entry-server.js
router/
pages/
scripts/
prerender.js
vite.config.js
Скрипт prerender выполняет основную работу генерации и вызывается после build.
Частые ошибки:
Решение — изоляция побочных эффектов и явная сериализация состояния.
Через плагины можно:
export default {
name: 'prerender-plugin',
closeBundle: async () => {
await generateStaticPages()
}
}
Это позволяет интегрировать SSG прямо в build pipeline Vite без внешних инструментов.