Lazy loading on vuex modules

Hello,

I’m trying to use lazy loading with my vuex modules like this article : https://alexjoverm.github.io/2017/07/16/Lazy-load-in-Vue-using-Webpack-s-code-splitting/

Here is my old store\index.js :

import Vue from 'vue';
import Vuex from 'vuex';

import app from './modules/app';
import search from './modules/search';
import identity from './modules/identity';
import profil from './modules/profil';

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    app,
    search,
    identity,
    profil,
  },
});

I tried to do this :

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store();

import('./modules/app').then((appModule) => {
  store.registerModule('app', appModule);
});

import('./modules/search').then((searchModule) => {
  store.registerModule('search', searchModule);
});

import('./modules/identity').then((identityModule) => {
  store.registerModule('identity', identityModule);
});

import('./modules/profil').then((profilModule) => {
  store.registerModule('profil', profilModule);
});

But now I have a lot of error like “this.$store is undefined” or “this.$store.dispatch(…) is undefined” and all my app is broken
Did I’ve done something wrong ?

Well, it seems you don’t export your store anymore?

Yes I have correct this I’ve added :
export default store;

But now all my mapState variables and mapActions functions are undefined :confused:

That’s not very specific …

Well, since a change my store\index.js I have a lot of error like :
"TypeError: _vm.consultList is undefined"
Same for the mapActions functions :
"Error in render: “TypeError: _vm.getConsultList is undefined”

The code :

computed: {
      ...mapState({
        consultList: state => state.identity.consultList,
      }),
    },
methods: {
      ...mapActions([
        'getConsultList',
      ]),
},
created() {
      this.getConsultList();
},

Well, you are lazy-loading your store modules, so they are not available initially, and their state isn’t as well. That means if you immediatly start your app and render a component that tries to access consultList, it’s undefined because the store module hasn’t been loaded yet.

You should probably go back and think about why you want to lazy load them, and when you want to or have to load them. It seems you don’t have a real plan for that yet.

The usual approach would be to lazy-load only those store modules that are required for a certain route, for example - and then make sure that the module has been loaded before actually loading that route (you would use vue-router’s navigation guards like beforeRouteEnter for this, for example)

Ok thanks I’ll think about it

Hi, Linus. I think it would be a greath feature, if vuex could provide store modules lazy loading like vue-router does. For example

const store = new Vuex.store({
    state:() => ({...}),
    ...mutations,
    ...getters,
    ...actions,
    modules:{
         lazyOne: ()=>import("@/store/modules/lazy-one/lazyOne"),
    }
})

Also it would be greath if vuex could provide documentation about how to hot reload lazy registered module

computed: {
      ...mapState({
        consultList: state => state.identity && state.identity.consultList,
      }),
},
methods: {
      getConsultList(){
           this.$store.dispatch('identity/counsultList')
      }
},
async created() {
      const  identityModule =  await import('./modules/identity');
      this.$store.registerModule('identity', (identityModule.default || identityModule));
      this.getConsultList();
},

but mapActions wouldnt work anyway. Also you need to check if module is registered already

export function registerStoreModule(store, module, moduleName) {
    const moduleIsRegistered = store._modules.root._children[moduleName] !== undefined;
    const stateExists = store.state[moduleName];

    if (!moduleIsRegistered) {
        store.registerModule(moduleName, module, {preserveState: stateExists});
    }
}

And also with HMR you would do something like

If(IS_DEV && module.hot) {
    const identity = require("./modules/identity");
    module.hot.accept(
        ["./modules/identity"],
        () => {
        const identity = require("./modules/identity").default;
         store.hotUpdate({modules: {identity}})
        }
    )
}

So for dev mode you can require module on initial load, and then import it lazy way. Otherwise hmr wouldn’t catch the hot updates on ./modules/identity file. Also you’d better use lazy loading in asyncData, or beforeRouteEnter hook, especially if your use ssr.
Also you can try to import and register vuex module synchronously inside a lazy abstract component (like react do) and wrap your page with it. Maybe it would look more or less weird.