As soon as you start learning Vue you find out that the atomic unit of its architecture are components. In fact, that's nothing Vue-specific: any component-based technology, such as React or Angular, work the same way.
Then you learn more about components and how to build them. You start creating your own components, combining them and applying different communication patterns in order to build more complex components. Sure you're doing great and keep the components as small as possible so you can reuse some of them in several places of your application.
But at some point, the application grows. You have many components and things are starting to get messy: it's hard to find the right component and to know its responsibility, then maintainability starts to suffer.
No worries, in this article we're going to see different ways and tips you can use to structure your application components.
First Steps: Pages
A basic structure commonly seen when starting an application from scratch has a
components folder, along with a
main.js entry file and an
src/ main.js App.vue components/
After a while, you'll have several components. A very simple example of that structure, could be:
components/ ArticlePage.vue ArticleTitle.vue ArticleList.vue AppButton.vue AppFooter.vue AppHeader.vue LastArticlesSection.vue AppList.vue UserPage.vue
Note: Vue’s style guide multi-word rule tells us not to use a single word to name a component, that’s why we’re prefixing some with “App”
In component-based technologies, everything is a component. Having a fact like that, we must think about a way to categorize them.
If you take a look at above's structure, you can easily identify one type of components: pages. Thus, we can create a pages folder when we can place our page components:
components/ ArticleTitle.vue ArticleList.vue AppButton.vue AppFooter.vue AppHeader.vue LastArticlesSection.vue AppList.vue pages/ ArticlePage.vue UserPage.vue
That's an easy split and already gives us a bit of structure, so that when we know where to place and search for pages components.
However, a page is usually composed by more components or sections. Related to the ArticlePage, we see the ArticleTitle, ArticleList and LastArticlesSection components.
Let's assume ArticleTitle and LastArticlesSection are meant to exist only in the ArticlePage, but ArticleList is a component that fetches and renders a list of articles, and it can be used in multiple places.
Given these facts, it would make sense that ArticleTitle and LastArticlesSection are placed along with its page in a common folder:
components/ ArticleList.vue AppButton.vue AppFooter.vue AppHeader.vue AppList.vue pages/ ArticlePage/ index.vue ArticleTitle.vue LastArticlesSection.vue UserPage.vue
We've also renamed ArticlePage.vue to index.vue. Thanks to how module resolution works, when we import the article page in this way:
import ArticlePage from "@/pages/ArticlePage"
It will be imported it from
pages/ArticlePage/index.vue. For that reason, we can always start creating the pages as a component and later move it to a folder without having to change the way to import it, making refactoring easier.
We still have components with mixed responsibilities and domains in the components folder.
There is another split point on UI components: those that are reusable across the whole app. They communicate just by using props and events, not holding any application logic.
In the structure of this example, we see that the AppButton and AppList components are one of them, so let's place them under the ui folder:
components/ ui/ AppButton.vue AppList.vue ArticleList.vue AppFooter.vue AppHeader.vue pages/ ArticlePage/ index.vue ArticleTitle.vue LastArticlesSection.vue UserPage.vue
The AppFooter and AppHeader components, however, are not exactly UI components. Instead they're more like layout components since the app will have only one footer and header. You don't need to, but you can move them to a layout folder if you want:
components/ layout/ AppFooter.vue AppHeader.vue ui/ AppButton.vue AppList.vue ArticleList.vue pages/ ArticlePage/ index.vue ArticleTitle.vue LastArticlesSection.vue UserPage.vue
What about the ArticleList component? We can have components that are reusable in different pages, so we shouldn't place them with the page components. However, they belong to a specific domain, in this case to the article domain.
Let's call them domain components. A good way to organize them is to place them in separate folders under components, one folder per domain:
components/ article/ AppList.vue layout/ AppFooter.vue AppHeader.vue ui/ AppButton.vue AppList.vue pages/ ArticlePAge/ index.vue ArticleTitle.vue LastArticlesSection.vue UserPage.vue
Again, we can remove the Article prefix since the path is already representative. In fact, now we have two List components:
import ArticleList from "@/components/article/List" import AppList from "@/components/ui/AppList"
Lastly, what about the rest of the components? There can be components that belong to no domain, are not ui or layout. They can be some kind of utility components that have some logic but delegate the rendering to children components.
For example, imagine an Observer component that detects when its children intersect on the screen. Another example is vue-no-ssr: a component that renders its children only when it's running on the client, in case you're applying Server-Side Rendering (SSR) or you're using Nuxt.
We can place this kind of uncategorised common components under a common folder:
components/ article/ AppList.vue common/ AppObserver.vue NoSSR.vue layout/ AppFooter.vue AppHeader.vue ui/ AppButton.vue AppList.vue pages/ ArticlePage/ index.vue ArticleTitle.vue LastArticlesSection.vue UserPage.vue
We've seen different techniques to structure your application components. They might be helpful for you or not, but I hope at least you got some ideas that you can use from now on.