šŸš© Vuex Pattern: Smart Module Registration

nkoik

Nikos Koikas

Posted on July 30, 2018

šŸš© Vuex Pattern: Smart Module Registration

Vue Experience: āš«ļøāš«ļøāš«ļøāš«ļøāšŖļø
Vuex Experience: āš«ļøāš«ļøāš«ļøāš«ļøāš«ļø

Have your ever tried to manage your's application state?
Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions between them. So, Vue offers Vuex but as official documentation says:

Vuex is using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated.

To help with that, Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules.


I think you have already got confused, so let's go into code.

# This is a classic store structure with modules
ā”œā”€ā”€ index.html
ā”œā”€ā”€ main.js
ā”œā”€ā”€ components
ā””ā”€ā”€ store
    ā”œā”€ā”€ index.js    # where we assemble modules and export the store
    ā””ā”€ā”€ modules
        ā”œā”€ā”€ auth.js
        ā”œā”€ā”€ posts.js
        ā””ā”€ā”€ comments.js
Enter fullscreen mode Exit fullscreen mode

As you can see we have a store folder with an index.js and a subfolder named modules, which contains all modules. But module registration can start to get tedious.
index.js in store/

import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
import posts from './modules/posts'
import comments from './modules/comments'
// ...

Vue.use(Vuex)
export default new Vuex.Store({
    modules: {
        auth,
        posts,
        comments,
        // ...
    }
})
Enter fullscreen mode Exit fullscreen mode

Example scaffolding for Vuex modules.

export default {
  namespaced: true,
  state: {},
  getters: {},
  mutations: {},
  actions: {}
}
Enter fullscreen mode Exit fullscreen mode

This is the standard way for registering modules. If you know what namespacing is, go on.

By default, actions, mutations and getters inside modules are still registered under the global namespace - this allows multiple modules to react to the same mutation/action type.
If you want your modules to be more self-contained or reusable, you can mark it as namespaced with namespaced: true

Let's see Module Registration as mentioned by Chris Fritz(Vue core member) in a VueConf.

šŸš© Firstly, let's add a index.js file in store/modules/

# This is our store structure with modules
ā”œā”€ā”€ index.html
ā”œā”€ā”€ main.js
ā”œā”€ā”€ components
ā””ā”€ā”€ store
    ā”œā”€ā”€ index.js      # where we assemble modules and export the store
    ā””ā”€ā”€ modules
        ā”œā”€ā”€ index.js  # this is the js file that solves the problem
        ā”œā”€ā”€ auth.js
        ā”œā”€ā”€ posts.js
        ā””ā”€ā”€ comments.js
Enter fullscreen mode Exit fullscreen mode

šŸš© Then let's modify this index.js in store/modules/index.js

import camelCase from 'lodash/camelCase'
// Storing in variable a context with all files in this folder
// ending with `.js`.
const requireModule = require.context('.', false, /\.js$/)
const modules = {}

requireModule.keys().forEach(fileName => {
    if (fileName === './index.js') return
    // filter fullstops and extension 
  // and return a camel-case name for the file
    const moduleName = camelCase(
        fileName.replace(/(\.\/|\.js)/g, '')
    )
  // create a dynamic object with all modules
    modules[moduleName] = {
    // add namespace here
        namespaced: true,
        ...requireModule(fileName).default
    // if you have exported the object with name in the module `js` file
    // e.g., export const name = {};
    // uncomment this line and comment the above
        // ...requireModule(fileName)[moduleName]
    }
})
export default modules
Enter fullscreen mode Exit fullscreen mode

šŸš© Let's delete namespacing from every module js file.

// export const name = { if you want to export an object with name
export default {
  // namespaced: true,   delete this line 
    state: {},
    getters: {},
    mutations: {},
    actions: {}
}

Enter fullscreen mode Exit fullscreen mode

šŸš© Finally the code from above, where we had to import all the modules can change to:
index.js in store/

import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'

Vue.use(Vuex)
export default new Vuex.Store({
    modules
})
Enter fullscreen mode Exit fullscreen mode

I think we have done an ''automated'' system that includes every file in modules folder. A smarter and cleaner code.

Until next time...Happy coding!

šŸ’– šŸ’Ŗ šŸ™… šŸš©
nkoik
Nikos Koikas

Posted on July 30, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related