@ithinkdt/core
Version:
iThinkDT Core
111 lines (98 loc) • 3.46 kB
JavaScript
import { useEventListener } from '@vueuse/core'
import { copy, omitProps } from '@ithinkdt/common'
export let STORE_PREFIX = ''
export function persistPlugin({ prefix: _prefix, getUsername }) {
STORE_PREFIX = _prefix ?? STORE_PREFIX
return ({ options, store }) => {
if (!options.persist) {
return {
$clear() {
console.debug(`[store] the store '${store.$id}' not set persist, force it.`)
},
}
}
const {
prefix = _prefix,
userIsolate = false,
storage = 'session',
version = 1,
validate,
excludes,
saveOnlyChanged,
onStore,
onRestore,
} = options.persist
const getKey = () => `${prefix || ''}${store.$id}${userIsolate && getUsername() ? `[${getUsername()}]` : ''}`
const _state = saveOnlyChanged ? omitProps({ ...store.$state }, ...(excludes || [])) : undefined
let force
const parse = () => {
let data = parseData(storage, getKey(), version, validate)
if (saveOnlyChanged) data = Object.assign({}, _state, data)
if (onRestore) data = onRestore(data)
if (data) {
force = true
Object.assign(store.$state, data)
}
}
parse()
useEventListener('storage', (e) => {
if (e.key !== getKey() || e.newValue === e.oldValue) {
return
}
setTimeout(parse, 0)
})
store.$subscribe((_, state) => {
if (force) {
force = false
return
}
let s = {}
for (const key of Object.keys(state)) {
if (
typeof key !== 'symbol' &&
!excludes?.includes(key) &&
(!saveOnlyChanged || _state[key] !== state[key])
) {
s[key] = state[key]
}
}
s = onStore ? onStore(s) : s
saveData(storage, getKey(), s, version)
})
return {
$clear() {
saveData(storage, getKey(), undefined, version)
},
}
}
}
export function parseData(storage, key, version, validate) {
const $storage = storage === 'local' ? localStorage : sessionStorage
const data = $storage.getItem(key)
if (data) {
const { s, v, t } = JSON.parse(data)
console.debug(`[store] parsed '${key}' data from ${storage}, version: ${v}, date: ${t}, data:`, s)
if (v !== version || validate?.(s, v, t) === false) {
console.debug(`[store] '${key}' data not valid, remove it.`)
$storage.removeItem(key)
} else {
return s
}
}
return
}
export function saveData(storage, key, data, version) {
const $storage = storage === 'local' ? localStorage : sessionStorage
const date = Date.now()
const s = JSON.stringify({
t: date,
v: version,
s: data,
})
let old = $storage.getItem(key) ?? ''
old = old.slice(Math.max(0, old.indexOf('"v":')))
let n = s.slice(Math.max(0, s.indexOf('"v":')))
if (old === n) return
$storage.setItem(key, s)
console.debug(`[store] save '${key}' data to ${storage}, version: ${version}, date: ${date}, data:`, copy(data))
}