Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як передати стан Pinia з сервера в браузер при SSR і уникнути XSS?

При серверному рендерингу сервер заповнює стори (завантажує дані), рендерить HTML і має передати цей стан у браузер. Інакше на клієнті стори стартують порожніми, Vue перемалює сторінку іншими даними, і гідрація зламається.

Схема:

  1. на сервері після рендеру взяти весь стан: pinia.state.value;
  2. серіалізувати з екрануванням і вставити в HTML;
  3. на клієнті до першого useStore() відновити його.
// сервер
import { uneval } from 'devalue';

const html = await renderToString(app);
const state = uneval(pinia.state.value);
// <script>window.__pinia = ${state}</script>
// клієнт - перед монтуванням і до будь-якого useStore()
const pinia = createPinia();
app.use(pinia);
if (window.__pinia) {
  pinia.state.value = window.__pinia;
}

Чому JSON.stringify - діра. Стан майже завжди містить дані, які вводили користувачі (ім'я, коментар, назва товару). Рядок </script><script>stealCookies()</script> у полі name, вставлений через JSON.stringify у <script>, закриє тег і виконає чужий код. Документація Pinia прямо наголошує: стан треба екранувати, наприклад бібліотекою devalue (її використовує Nuxt), яка ще й зберігає Date, Map, Set.

Що не повинно гідруватися. У setup store можуть бути значення, що мають братися лише з браузера (наприклад, useLocalStorage). Їх позначають skipHydrate(), щоб серверне значення не затерло клієнтське.

Інші правила SSR зі сторами:

  • новий екземпляр Pinia на кожен запит - інакше стан одного користувача потрапить у відповідь іншому;
  • поза setup (guard роутера, serverPrefetch) передавати екземпляр явно: useStore(pinia);
  • не класти в стан секрети: усе, що в сторі на сервері, буде у HTML сторінки;
  • браузерні API (window, localStorage) у сторах - лише в діях, що викликаються в браузері, чи з перевіркою середовища.

У Nuxt усе це зроблено модулем @pinia/nuxt - вручну налаштовувати не треба.

Докладніше в документації: Pinia: SSR

Схожі питання