Pinia 服務(wù)端渲染 Vue 與 Vite

2023-09-28 15:18 更新

只要你只在 setup 函數(shù)、getteraction 的頂部調(diào)用你定義的 useStore() 函數(shù),那么使用 Pinia 創(chuàng)建 store 對(duì)于 SSR 來說應(yīng)該是開箱即用的:

  1. <script setup>
  2. // 這是可行的,
  3. // 因?yàn)?pinia 知道在 `setup` 中運(yùn)行的是什么程序。
  4. const main = useMainStore()
  5. </script>

setup() 外部使用 store

如果你需要在其他地方使用 store,你需要將原本被傳遞給應(yīng)用pinia 實(shí)例傳遞給 useStore() 函數(shù):

  1. const pinia = createPinia()
  2. const app = createApp(App)
  3. app.use(router)
  4. app.use(pinia)
  5. router.beforeEach((to) => {
  6. // ?這會(huì)正常工作,因?yàn)樗_保了正確的 store 被用于
  7. // 當(dāng)前正在運(yùn)行的應(yīng)用
  8. const main = useMainStore(pinia)
  9. if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
  10. })

Pinia 會(huì)將自己作為 $pinia 添加到你的應(yīng)用中,所以你可以在 serverPrefetch() 等函數(shù)中使用它。

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

State 激活

為了激活初始 state,你需要確保 rootState 包含在 HTML 中的某個(gè)地方,以便 Pinia 稍后能夠接收到它。根據(jù)你服務(wù)端所渲染的內(nèi)容,為了安全你應(yīng)該轉(zhuǎn)義 state。我們推薦 Nuxt.js 目前使用的 @nuxt/devalue

  1. import devalue from '@nuxt/devalue'
  2. import { createPinia } from 'pinia'
  3. // 檢索服務(wù)端的 rootState
  4. const pinia = createPinia()
  5. const app = createApp(App)
  6. app.use(router)
  7. app.use(pinia)
  8. // 渲染頁面后,rootState 被建立,
  9. // 可以直接在 `pinia.state.value`上讀取。
  10. // 序列化,轉(zhuǎn)義(如果 state 的內(nèi)容可以被用戶改變,這點(diǎn)就非常重要,幾乎都是這樣的)
  11. // 并將其放置在頁面的某處
  12. // 例如,作為一個(gè)全局變量。
  13. devalue(pinia.state.value)

根據(jù)你服務(wù)端所渲染的內(nèi)容,你將設(shè)置一個(gè)初始狀態(tài)變量,該變量將在 HTML 中被序列化。你還應(yīng)該保護(hù)自己免受 XSS 攻擊。例如,在 vite-ssr中你可以使用transformState 選項(xiàng) 以及 @nuxt/devalue

  1. import devalue from '@nuxt/devalue'
  2. export default viteSSR(
  3. App,
  4. {
  5. routes,
  6. transformState(state) {
  7. return import.meta.env.SSR ? devalue(state) : state
  8. },
  9. },
  10. ({ initialState }) => {
  11. // ...
  12. if (import.meta.env.SSR) {
  13. // 序列化并設(shè)置為 window.__INITIAL_STATE__
  14. initialState.pinia = pinia.state.value
  15. } else {
  16. // 在客戶端,我們恢復(fù) state
  17. pinia.state.value = initialState.pinia
  18. }
  19. }
  20. )

你可以根據(jù)你的需要使用 @nuxt/devalue其他替代品,例如,你也可以用 JSON.stringify()/JSON.parse() 來序列化和解析你的 state,這樣你可以把性能提高很多。

也可以根據(jù)你的環(huán)境調(diào)整這個(gè)策略。但確保在客戶端調(diào)用任何 useStore() 函數(shù)之前,激活 pinia 的 state。例如,如果我們將 state 序列化為一個(gè) <script> 標(biāo)簽,并在客戶端通過 window.__pinia 全局訪問它,我們可以這樣寫:

  1. const pinia = createPinia()
  2. const app = createApp(App)
  3. app.use(pinia)
  4. // 必須由用戶設(shè)置
  5. if (isClient) {
  6. pinia.state.value = JSON.parse(window.__pinia)
  7. }
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)