This would register the modules and the code would be separated in such a way that it is still readable, navigable and maintainable. A good example of this implementation can be found inside bstavroulakis/vue-wordpress-pwa or in my implementation igeligel/vuex-namespaced-module-structure. This application structure will handle small to medium applications really well. A new developer to the codebase will not struggle to find places where the business logic lives since every module should have a proper name and reference inside the components. It is really interesting to work with modules, and this is explained in the official documentation.

At some point though, there is a problem. Your backend team is creating many more APIs and the application is getting more and more complex. You reach 20, 30 or 50 modules. Still maintainable but the new intern you got is struggling with the architecture since he is not sure where the business logic is called. Then you ask yourself how you could structure this better. You could probably do the API calls directly in the components, but this would be a huge mess since components would then be holding business logic. Components should just be there to render data. Not handling data.

In React there is the concept of containers and components. It is not strongly enforced by Vue.js. Containers are just components, but they can also fetch data from the store and speak to a store. Components are just there to hold the data and render it. They communicate via props to those upper containers. Let us imagine a chat widget inside our application which needs to get some kind of data from the store or even better from the API. We will just create a simple example by getting all messages from the chat and no real-time support. Let us assume we have some kind of container which holds the whole chat. This container will communicate with the store to update data, or to populate data to the presentation components. The whole architecture is shown in this little graphic:

Architecture of the chat widget

In this system we have a container called Chat.vue which communicates to our store module chat . This chat module also handles the logic by calling the API and updating the store. When the state has finally updated the container, Chat.vue will also be updated by using a computed property which will be updated by the reactive nature of Vue.js and Vuex. After this, the property will be handed down to ChatList.vue as props. Since the props are an Array in this component, an iteration will take place which will render a list of ChatListElement.vue components which are responsible for rendering the chat messages and meta information.

With this pattern, we have split the application into three parts. One part is the business logic which exists inside the module of the store or more generally just in the store, the container elements which are responsible for getting the data and populating it to the presentation components, which are just there for rendering the data. This offers us great modularity and supports the single responsibility principle. It provides also good testability since you can test each part of this structure by itself. Together they will form some kind of integration test. But this can be discussed in another article.

Now imagine the application grows a lot. By a lot, I mean you have several modules and it is not clear where those modules are used anymore, which components depend on them and which do not. In huge applications, this can be a real problem. Imagine someone new to the codebase overlooking 50 modules and somewhere around 50 components. He would have a big problem to navigate around.

Vuex’s recommendation is to have directories of features of business logic inside the store directory. Sometimes the connection to the containers which are using those modules can be broken up and it gets unclear where those Vuex modules are used. Some modules might just be there because of one container so it would be good to have this business logic somewhere near the container which will handle the data. Let us restructure the application a bit. This template is based on vuejs-templates/webpack.

Improved application structure

The only difference is that I installed Vuex to this template, set it up and added the modules directory below the src directory. You can find this application later in this blog post. The difference with this directory is that it contains modules. Do not mix up these modules with Vuex modules. There is probably a better name, so if you know one please comment it under this article. So, inside the modules directory, we have the modules of this Vue.js application. It looks something like this:

Inside the modules directory

Inside the modules directory, there are several directories describing the different features. For example, we have the chat and products feature. The interesting thing, though, is inside those module directories. We have a store directory, a index.vue file and components. To clear things up we will just look at the Single File Component files. The index.vue is used as a container component. This container will fetch all data out of the store and pass this data as props to the components. The components ChatList.vue and ChatListElement.vue are just there to get the data out of the component and trigger actions to the store, which is globally attached to the Vue.js instance. The big question is why those components are not in the components directory. The reason is that those components are specially made for this feature. If they would have been reused for another feature then I would consider moving it into components directory. Basically the question here, is if the component is reused in some way. Then we should refactor the component into the shared component directory. Now comes the store. It is basically the same store as in the other pattern but moved into the local directory store. To register it we use the registerModule function from Vuex. This function will register the Vuex module dynamically. Normally it is used for plugins, but we will use it here for better separation of concerns. Inside the index.vue file we can access the lifecycle functions by Vue.js, and inside the created function we can safely create our module.

import { mapGetters } from 'vuex';

import store from './_store';

import ChatList from './_components/ChatList';



export default {

name: 'ChatModule',

components: {

ChatList,

},

computed: {

...mapGetters({

messages: '$_chat/messages',

}),

},

created() {

this.$store.registerModule('$_chat', store);

},

mounted() {

this.$store.dispatch('$_chat/getMessages');

},

};

We prefix it with $_ to show that this module is private, since it is just available within the module. After registering, the store will be populated to our global Vuex store. From there on we can use those Vuex functionalities inside our components. To register the store we need to somehow bind the Vuex functionality to the Vue.js instance. This can be done easily done by creating an empty Vuex store, exporting it and appending it to the Vue.js constructor. Lookup these files to get the idea (store/index.js, main.js).

If we find ourselves needing some kind of global store, I would create a Vuex module under the store directory with the recommended structure. If, for example, we need to authenticate at different places inside the application, it would be better to have it shared in a way which is not coupled to containers. This would be a nice use case for having the shared Vuex module.

Global Vuex modules

Some of the pitfalls: It is probably not clear which modules to make global or just locally available and it is really hard to decide. It is also really hard to find components which should be global, but basically, all generic components should be inside this directory which is used by different modules. It is really hard to maintain this structure but in the end, I think it is worth it in order to scale the application. Another pitfall is the naming. You have components directories all over the place now. It’s probably better to name the directory inside the modules _components to show they are private components but this is something of personal preference.

A good argument for this structure is that modules are somehow extractable. If a feature gets too big you can just extract it by creating a module out of its directory inside the src/modules directory and make a npm package out of it. The only thing you would need to export is the container component. This npm package can then be hosted on your company’s registry or publically on npm. Just be sure to somehow make the behaviors of the Vuex module configurable. Another good argument is that tests can be written in a feature scoped way.

The most positive argument is that the scope of the Vuex module, the containers and the components is clear to every developer who is reading through the code. You can find the business logic of every feature really fast and features are easily testable since the principle of separation of concerns is used throughout the whole application.

Examples of the different structures:

Still here?

Thanks for reading this article. I appreciate it 🙂 You can follow me on twitter or come to my personal site where you can find more blog articles and a little bit more about me and my projects.

This blog post was written in cooperation with the company 3YOURMIND. We are looking for developers in Berlin. You can find openings here. We are a 3D Printing startup with a lot of cool engineers using Vue.js, Django REST, Java, Docker and many more frameworks to change the enterprise 3D printing world.