Skip to content

Интеграции

Vue-плагин

Установите плагин, чтобы настроить глобальный префикс ключей, цель по умолчанию и обработчик ошибок.

ts
import { createApp } from 'vue'
import { VueStoragePlugin } from 'vue-storage-kit'
import App from './App.vue'

const app = createApp(App)

app.use(VueStoragePlugin, {
  prefix: 'myapp:', // все ключи автоматически получают префикс
  defaultTarget: 'local',
  onError: (err) => {
    if (err.type === 'quota-exceeded') showNotification('Storage full')
  },
})

app.mount('#app')

VueStoragePluginOptions

Применяются к каждому вызову useStorage() (и ко всему, что на нём построено, например useStorageList()), сделанному после установки плагина — но не к useCookie, useIndexedDB/useIDBRef или createPiniaPersist, у которых свои независимые опции, не читающие настройки плагина.

ОпцияТипОписание
prefixstringДобавляется перед каждым ключом хранилища — useStorage('counter', ...) на самом деле читает/пишет myapp:counter. Два вызова useStorage() для одного логического ключа, установленные с разными префиксами, считаются разными экземплярами
defaultTargetStorageTargetИспользуется, когда вызов сам не передаёт target; явный target (включая встроенный в useLocalStorage/useSessionStorage) всегда побеждает
defaultSerializerSerializer<unknown>Запасной вариант, используемый, когда вызов не передаёт свой serializer
defaultEncryptEncryptOptionsПри encrypt: true используется как есть. При encrypt: { ... } опции вызова накладываются поверх — например, encrypt: { iterations: 200_000 } может переопределить только одно поле, при этом пароль всё равно берётся отсюда
onError(err: StorageError) => voidВызывается в дополнение к (а не вместо) любого onError конкретного вызова — удобно для логирования/телеметрии на уровне приложения наряду с обработкой на конкретном месте вызова

Devtools

Кастомный инспектор Vue Devtools и таймлайн, построенный на общем кэше движка — так что показывает каждый живой экземпляр useStorage() независимо от того, был ли он создан из Vue или из хука React.

  • Инспектор: ключ, цель, текущее значение, isReady, expiry, canUndo/canRedo и состояние ошибки — обновляется примерно раз в секунду, так что изменения, вызванные синхронизацией между вкладками или TTL, появляются без ручного обновления.
  • Таймлайн: логирует события write, expire, migrate, sync-received и error по мере их возникновения, так что вы видите когда и почему изменилось значение, а не только его текущий снапшот.

Опционально: вызовите setupDevtools(app) из точки входа /devtools один раз, там, где вы создаёте приложение.

ts
import { createApp } from 'vue'
import { setupDevtools } from 'vue-storage-kit/devtools'
import App from './App.vue'

const app = createApp(App)
setupDevtools(app)
app.mount('#app')

Безопасно вызывать безусловно — setupDevtools@vue/devtools-api, который он оборачивает) ничего не делает, когда клиент devtools не подключён, так что вызов в продакшене не имеет эффекта, кроме (крошечного) добавленного кода. Если хотите полностью убрать это из продакшен-бандлов, оберните вызов и импорт своей проверкой dev-режима:

ts
if (import.meta.env.DEV) {
  const { setupDevtools } = await import('vue-storage-kit/devtools')
  setupDevtools(app)
}

Модуль Nuxt

Добавьте модуль в nuxt.config.ts, чтобы автоимпортировать все composables и зарегистрировать плагин с префиксом из runtimeConfig.

ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['vue-storage-kit/nuxt'],

  storageKit: {
    prefix: 'myapp_',
    autoImports: true, // по умолчанию: true
  },
})

При autoImports: true следующее доступно глобально без явного импорта. useCookie здесь разрешается в SSR-совместимую runtime-версию (на базе H3 на сервере), а не в клиентскую, экспортируемую из корня пакета:

ts
useStorage()
useLocalStorage()
useSessionStorage()
useIndexedDB()
useIDBRef()
useCookie()

Оговорка про SSR: кэш экземпляров StorageEngine (по ключу target:key, общий для привязок и Vue, и React) — синглтон на уровне модуля для каждого серверного процесса, а не для каждого запроса. target: 'local' / 'session' уже закрыто откатываются к defaultValue на сервере (в Node нет window). Однако у target: 'memory'/'indexeddb' такой защиты нет, и они будут делить состояние между конкурентными запросами на одном сервере, если использовать их при SSR — избегайте этих целей для данных по-запросу/по-пользователю на сервере; они предназначены для клиентского использования.

