Интеграции
Vue-плагин
Установите плагин, чтобы настроить глобальный префикс ключей, цель по умолчанию и обработчик ошибок.
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, у которых свои независимые опции, не читающие настройки плагина.
| Опция | Тип | Описание |
|---|---|---|
prefix | string | Добавляется перед каждым ключом хранилища — useStorage('counter', ...) на самом деле читает/пишет myapp:counter. Два вызова useStorage() для одного логического ключа, установленные с разными префиксами, считаются разными экземплярами |
defaultTarget | StorageTarget | Используется, когда вызов сам не передаёт target; явный target (включая встроенный в useLocalStorage/useSessionStorage) всегда побеждает |
defaultSerializer | Serializer<unknown> | Запасной вариант, используемый, когда вызов не передаёт свой serializer |
defaultEncrypt | EncryptOptions | При 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 один раз, там, где вы создаёте приложение.
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-режима:
if (import.meta.env.DEV) {
const { setupDevtools } = await import('vue-storage-kit/devtools')
setupDevtools(app)
}Модуль Nuxt
Добавьте модуль в nuxt.config.ts, чтобы автоимпортировать все composables и зарегистрировать плагин с префиксом из runtimeConfig.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['vue-storage-kit/nuxt'],
storageKit: {
prefix: 'myapp_',
autoImports: true, // по умолчанию: true
},
})При autoImports: true следующее доступно глобально без явного импорта. useCookie здесь разрешается в SSR-совместимую runtime-версию (на базе H3 на сервере), а не в клиентскую, экспортируемую из корня пакета:
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, так что безопасен при конкурентном рендеринге.
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
| Vue | React | |
|---|---|---|
| Возвращает | { 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).
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 | Реэкспортированы для удобства |