Skip to content
目录导航

服务器端渲染 (SSR)

TIP

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

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

js
export default defineComponent({
  setup() {
    // 这是有效的,因为 pinia 知道什么应用程序在 `setup()` 中运行
    const main = useMainStore()
    return { main }
  },
})
1
2
3
4
5
6
7

setup() 之外使用Store

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

js
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'
})
1
2
3
4
5
6
7
8
9
10
11
12

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

js
export default {
  serverPrefetch() {
    const store = useStore(this.$pinia)
  },
}
1
2
3
4
5

状态补水(hydration)

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

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

// 渲染页面后,根状态被构建,可以直接在 `pinia.state.value` 上读取。

// 序列化、转义(如果状态的内容可以由用户更改,这非常重要,这几乎总是如此)
// 并将其放置在页面上的某个位置,例如,作为全局变量。

devalue(pinia.state.value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

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

js
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
    }
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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

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

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

// 必须由用户设置
if (isClient) {
  pinia.state.value = JSON.parse(window.__pinia)
}
1
2
3
4
5
6
7
8