@application-kit/vue-ssr

SSR приложения на Vue.js: рендер страницы со снимком Pinia и повтором на 500, гидрация клиента в одном порядке и кодек снимка
328
Install
npm install @application-kit/vue-ssr
Latest Version:0.1.0
Vue:3
License:MIT
Last Updated:Oct 18, 2026
Links: GitLab  ·  npm
Maintainer: uwl

@application-kit/vue-ssr

SSR приложения на Vue.js поверх @libs-for-dev/vue-modular-application: рендер страницы на сервере со снимком Pinia и повторным проходом на 500, гидрация клиента в одном порядке и кодек снимка. Пакет не знает корневого компонента продукта, его локалей, фичефлагов и ключей window.*: всё это приходит параметрами.

Установка

yarn add @application-kit/vue-ssr

Peer-зависимости: vue, vue-router, pinia, devalue, @libs-for-dev/vue-modular-application — экземпляр у приложения один.

Входы

Вход Для чего Тянет
@application-kit/vue-ssr изоморфно: гидрация клиента, снимок Pinia, чтение window.*, тип контекста рендера devalue (типы vue, pinia)
@application-kit/vue-ssr/server сервер: SSR-энтри для рендерера страницы vue/server-renderer, vue-router, vue-modular-application
@application-kit/vue-ssr/testing спеки потребителя: снимок сторов через провод страницы devalue

Импорт любого входа не имеет побочных эффектов и не требует окружения. Nest пакету не нужен: Nest-провайдером энтри делает потребитель — зависимости context builder'а (порты, реестр модулей, логгер) знает только он.

Сервер

createSsrEntry(options) — энтри с render(url, initialState), страница которого совпадает по форме с SsrPageInterface пакета @application-kit/nestjs-vite. На каждый запрос — свежее приложение (VueApplication с memory history), навигация на url, renderToString с контекстом; ошибка приложения переключает pageType на 500, пишется в лог, и дерево рендерится вторым проходом — уже страницей ошибки.

  • rootComponent, moduleRegistry — корневой компонент и реестр модулей продукта.
  • buildContext(app, initialState) — контекст рендера (расширение SsrRenderContextInterface { pageType }). Вызывается до рендера: локаль, provide флагов и всё, что разметка должна увидеть, ставится приложению здесь.
  • describePage(context) — lang и значения window.* из того же контекста, которым рендерилась разметка.
  • stateKey — ключ window.* для снимка Pinia; logger — структурный { error(error, message) }, подходит PinoLogger.
@Injectable()
export class EntrySsr implements SsrEntryInterface {
  private readonly entry: VueSsrEntryInterface<VueSsrInitialState>

  public constructor(moduleRegistry: ModuleRegistry<RouteRecordRaw[], MenuItem[]>, logger: ApplicationLogger) {
    this.entry = createSsrEntry({
      buildContext: (app, { locale }) => {
        setLocale(app, locale)

        return { locale, pageType: HttpStatus.OK }
      },
      describePage: (context) => ({ lang: context.locale, state: { ssrLocale: context.locale } }),
      logger,
      moduleRegistry,
      rootComponent: Application,
      stateKey: 'ssrState',
    })
  }

  public async render(url: string, initialState: VueSsrInitialState): Promise<SsrPageInterface> {
    return this.entry.render(url, initialState)
  }
}

Клиент

hydrateSsrApplication(app, { stateKey, beforeMount, container }) — подъём приложения на разметке сервера. Порядок — контракт: снимок Pinia восстанавливается до первой навигации (гварды маршрутов видят состояние сервера и не запрашивают его заново), beforeMount — после router.isReady() и до mount (локаль и флаги первого кадра совпадают с сервером), затем mount(container).

await hydrateSsrApplication(app, {
  beforeMount: (application) => {
    const locale = readSsrValue('ssrLocale')

    if (isSupportedLocale(locale)) {
      setLocale(application, locale)
    }
  },
  container: '#app',
  stateKey: 'ssrState',
})
  • restoreSsrState(app, key) — снимок под ключом key в Pinia приложения; ключа нет — сторы не трогаются.
  • readSsrValue(key) — строка, которую рендерер положил в window[key]; иначе undefined.
  • serializeSsrState(state), parseSsrState(serialized) — кодек снимка на devalue: Date, Map, Set, undefined и повторные ссылки переживают провод, в отличие от JSON.

Pinia и роутер должны быть установлены в приложение до гидрации (плагином модуля).

Тесты потребителя

roundTripSsrState(state) — снимок сторов через тот же провод, что между энтри: строка на сервере → разбор на клиенте. Спека гидрации, которая переносит экземпляр стора, а не строку, пропускает состояние, не попавшее в снимок.

pinia.state.value = roundTripSsrState(serverPinia.state.value)

Related Packages

lazy-hydration

Lazy Hydration for Vue SSR

6,488 139
nuxt-lazy-hydration

Lazy hydration of server-side rendered Vue.js components

2,795
vue-lazy-hydration

Lazy Hydration of Server-Side Rendered Vue.js Components

771,759 1,187
vue3-lazy-hydration

Lazy Hydration for Vue 3 SSR

689,047 161
nuxt-lazy-hydrate

This module is a wrapper around Vue 3 Lazy Hydration Plugin for Nuxt 3.

331,369 108

Version History

Version Released Vue License
0.1.0 ^3.5.0 MIT
Pre-releases (1)
Version Released License
0.0.0-stage