Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store works when using "window.localStorage" but not when using "localForage".. any pointers would be appreciated #232

Open
wattsie opened this issue Jul 8, 2021 · 3 comments

Comments

@wattsie
Copy link

wattsie commented Jul 8, 2021

Hi All,
New to "vuex-persist" mainly been using another persist package, and started having issues with exceeding storage size.
Data is around 6mb, but looks like LocalStore is limited to less than ~5Mb.

So thought I would take a look into using "vuex-persist" and IndexedDB (via localForage).

As such, I have configured my store as follows:

import {createLogger, createStore} from 'vuex'
import VuexPersist from 'vuex-persist'
import localForage from 'localforage'

// Store Modules
import settings from '@/store/modules/settings'
import data from '@/store/modules/data'

const debug = process.env.NODE_ENV !== 'production'

// Create the Persistence Store
const vuexStorage = new VuexPersist({
    key: 'data',
    storage: window.localStorage,
})

// Export the store
export default createStore({
    modules: { settings, data },
    strict: debug,
    plugins: debug ? [createLogger(), vuexStorage.plugin] : [vuexStorage.plugin],
})

When run the above, all works as expected, I can see the localStore "data" key created with content, and when refreshing the page, everything loads as expected.

However, if I change to "localForage", nothing shows up in the "IndexedDB" Browser and when page is refreshed all data is lost.

const vuexStorage = new VuexPersist({
    key: 'data',
    storage: localForage,
    modules: [ 'settings' , 'data' ],
    asyncStorage: true,
})

PS: I do find I am getting the following on both Firefox and Chrome:

Uncaught (in promise) DOMException: Failed to execute 'put' on 'IDBObjectStore': [object Array] could not be cloned.

Which is weird, as all the data is a bunch of large arrays, and localStore saves perfectly.

Any suggestions or pointers would be really appreciated.

Many thanks in advance.

Package Versions:

"vue": "^3.0.11",
"vuex": "^4.0.1",
"localforage": "^1.9.0",
"vuex-persist": "^3.1.3"
@wattsie
Copy link
Author

wattsie commented Jul 26, 2021

Hi All,
As it has been very quiet on this git, I have spent some more time myself.

So I have been able to work out how to get around the IDBObjectStore issue, using the reducer: (state) => JSON.parse(JSON.stringify(state))

However, if I want to specify modules, the docs say you shouldnt use a reducer.

Any idea if it is possible to apply a reducer per module?

Or a fix so that state is stripped of all non-cloneable entries before being passed to localforage?

Here is what I have working atm, however I would like to be able to have mod1, mod2 and mod3 in separate stores.

Any suggestions?

import VuexPersist from 'vuex-persist'
import localForage from 'localforage'

const store1 = localForage.createInstance({})
store1.config({
    driver      : localForage.INDEXEDDB,
    name        : 'myDb',
    version     : 1.0,
    storeName   : 'myStore',
})

const vuexStorage1 = new VuexPersist({
    key: 'vuex',
    storage: store1,
    strictMode: false,
    asyncStorage: true,
    reducer: (state) => JSON.parse(JSON.stringify(state)),
})

export default createStore({
    modules: {
        mod1,
        mod2,
        mod3,
    },
    strict: false,
    plugins: [vuexStorage1.plugin],
})

For example, if I try this, I get a complete copy of all store modules in both databases.
Obviously, the converting of the global state is over ruling any module limits etc.

const store2 = localForage.createInstance({})
store2.config({
    driver      : localForage.INDEXEDDB,
    name        : 'myDb2',
    version     : 1.0,
    storeName   : 'myStore2',
})
const vuexStorage2 = new VuexPersist({
    key: 'vuex2',
    modules: ['mod2'],
    storage: myStore2,
    strictMode: false,
    asyncStorage: true,
    reducer: (state) => JSON.parse(JSON.stringify(state)),
})

and modify

plugins: [vuexStorage1.plugin, vuexStorage2.plugin],

Many thanks in advance.

@chrisspiegl
Copy link

I am having the same issue. No idea what may be going on there… also not really much to add, the description is already pretty on point.

@toniengelhardt
Copy link

I think we can do something like this:

storage: {
  getItem: async (key: string) => {
    const raw: string | null = await localForage.getItem(key)
    const data = raw ? JSON.parse(raw) : {}
    return data
  },
  setItem: async (key: string, value: any) => {
    const valueString = JSON.stringify(value)
    localForage.setItem(key, valueString)
  },
  removeItem: async (key: string) => localForage.removeItem(key),
},
asyncStorage: true,

aka. wrap the localForage getter and setter in sort of a serializer/deserializer.

This way we can still use the modules as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants