Closed Nigui closed 3 years ago
Hi @Nigui, I have no experiece with vuex-module-decorator
, but I don't see anywhere @Module
in the code you provided.
The typing of the store
wrapper is correct and casting it to something else will probably cause problems.
Note that, if you need the store instance, you can just move the Vuex.Store initialization outside the function and export it as a named export (which IS DIFFERENT from the default export, which is a function returning the store instance).
Vue.use(Vuex);
export const store = new Vuex.Store<any>({
modules: {
// example
},
// enable strict mode (adds overhead!)
// for dev mode only
strict: !!process.env.DEV,
});
export default store(({ Vue }) => {
return store
},
);
I tried the above workaround in SSR mode and I get [vuex] must call Vue.use(Vuex) before creating a store instance.
EDIT: I thought calling Vue.use(Vuex) outside a function would cause state pollution on ssr, it doesnt. You can just put the line before
Updated the example to actually install the plugin before creating the store.
Closing due to lack of answer from issue author
While that isn't a problem in others modes, in the SSR mode you would keep the store and router wrappers, that is needed to prevent poisoning of the global scope. That said, if u wanna to access the store and/or router, u would do this thought a vue component or inside a boot and/or preFetch, other way is passing the store/router as parameter to your "singletons".
TL;DR; anyway, i was able to make the vuex-module-decorators
work, all what u need todo is call getModule
after register a module.
quasar create ts-store
yarn add -D vuex-module-decorators
# that is needed to generate the needed flags, without this, your code editor will not recognize the store in the wrappers (router, boot, preFetch, etc)
quasar dev -m ssr
in order to test, i created two modules, one will be registered globally and the another on demand. src/store/modules/app.js
import { uid } from 'quasar'
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'
@Module({ namespaced: true, name: 'app' })
export default class App extends VuexModule {
uid = ''
@Mutation
setUid(uid: string) {
this.uid = uid
}
@Action({ commit: 'setUid' })
async uidAsync() {
await new Promise(resolve => setTimeout(resolve, 250))
return uid()
}
get reverseUid () {
return this.uid.split('').reverse().join('')
}
}
src/store/modules/ondemand.js
import { uid } from 'quasar'
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'
@Module({ namespaced: true, name: 'demand' })
export default class App extends VuexModule {
uid = ''
@Mutation
setUid(uid: string) {
this.uid = uid
}
@Action({ commit: 'setUid' })
async uidAsync() {
await new Promise(resolve => setTimeout(resolve, 250))
return uid()
}
get reverseUid () {
return this.uid.split('').reverse().join('')
}
}
and now, the store/index.js
, who is where the magic happens:
import { store as wrapper } from 'quasar/wrappers'
import Vuex, { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import app from './modules/app';
export interface StateInterface {
app: unknown;
demand: unknown;
}
export default wrapper(function ({ Vue }) {
Vue.use(Vuex)
const store = new Store<StateInterface>({
modules: {
app
},
strict: !!process.env.DEBUGGING
})
// this line does all the magic
getModule(app, store)
return store
})
now, try to dispatch an action from a boot: src/boot/store.js
import { boot } from 'quasar/wrappers'
import { Store } from 'vuex'
import { StateInterface } from 'src/store'
export default boot<Store<StateInterface>>(({ store }) => {
return store.dispatch('app/uidAsync')
})
don't forget to register this boot to run only at the server side: quasar.config.js
module.exports = configure(function (ctx) {
return {
boot: [
'composition-api',
{ path: 'store', client: false }
],
}
}
And finally, the last test, lets register the ondemand module inside the index page (using the Store Code Splitting strategy)
<template>
<q-page class="row items-center justify-evenly">
<div class="row">
<div class="col col-auto">App UID:</div>
<div class="col">{{appUid}}</div>
</div>
<div class="row">
<div class="col col-auto">Page UID:</div>
<div class="col">{{demandUid}}</div>
</div>
<div class="row">
<div class="col col-auto">Reversed App UID:</div>
<div class="col">{{reversedAppUid}}</div>
</div>
<div class="row">
<div class="col col-auto">Reversed Page UID:</div>
<div class="col">{{reversedDemandUid}}</div>
</div>
</q-page>
</template>
import { defineComponent } from '@vue/composition-api'
import { getModule } from 'vuex-module-decorators'
import { preFetch } from 'quasar/wrappers'
import { StateInterface } from 'src/store'
import { Store, ModuleOptions } from 'vuex'
import OnDemand from 'src/store/modules/ondemand'
function registerModule(store: Store<StateInterface>, options?: ModuleOptions | undefined) {
if (!store.hasModule('demand')) {
store.registerModule('demand', OnDemand, options)
// this line does all the magic
getModule(OnDemand, store)
}
}
export default defineComponent({
name: 'PageIndex',
preFetch: preFetch<Store<StateInterface>>(({ store }) => {
registerModule(store)
return store.dispatch('demand/uidAsync')
}),
created () {
registerModule(this.$store, { preserveState: true })
},
beforeDestroy () {
this.$store.unregisterModule('demand')
},
computed: {
appUid () {
return this.$store.state.app.uid
},
demandUid () {
return this.$store.state.demand.uid
},
reversedAppUid () {
return this.$store.getters['app/reverseUid']
},
reversedDemandUid () {
return this.$store.getters['demand/reverseUid']
}
}
})
now, run the project and check if anything had run as expected (check if the variables present in the window.__INITIAL_STATE__ are equals to the one displayed at the screen)
Describe the bug
I'm working with the following tools :
quasar/wrappers
store
function returnsStoreCallback
(which is a shorthand for(params: StoreParams) => Store<any>
)When we declare a new
@Module
withvuex-module-decorator
we have to pass a reference to vuex store which must be of typeStore<any>
.(params: StoreParams) => Store<any>
is explicitly not equal toStore<any>
so typescript throws the following errorMy workaround
I force
store
return type toStore<any>
in@/store/index.ts
To Reproduce Craft a sample with my introduced stack
Expected behavior I would like to use my (not very unusual ) stack without any typescript errors