Skip to content

初始状态(Initial State) ​

初始状态(initial state)包含的数据会与你服务端生成的 HTML 一起被序列化,并在浏览器访问时进行水合(hydration)。这些数据可以是从 CDN、API 等获取的数据,通常是应用启动或首次被访问时立即需要用到的。

设置应用初始状态的主要好处在于:静态生成的页面不需要重新获取数据,因为这些数据在构建时就已经被获取并序列化进了页面的 HTML 中。

初始状态是一个普通的 JavaScript 对象,可以在 SSR 期间设置。也就是说,在像这样静态生成页面的时候:

ts
// src/main.ts

// ...

export const createApp = ViteSSG(
  App,
  { routes },
  ({ app, router, routes, isClient, initialState }) => {
    // ...

    if (import.meta.env.SSR) {
      // 在服务端设置初始状态
      initialState.data = { cats: 2, dogs: 3 }
    }
    else {
      // 在浏览器客户端恢复或读取初始状态
      console.log(initialState.data) // => { cats: 2, dogs: 3 }
    }

    // ...
  },
)

通常,你会把它和应用程序的状态存储(store)一起使用,比如Vuex或Pinia。

当使用pinia时

按照 Pinia's guide的指南,你需要把你的 main.{ts,js} 文件改成这样:

ts
import { createPinia } from 'pinia'
import routes from 'virtual:generated-pages'
// main.ts
import { ViteSSG } from 'vite-ssg'

import App from './App.vue'
// 使用你已配置的、在启动时需要取数据的任意 store
import { useRootStore } from './store/root'

export const createApp = ViteSSG(
  App,
  { routes },
  ({ app, router, initialState }) => {
    const pinia = createPinia()
    app.use(pinia)

    if (import.meta.env.SSR)
      initialState.pinia = pinia.state.value
    else
      pinia.state.value = initialState.pinia || {}

    router.beforeEach((to, from, next) => {
      const store = useRootStore(pinia)
      if (!store.ready)
        // 执行用户实现的 store action,以填充 store 的状态
        store.initialize()
      next()
    })
  },
)
当使用VueX时

关于如何在单页应用(single page app)中使用带有初始状态的 store,示例请参见单页应用示例the single page example。

状态序列化 ​

默认情况下,状态的序列化和反序列化分别使用JSON.stringify和JSON.parse。 如果这种方式对你有用,那你完全应该坚持使用它,因为它的性能要好得多。

你可以使用ViteSSGClientOptions选项对象中的transformState选项,如下所示。 除了JSON.stringify和JSON.parse之外,一个可行的方案是 @nuxt/devalue (Nuxt.js 就使用了它):

ts
import devalue from '@nuxt/devalue'
import { ViteSSG } from 'vite-ssg'

// ...
import App from './App.vue'

export const createApp = ViteSSG(
  App,
  { routes },
  ({ app, router, initialState }) => {
    // ...
  },
  {
    transformState(state) {
      return import.meta.env.SSR ? devalue(state) : state
    },
  },
)

使用 @nuxt/devalue 时的一点小提示: 如果你因为 @nuxt/devalue 包内部的 require 而遇到报错,你需要在 Vite 配置中加入下面这段配置:

ts
// vite.config.ts
// ...

export default defineConfig({
  resolve: {
    alias: {
      '@nuxt/devalue': '@nuxt/devalue/dist/devalue.js',
    },
  },
  // ...
})

异步组件 ​

某些应用可能会使用Vue特性,这些特性会导致组件异步渲染(例如suspense)。当这些特性以可能影响initialState的方式使用时,可以使用onSSRAppRendered来确保在初始应用渲染期间所有异步操作都已完成。

ts
const { app, router, initialState, isClient, onSSRAppRendered } = ctx

const pinia = createPinia()
app.use(pinia)

if (import.meta.env.SSR) {
  onSSRAppRendered(() => {
    initialState.pinia = pinia.state.value
  })
}
else {
  pinia.state.value = (initialState.pinia) || {}
}

vite-ssg 中文文档,基于 VitePress 构建