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

2023-09-28 15:18 更新

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

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

setup() 外部使用 store

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

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


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


router.beforeEach((to) => {
  // ?這會(huì)正常工作,因?yàn)樗_保了正確的 store 被用于
  // 當(dāng)前正在運(yùn)行的應(yīng)用
  const main = useMainStore(pinia)


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

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

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

State 激活

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

import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// 檢索服務(wù)端的 rootState
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)


// 渲染頁面后,rootState 被建立,
// 可以直接在 `pinia.state.value`上讀取。


// 序列化,轉(zhuǎn)義(如果 state 的內(nèi)容可以被用戶改變,這點(diǎn)就非常重要,幾乎都是這樣的)
// 并將其放置在頁面的某處
// 例如,作為一個(gè)全局變量。
devalue(pinia.state.value)

根據(jù)你服務(wù)端所渲染的內(nèi)容,你將設(shè)置一個(gè)初始狀態(tài)變量,該變量將在 HTML 中被序列化。你還應(yīng)該保護(hù)自己免受 XSS 攻擊。例如,在 vite-ssr中你可以使用transformState 選項(xiàng) 以及 @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) {
      // 序列化并設(shè)置為 window.__INITIAL_STATE__
      initialState.pinia = pinia.state.value
    } else {
      // 在客戶端,我們恢復(fù) state
      pinia.state.value = initialState.pinia
    }
  }
)

你可以根據(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 全局訪問它,我們可以這樣寫:

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


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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)