Skip to content

Commit 9c1272b

Browse files
committed
fix(storage): enhance storage handling with default merging options
1 parent 50833be commit 9c1272b

2 files changed

Lines changed: 88 additions & 22 deletions

File tree

src/components/Settings/About/About.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function handleResetSettings() {
7373
if (result) {
7474
// Remember the last selected language when resetting settings
7575
originalSettings.language = settings.value.language
76-
settings.value = originalSettings
76+
settings.value = { ...originalSettings }
7777
}
7878
}
7979

src/composables/useStorageLocal.ts

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,94 @@
1-
import type {
2-
MaybeRef,
3-
RemovableRef,
4-
StorageLikeAsync,
5-
UseStorageAsyncOptions,
6-
} from '@vueuse/core'
7-
import {
8-
useStorageAsync,
9-
} from '@vueuse/core'
1+
import type { MaybeRef, RemovableRef } from '@vueuse/core'
2+
import { StorageSerializers } from '@vueuse/core'
3+
import type { Ref } from 'vue'
4+
import { ref, toValue, watch } from 'vue'
105
import { storage } from 'webextension-polyfill'
116

12-
const storageLocal: StorageLikeAsync = {
13-
removeItem(key: string) {
14-
return storage.local.remove(key)
15-
},
7+
interface UseStorageLocalOptions {
8+
/** Merge the stored value with the default value (shallow) instead of replacing it. */
9+
mergeDefaults?: boolean
10+
/** Persist the default value when nothing is stored yet. Defaults to `true`. */
11+
writeDefaults?: boolean
12+
/** Deep watch the value for changes. Defaults to `true`. */
13+
deep?: boolean
14+
}
1615

17-
setItem(key: string, value: string) {
18-
return storage.local.set({ [key]: value })
19-
},
16+
type SerializerType = keyof typeof StorageSerializers
2017

21-
async getItem(key: string) {
22-
return (await storage.local.get(key))[key]
23-
},
18+
function guessSerializerType<T>(rawInit: T): SerializerType {
19+
return rawInit == null
20+
? 'any'
21+
: rawInit instanceof Set
22+
? 'set'
23+
: rawInit instanceof Map
24+
? 'map'
25+
: rawInit instanceof Date
26+
? 'date'
27+
: typeof rawInit === 'boolean'
28+
? 'boolean'
29+
: typeof rawInit === 'string'
30+
? 'string'
31+
: typeof rawInit === 'object'
32+
? 'object'
33+
: !Number.isNaN(rawInit as number)
34+
? 'number'
35+
: 'any'
2436
}
2537

26-
export function useStorageLocal<T>(key: string, initialValue: MaybeRef<T>, options?: UseStorageAsyncOptions<T>): RemovableRef<T> {
27-
return useStorageAsync(key, initialValue, storageLocal, options)
38+
/**
39+
* A `storage.local`-backed ref.
40+
*/
41+
export function useStorageLocal<T>(
42+
key: string,
43+
initialValue: MaybeRef<T>,
44+
options: UseStorageLocalOptions = {},
45+
): RemovableRef<T> {
46+
const { mergeDefaults = false, writeDefaults = true, deep = true } = options
47+
48+
const rawInit = toValue(initialValue) as T
49+
const type = guessSerializerType(rawInit)
50+
const serializer = StorageSerializers[type]
51+
const data = ref(rawInit) as Ref<T>
52+
53+
async function read() {
54+
try {
55+
const rawValue = (await storage.local.get(key))[key] as string | undefined
56+
57+
if (rawValue == null) {
58+
data.value = rawInit
59+
if (writeDefaults && rawInit != null)
60+
await storage.local.set({ [key]: serializer.write(rawInit) })
61+
}
62+
else {
63+
const value = await serializer.read(rawValue)
64+
if (mergeDefaults && type === 'object' && value && !Array.isArray(value))
65+
data.value = { ...(rawInit as object), ...(value as object) } as T
66+
else
67+
data.value = value as T
68+
}
69+
}
70+
catch (e) {
71+
console.error(e)
72+
}
73+
}
74+
75+
read().finally(() => {
76+
watch(
77+
data,
78+
async (value) => {
79+
try {
80+
if (value == null)
81+
await storage.local.remove(key)
82+
else
83+
await storage.local.set({ [key]: serializer.write(value) })
84+
}
85+
catch (e) {
86+
console.error(e)
87+
}
88+
},
89+
{ deep, flush: 'pre' },
90+
)
91+
})
92+
93+
return data as RemovableRef<T>
2894
}

0 commit comments

Comments
 (0)