Renderizado del Lado del Servidor (SSR)
TIP
Si estás usando Nuxt.js, necesitas leer estas instrucciones en lugar de estas.
La creación de almacenes con Pinia debería funcionar de forma inmediata para SSR siempre y cuando llame a sus funciones useStore()
en la parte superior de las funciones setup
, getters
y acciones
:
<script setup>
// esto funciona porque pinia sabe que aplicación está ejecutándose
// dentro de `setup()`
const main = useMainStore()
</script>
<script setup>
// esto funciona porque pinia sabe que aplicación está ejecutándose
// dentro de `setup()`
const main = useMainStore()
</script>
Usar el almacén fuera de setup()
Si necesitas usar el almacén en algún otro lugar, necesitas pasar la instancia de pinia
que fue pasada a la aplicación a la llamada de la función useStore()
:
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
router.beforeEach((to) => {
// ✅ Esto funcionará si te aseguras que usas el almacén
// correcto en la aplicación que está siendo ejecutada
const main = useMainStore(pinia)
if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
router.beforeEach((to) => {
// ✅ Esto funcionará si te aseguras que usas el almacén
// correcto en la aplicación que está siendo ejecutada
const main = useMainStore(pinia)
if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})
Pinia se añadirá convenientemente como $pinia
a tu aplicación para que puedas usarla en funciones como serverPrefetch()
:
export default {
serverPrefetch() {
const store = useStore(this.$pinia)
},
}
export default {
serverPrefetch() {
const store = useStore(this.$pinia)
},
}
Nota: no necesitas hacer nada especial cuando usas onServerPrefetch()
:
<script setup>
const store = useStore()
onServerPrefetch(async () => {
// ✅ esto funcionará
await store.fetchData()
})
</script>
<script setup>
const store = useStore()
onServerPrefetch(async () => {
// ✅ esto funcionará
await store.fetchData()
})
</script>
Hidratación del Estado
Para hidratar en estado inicial, necesitas asegurarte que el estado raíz este incluido en algún lugar del HTML para que Pinia lo recoja más adelante. Dependiendo de para que uses SSR, deberás escapar el estado por razones de seguridad. Recomendamos usar @nuxt/devalue que es el usado por Nuxt.js:
import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// recupera el estado raíz del lado del servidor
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
// después de renderizar la página, el estado raíz es construido y puede ser
// leído directamente en `pinia.state.value`.
// serializa, escapa (MUY importante si el contenido del estado pude ser cambiado)
// por el usuario, que casi siempre es el caso), y ponlo en algún lugar de la
// página, por ejemplo, como una variable global.
devalue(pinia.state.value)
import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// recupera el estado raíz del lado del servidor
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
// después de renderizar la página, el estado raíz es construido y puede ser
// leído directamente en `pinia.state.value`.
// serializa, escapa (MUY importante si el contenido del estado pude ser cambiado)
// por el usuario, que casi siempre es el caso), y ponlo en algún lugar de la
// página, por ejemplo, como una variable global.
devalue(pinia.state.value)
Dependiendo de para que uses SSR, deberás poner una variable de estado inicial que será serializada en el HTML. También deberás protegerte contra ataques XSS. Puedes usar otras alternativas a @nuxt/devalue
dependiendo de lo que necesites, por ejemplo, si puedes serializar y parsear tu estado con JSON.stringify()
/JSON.parse()
, puedes mejorar mucho tu rendimiento.
Si no estás usando Nuxt, necesitarás manejar la serialización e hidratación del estado por ti mismo. Aquí tienes algunos ejemplos:
Adapta esta estrategia a tu entorno. Asegúrate de hidratar el estado de pinia antes de llamar a cualquier función useStore()
en el lado del cliente. Por ejemplo, si serializamos el estado dentro de una etiqueta <script>
para hacerlo accesible globalmente en el lado del cliente a través de window.__pinia
, podemos escribir esto:
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
// `isClient` depende del entorno, por ejemplo, en Nuxt es `process.client`
if (isClient) {
pinia.state.value = JSON.parse(window.__pinia)
}
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
// `isClient` depende del entorno, por ejemplo, en Nuxt es `process.client`
if (isClient) {
pinia.state.value = JSON.parse(window.__pinia)
}