Рендеринг на стороні серверу (SSR)
TIP
Якщо ви використовуєте Nuxt.js, вам потрібно натомість прочитати ці інструкції.
Створення сховищ за допомогою Pinia має працювати для SSR з коробки, якщо ви викликаєте свої функції useStore() у верхній частині функцій setup, getters і actions:
<script setup>
// це працює, тому що Pinia знає, який застосунок працює всередині
// `setup`
const main = useMainStore()
</script><script setup>
// це працює, тому що Pinia знає, який застосунок працює всередині
// `setup`
const main = useMainStore()
</script>Використання сховища за межами setup()
Якщо вам потрібно використовувати сховища десь ще, вам потрібно передати екземпляр pinia, який було передано до застосунку до виклику функції useStore():
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
router.beforeEach((to) => {
// ✅ Це спрацює. Переконайтеся, що використовується коректне сховище для
// поточного запущеного застосунку.
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) => {
// ✅ Це спрацює. Переконайтеся, що використовується коректне сховище для
// поточного запущеного застосунку.
const main = useMainStore(pinia)
if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})Pinia зручно додає себе як $pinia до вашого застосунку, щоб ви могли використовувати її в таких функціях, як serverPrefetch():
export default {
serverPrefetch() {
const store = useStore(this.$pinia)
},
}export default {
serverPrefetch() {
const store = useStore(this.$pinia)
},
}Зауважте, що вам не потрібно робити нічого особливого коли використовуєте onServerPrefetch():
<script setup>
const store = useStore()
onServerPrefetch(async () => {
// ✅ Це спрацює
await store.fetchData()
})
</script><script setup>
const store = useStore()
onServerPrefetch(async () => {
// ✅ Це спрацює
await store.fetchData()
})
</script>Гідрація стану
Щоб гідратувати початковий стан, вам потрібно переконатися, що rootState включено десь у HTML, щоб Pinia міг забрати його пізніше. Залежно від того, що ви використовуєте для SSR, вам потрібно екранувати стан сховища з міркувань безпеки. Ми рекомендуємо використовувати @nuxt/devalue який використовується Nuxt.js:
import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// отримати rootState на стороні серверу
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
// після відтворення сторінки створюється кореневий стан, який можна прочитати
// безпосередньо з `pinia.state.value`.
// серіалізація, екранування (ДУЖЕ важливо, якщо вміст стану може бути змінений
// користувачем, що майже завжди так), і розміщення його десь на сторінці,
// наприклад, як глобальна змінна.
devalue(pinia.state.value)import devalue from '@nuxt/devalue'
import { createPinia } from 'pinia'
// отримати rootState на стороні серверу
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
// після відтворення сторінки створюється кореневий стан, який можна прочитати
// безпосередньо з `pinia.state.value`.
// серіалізація, екранування (ДУЖЕ важливо, якщо вміст стану може бути змінений
// користувачем, що майже завжди так), і розміщення його десь на сторінці,
// наприклад, як глобальна змінна.
devalue(pinia.state.value)Залежно від того, що ви використовуєте для SSR, ви встановите змінну початкового стану, яка буде серіалізована в HTML. Ви також повинні захистити себе від атак XSS. Ви можете використовувати інші альтернативи для @nuxt/devalue залежно від того, що вам потрібно, наприклад, якщо ви можете серіалізувати та проаналізувати свій стан за допомогою JSON.stringify()/JSON.parse(), ви можете значно покращити свою продуктивність.
Якщо ви не використовуєте Nuxt, вам доведеться самостійно виконувати серіалізацію та гідратацію стану. Ось кілька прикладів:
Адаптуйте цю стратегію до свого середовища. Переконайтеся, що стан pinia гідровано перед викликом будь-якої функції useStore() на стороні клієнта. Наприклад, якщо ми серіалізуємо стан у тег <script>, щоб зробити його доступним глобально на стороні клієнта через window.__pinia, ми можемо написати це так:
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
// `isClient` залежить від середовища, наприклад, на Nuxt це `process.client`
if (isClient) {
pinia.state.value = JSON.parse(window.__pinia)
}const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
// `isClient` залежить від середовища, наприклад, на Nuxt це `process.client`
if (isClient) {
pinia.state.value = JSON.parse(window.__pinia)
}