Поддержка React

Точка входа /react экспортирует хук useStorage(), построенный на том же фреймворк-агностичном движке, что и Vue composable — те же опции (TTL, миграции, encrypt, compress, sign, sync, debounce/throttle, history, evictOnQuota), то же поведение. Он построен на React useSyncExternalStore, так что безопасен при конкурентном рендеринге.

tsx
import { useStorage } from 'vue-storage-kit/react'

function Counter() {
  const {
    value: count,
    setValue: setCount,
    isReady,
  } = useStorage('count', {
    defaultValue: 0,
    target: 'local',
  })

  if (!isReady) return <p>Loading…</p>

  return <button onClick={() => setCount((c) => c + 1)}>Clicked {count} times</button>
}

Отличия от Vue composable

VueReact
Возвращает{ value: Ref<T>, ... } — присвойте value.value = x для записи{ value: T, setValue, ... } — вызовите setValue(x) или setValue(prev => next) для записи
Общий экземплярДва Vue-компонента с одним key+target делят один RefДва React-компонента с одним key+target делят один и тот же движок (через useSyncExternalStore), но каждый получает свой снапшот
Реакция на изменившийся keyНе поддерживается — как и на стороне VueНе поддерживается. Смонтируйте новый экземпляр компонента для другого ключа (например, через проп key) — тот же паттерн, что React уже рекомендует для «сбросить это состояние»

Два Vue-компонента, два React-компонента или их смесь, вызывающие useStorage() с одним key+target, все делят один движок — один набор таймеров, один вызов адаптера на запись, один конвейер TTL/миграций/синхронизации — независимо от того, какой фреймворк(и) их создал.

Пока недоступно для React (пока только для Vue — см. todo.md проекта для отслеживаемого бэклога): useCookie, useIndexedDB/useIDBRef, useStorageList, useStorageKeys, useBroadcastChannel и эквивалент Pinia-persist.

react (^18.0.0, для useSyncExternalStore) — опциональная peer-зависимость, нужна только при импорте vue-storage-kit/react.

Утилиты для тестирования

Точка входа /testing упаковывает паттерны, которые собственный тестовый набор этого пакета использует повсюду — без импорта, специфичного для тест-раннера (работает с Vitest, Jest или чем угодно ещё, поскольку просто переприсваивает обычное свойство объекта, а не использует vi.spyOn).

ts
import {
  mockStorage,
  resetStorageState,
  seedExpiredEnvelope,
  flushAsync,
} from 'vue-storage-kit/testing'
import { useStorage } from 'vue-storage-kit'

beforeEach(() => {
  resetStorageState() // очищает общий кэш экземпляров/движка между тестами
})

it('reads an existing value', async () => {
  const { adapter, restore } = mockStorage() // перенаправляет любую цель на один MemoryStorageAdapter
  await adapter.setItem('k', JSON.stringify({ v: 1, d: '"stored"', exp: null, ts: Date.now() }))

  const { value } = useStorage('k', { defaultValue: 'default', target: 'memory' })
  await flushAsync()

  expect(value.value).toBe('stored')
  restore()
})

it('treats an expired key as expired', async () => {
  const { adapter } = mockStorage()
  await seedExpiredEnvelope(adapter, 'k', 'stale') // сокращение для конверта выше, с exp в прошлом

  const { value } = useStorage('k', { defaultValue: 'default', target: 'memory' })
  await flushAsync()

  expect(value.value).toBe('default')
})
ЭкспортОписание
mockStorage(adapter?)Перенаправляет StorageAdapterFactory.get(), чтобы всегда возвращать adapter (свежий MemoryStorageAdapter по умолчанию), независимо от запрошенной цели. Возвращает { adapter, restore() }
resetStorageState()Очищает общий кэш экземпляров/движка useStorage() (и Vue, и React) и синглтоны StorageAdapterFactory для каждой цели
seedEnvelope(adapter, key, value, opts?)Пишет сырой конверт напрямую, чтобы подготовить состояние без живого экземпляра useStorage()
seedExpiredEnvelope(adapter, key, value, opts?)seedEnvelope() с exp, по умолчанию установленным на метку времени уже в прошлом
flushAsync(ms?)Ожидаемая задержка (по умолчанию 10мс), позволяющая устояться ожидающим записям/debounce/throttle/динамическим импортам
MemoryStorageAdapter, StorageAdapterFactoryРеэкспортированы для удобства