服务端渲染 (SSR)

提示

如果您使用的是 Nuxt.js, 您需要改为阅读 这些说明

只要您在 setup 函数、gettersactions 的顶部调用 useStore() 函数,使用 Pinia 创建商店应该可以立即用于 SSR:

export default defineComponent({
  setup() {
    // 这是有效的,因为 pinia 知道里面运行的是什么应用程序
    // `setup()`
    const main = useMainStore()
    return { main }
  },
})

setup() 之外使用存储

如果您需要在其他地方使用商店,则需要将 pinia 实例 已传递给应用程序 传递给 useStore() 函数调用:

const pinia = createPinia()
const app = createApp(App)

app.use(router)
app.use(pinia)

router.beforeEach((to) => {
  // ✅ 这将确保正确的商店用于
  // 当前运行的应用
  const main = useMainStore(pinia)

  if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})

Pinia 可以方便地将自身作为 $pinia 添加到您的应用程序中,以便您可以在诸如 serverPrefetch() 之类的函数中使用它:

export default {
  serverPrefetch() {
    const store = useStore(this.$pinia)
  },
}

State hydration

为了 hydration 初始状态,您需要确保 rootState 包含在 HTML 中的某个位置,以便 Pinia 稍后获取它。 根据您用于 SSR 的内容,出于安全原因,您应该转义状态。 我们建议使用 Nuxt.js 使用的 @nuxt/devalue

import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// 检索 rootState 服务器端
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)

// 页面渲染完成后,根状态为build,可直接读取
// 在 `pinia.state.value` 上。
// 序列化,转义(如果状态的内容可以由用户更改,则非常重要)
// 并将其放置在某处页面,例如,作为全局变量。
devalue(pinia.state.value)

根据您用于 SSR 的内容,您将设置一个将在 HTML 中序列化的 initial state 变量。 您还应该保护自己免受 XSS 攻击。 例如,使用 vite-ssr 你可以使用 transformState 选项@nuxt/devalue

import devalue from '@nuxt/devalue'

export default viteSSR(
  App,
  {
    routes,
    transformState(state) {
      return import.meta.env.SSR ? devalue(state) : state
    },
  },
  ({ initialState }) => {
    // ...
    if (import.meta.env.SSR) {
      // 这将被字符串化并设置为 window.__INITIAL_STATE__
      initialState.pinia = pinia.state.value
    } else {
      // 在客户端,我们恢复状态
      pinia.state.value = initialState.pinia
    }
  }
)

您可以根据需要使用 其他替代方法@nuxt/devalue,例如 如果你可以使用 JSON.stringify()/JSON.parse() 序列化和解析你的状态,你可以大大提高你的性能

使此策略适应您的环境。 确保在客户端调用任何 useStore() 函数之前对 pinia 的状态进行 hydrate。 例如,如果我们将状态序列化为 <script> 标记,以便通过 window.__pinia 在客户端全局访问它,我们可以这样写:

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

// 必须由用户设置
if (isClient) {
  pinia.state.value = JSON.parse(window.__pinia)
}