• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • Pinia 与 服务器端渲染(SSR)

    在 SSR 服务端渲染模式下,使用 Pinia Store 应该是开箱即用的。只要您在组件setup()选项的顶层,直接调用 Pinia Store 的useStore()gettersactions

    export default defineComponent({
      setup() {
        // 在 setup() 中,它能运行,因为 pinia 知道,程序 app 实例已经运行
        const main = useMainStore()
        return { main }
      },
    })
    


    在 SSR 服务端渲染模式下,如果您需要在组件setup()外的其他地方,使用 Pinia,则需要把Pinia 实例,传递给useStore()

    const app = createApp(App)
    const pinia = createPinia()
    
    app.use(router)
    app.use(pinia)
    
    router.beforeEach((to) => {
      // ✅这会正常工作,因为它确保了正确的 store 被用于当前正在运行的应用 app 实例
      const main = useMainStore(pinia)
    
      if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
    })
    


    在 SSR 服务端渲染模式下,在组件选项serverPrefetch()生命周期钩子中,Pinia 方便地将自身$pinia,添加到您的应用程序中:

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


    客户端激活 state

    在服务端渲染的时候,需要为客户端提供 state 初始值,把它将在 HTML 中被序列化。出于安全,免受 XSS 攻击,也应该转义 state,可以使用JSON.stringify()JSON.parse(),转义解析 state,则可以大大提高安全。

    JSON.stringify(pinia.state.value)
    

    在客户端,调用任何useStore()函数之前,需要激活 Pinia 的 state,需要确保 state 包含在 HTML 中的某个位置,以便 Pinia 稍后获取它。例如,如果我们在<script>标签内,序列化 state,使其可以在客户端通过访问 window 对象的自定义属性,全局访问:

    // index.html
    <script>window.__pinia={key:value}</script>
    
    // client.ts
    const app = createApp(App);
    const router = createRouter();
    const pinia = createPinia();
    
    app.use(pinia);
    app.use(router);
    
    router.isReady().then(() => {
      if (window.__pinia) {
        pinia.state.value = JSON.parse(window.__pinia);
      }
      app.mount('#app');
    });
    


    在 nuxt.js 框架中,使用@nuxt/devalue转义该 state:

    import devalue from '@nuxt/devalue'
    import { createPinia } from 'pinia'
    // retrieve the rootState server side
    const pinia = createPinia()
    const app = createApp(App)
    app.use(router)
    app.use(pinia)
    
    // 渲染页面后,rootState 被建立,可以直接在 `pinia.state.value`上读取。
    // 序列化,转义(如果 state 的内容可以被用户改变,这点就非常重要,几乎都是这样的)并将其放置在页面的某处
    // 例如,作为一个全局变量
    devalue(pinia.state.value)
    

    在 vite-ssr 中,可以使用transformState选项转义:

    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) {
          // this will be stringified and set to window.__INITIAL_STATE__
          initialState.pinia = pinia.state.value
        } else {
          // on the client side, we restore the state
          pinia.state.value = initialState.pinia
        }
      }
    )