初始状态(Initial State)
初始状态(initial state)包含的数据会与你服务端生成的 HTML 一起被序列化,并在浏览器访问时进行水合(hydration)。这些数据可以是从 CDN、API 等获取的数据,通常是应用启动或首次被访问时立即需要用到的。
设置应用初始状态的主要好处在于:静态生成的页面不需要重新获取数据,因为这些数据在构建时就已经被获取并序列化进了页面的 HTML 中。
初始状态是一个普通的 JavaScript 对象,可以在 SSR 期间设置。也就是说,在像这样静态生成页面的时候:
// 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} 文件改成这样:
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 就使用了它):
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 配置中加入下面这段配置:
// vite.config.ts
// ...
export default defineConfig({
resolve: {
alias: {
'@nuxt/devalue': '@nuxt/devalue/dist/devalue.js',
},
},
// ...
})异步组件
某些应用可能会使用Vue特性,这些特性会导致组件异步渲染(例如suspense)。当这些特性以可能影响initialState的方式使用时,可以使用onSSRAppRendered来确保在初始应用渲染期间所有异步操作都已完成。
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) || {}
}