服务器端渲染 (SSR)
提示
手动进行服务器端渲染可能会非常复杂,建议使用 Nuxt。阅读 Nuxt 指南,大多数内容已经为您配置好了。
使用 Vitesse 进行 SSR
在进行 SSR(服务器端渲染)时,您需要等待服务器上的数据进行序列化,并在客户端检索数据,然后在客户端显示数据。如果您在组件中使用可组合函数,VueFire 已经为您等待数据了。
<script setup>
import { doc, getDoc } from 'firebase/firestore'
import { useDocument, useFirestore } from 'vuefire'
const db = useFirestore()
// automatically waits for the data to be loaded on the server
const quizResults = useDocument(doc(db, 'quizzes', quizId))
</script>
您只需要将数据转义并序列化到客户端,并处理状态水合。这取决于您使用什么进行 SSR,但应该类似于使用 Vitesse 模板 的示例。
添加一个 src/modules/vuefire.ts
(或 .js
)文件
// src/modules/vuefire.ts
import { initializeApp } from 'firebase/app'
import { VueFire useSSRInitialState } from 'vuefire'
import type { UserModule } from '~/types'
export const install: UserModule = ({ isClient, initialState, app }) => {
const firebaseApp = initializeApp({
// your config
})
app.use(VueFire, { firebaseApp })
if (isClient) {
// reuse the initial state on the client
useSSRInitialState(initialState.vuefire, firebaseApp)
} else {
// on the server we ensure all the data is retrieved in this object
initialState.vuefire = useSSRInitialState(
// let `useSSRInitialState` create the initial object for us
undefined,
// this is necessary to work with concurrent requests
firebaseApp,
)
}
}
请注意,默认情况下,vite-ssg(由 Vitesse 使用)使用 JSON.stringify()
来序列化状态,这更快,但不支持一些值,例如 TimeStamp
和 GeoPoint
对象,并且如果您的数据来自用户,还会使您的应用程序容易受到一些攻击。您可以使用自定义 transformState
函数来处理这种情况。
// src/main.ts
// https://github.com/Rich-Harris/devalue#usage
import devalue from 'devalue'
import { ViteSSG } from 'vite-ssg'
import App from './App.vue'
import {
devalueCustomParsers,
devalueCustomStringifiers,
} from 'vuefire'
export const createApp = ViteSSG(
App,
{ routes },
({ app, router, initialState }) => {
// ...
},
{
transformState(state) {
return import.meta.env.SSR
? devalue.stringify(state, devalueCustomStringifiers)
: devalue.parse(state, devalueCustomParsers)
},
}
)
提示
这在 Nuxt 项目中的 nuxt-vuefire
插件 中开箱即用。
网络安全是一个广泛的主题,我们无法在这里涵盖。我们建议您阅读这些资源以深入了解。
手动 SSR 密钥
VueFire 会自动根据文档或集合的路径推断 SSR 密钥,只要有可能。这意味着在某些情况下,**您必须提供手动 ssrKey
**。
- 使用 Firestore 查询时
- 将同一个文档绑定多次时
在这些情况下,将 ssrKey
作为第二个参数提供给 useDocument()
、useCollection()
等。
useCollection(queryRef, { ssrKey: 'my-quiz' })
在组件之外使用
如果您在组件之外使用 VueFire 可组合函数,例如在 Pinia 商店中使用 useDocument()
,则需要手动等待服务器上的数据加载,因为 VueFire 无法为您调用 onServerPrefetch()
,您必须手动调用它。VueFire 公开了一个函数来检索由不同可组合函数(useDocument()
、useDatabaseObject()
等)创建的所有挂起承诺。您需要在**使用数据的任何组件**中使用它。
<script setup>
import { useQuizStore } from '~/stores/quiz'
import { usePendingPromises } from 'vuefire'
// this store internally calls `useDocument()` when created
const quizStore = useQuizStore()
// `useDocument()` has been called within `useQuizStore()` but this component isn't aware of it
onServerPrefetch(() => usePendingPromises())
</script>
虽然推荐的方法是使用 onServerPrefetch()
,但另一种可能性是 使用 <Suspense>
来能够在 setup()
中使用 await
。
<script setup>
import { useQuizStore } from '~/stores/quiz'
import { usePendingPromises } from 'vuefire'
// this store internally calls `useDocument()` when created
const quizStore = useQuizStore()
// since `useDocument()` has been called
await usePendingPromises()
</script>