SoFunction
Updated on 2025-04-11

10 Best Practices for Building Large Vue Applications (Summary)

These are the best practices I came up with to build large Vue projects, and these tips will help you code more efficiently and make it easier to maintain and collaborate.

I have had the honor of developing some large Vue programs during my freelancing career this year. These projects I'm talking about use a lot of Vuex stores 😰 , a lot of Vue components (with hundreds) and a lot of views (pages). It's a very meaningful experience for me and I've found a lot of ways to make the extension. At the same time, I also need to fix some messy usages. 🍝

So I'm going to share my 10 best practices that you recommend using them if you have large projects that need to be developed.

1. Using Slots can make your components more powerful and easy to understand.

I wrote an article recentlysome important things you need to know regarding slots in . It mainly talks about why using Slots can improve component reuse and is easy to maintain.

But what does this have to do with large Vue projects? I'll draw a blueprint to use them to solve your pain points.

Suppose I want to develop a popup. At first it seems that there is nothing difficult, just including the title, description and some buttons. So just treat everything as props? I used three custom props and triggered an event when clicking the button. It's that simple! 😅

As the project continues to grow, the business needs to display many other new content: form fields, different buttons (depending on which page it is displayed), cards, footers, and lists. This problem can be solved by adding more props. 😩 But as the business develops, the components become too complex. Because it contains many subcomponents, many events need to be triggered. 🌋I encountered a scam problem. After modifying one function, it affected the functions on other pages. I created a monster instead of a maintainable component!

However, it might be better to use slots at the beginning. Finally I made the widget to refactor this component. It makes it easier to maintain, understand and expand.

<template>
 <div class="c-base-popup">
  <div v-if="$" class="c-base-popup__header">
   <slot name="header">
  </div>
  <div v-if="$" class="c-base-popup__subheader">
   <slot name="subheader">
  </div>
  <div class="c-base-popup__body">
   <h1>{{ title }}</h1>
   <p v-if="description">{{ description }}</p>
  </div>
  <div v-if="$" class="c-base-popup__actions">
   <slot name="actions">
  </div>
  <div v-if="$" class="c-base-popup__footer">
   <slot name="footer">
  </div>
 </div>
</template>

<script>
export default {
 props: {
  description: {
   type: String,
   default: null
  },
  title: {
   type: String,
   required: true
  }
 }
}
</script>

From experience, building projects by developers skilled in using slots has more significance for future projects maintainability.

⚠️ Rule of thumb: When the parent component's props are used in the child component, slots should be used.

2. Organize your Vuex store

Usually, a new Vue developer learns Vuex because of two problems:

  • When a component needs to redirect a relatively far-reaching component (necked hierarchy or sibling component: translator's note) to access data.
  • When you need to hold a data that destroys the component.

In this way, he created the first Vuex store, learned the usage of moudles and organized the program. 💡
The problem is that there is no single mode to follow when creating modules. I strongly recommend that you must think clearly about how to organize them. As far as I know, many people prefer to organize them by function (I am too: translator's note). For example:

  • Auth.
  • Blog.
  • Inbox.
  • Settings.

For me, it is easier to understand using data models obtained from the API. example:

  • Users
  • Teams
  • Messages
  • Widgets
  • Articles

Using that depends on yourself, but in the long run, a well-organized Vuex store is more productive. This is also easy for newcomers to integrate into and inherit your original intention.

3. Use Actions to call the API and submit data.

Most (not all) of my API calls are in Vuex's actions, you must be wondering why. �room

Simply put, it is because when pulling data, you need to commit in the store. And he provides the packaging and reuse I like. Other reasons are:

  • If I get the data for the first page in two places (blog and home page). I just need to call it with different parameters to get the data, and no duplicate code outside the first time is called.
  • If you need to create some logic to avoid repeated pulling of data, you only need to pull it once in one place. In addition to reducing the burden on the server, I can also use this data anywhere.
  • I can end the Mixpanel event in actions, based on maintenance, making the problem easier to analyze. Most of my code have only one Mixpanel call in my actions, 😂 I don't have to pay attention to the data and send it this way of working so good.

4. Use mapState, mapGetters, mapMutations and mapAction to streamline the code.

When you access state/getters or call actions/mutations in a component, you usually need to create multiple computed properties. Using mapState, mapGetters, mapMutations and mapActions can be used to centralize data from store modules in one place, which can simplify the code and better understand.

// NPM
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";

export default {
 computed: {
  // Accessing root properties
  ...mapState("my_module", ["property"]),
  // Accessing getters
  ...mapGetters("my_module", ["property"]),
  // Accessing non-root properties
  ...mapState("my_module", {
   property: state => 
  })
 },

 methods: {
  // Accessing actions
  ...mapActions("my_module", ["myAction"]),
  // Accessing mutations
  ...mapMutations("my_module", ["myMutation"])
 }
};

All you want hereVuex official documentation

5. Quickly use API Factories

I usually create this.$api helper that can access my API portal anywhere. My project root has an api folder with all my classes (below).

api
├── 
├── 
└── 

Each is a group of interfaces, which is initialized by the way I use plugins in my Nuxt application. (very similar to the process in standard Vue applications).

// PROJECT: API
import Auth from "@/api/auth";
import Teams from "@/api/teams";
import Notifications from "@/api/notifications";

export default (context, inject) => {
 if () {
  const token = ("token");
  // Set token when defined
  if (token) {
   context.$(token, "Bearer");
  }
 }
 // Initialize API repositories
 const repositories = {
  auth: Auth(context.$axios),
  teams: Teams(context.$axios),
  notifications: Notifications(context.$axios)
 };
 inject("api", repositories);
};
export default $axios => ({
 forgotPassword(email) {
  return $axios.$post("/auth/password/forgot", { email });
 },

 login(email, password) {
  return $axios.$post("/auth/login", { email, password });
 },

 logout() {
  return $axios.$get("/auth/logout");
 },

 register(payload) {
  return $axios.$post("/auth/register", payload);
 }
});

In this way, I can easily call them in components or Vuex operations, as follows:

export default {
 methods: {
  onSubmit() {
   try {
    this.$(, );
   } catch (error) {
    (error);
   }
  }
 }
};

6. Use $config to access environment variables (especially useful in templates).

Some global configuration variables are defined in the project:

config
├── 
└── 

I usually get it using this.$config, especially when I'm in a template. As always, it's very easy to extend Vue objects:

// NPM
import Vue from "vue";

// PROJECT: COMMONS
import development from "@/config/";
import production from "@/config/";

if (.NODE_ENV === "production") {
 .$config = (production);
} else {
 .$config = (development);
}

7. Obey a commit naming rule.

During the process of project development, it is often necessary to pay attention to the change history of components. If someone on the team doesn't follow the commit convention, it will be difficult to understand what they are doing.

I always use and recommendAngular commit message guidelines. I use him in all my projects and usually others on the team find his benefits.

Adhering to these rules makes commit more readable and makes commit easier to track when viewing project history. In short, he used it like this:

git commit -am "<type>(<scope>): <subject>"

# Here are some samples
git commit -am "docs(changelog): update changelog to beta.5"
git commit -am "fix(release): need to depend on latest rxjs and "

Look at theirsREADME fileUpdated more.

8. Always freeze the version of Package in production environment.

I know...all packages should followthe semantic versioning rules.. But this is not the case. 😅

To avoid a dependency affecting the entire project being dragged up in the middle of the night, freezing all package versions can make you sleep until dawn and have a happy job. 😇

This is simple: Avoid versions starting with ^:

{
 "name": "my project",

 "version": "1.0.0",

 "private": true,

 "dependencies": {
  "axios": "0.19.0",
  "imagemin-mozjpeg": "8.0.0",
  "imagemin-pngquant": "8.0.0",
  "imagemin-svgo": "7.0.0",
  "nuxt": "2.8.1",
 },

 "devDependencies": {
  "autoprefixer": "9.6.1",
  "babel-eslint": "10.0.2",
  "eslint": "6.1.0",
  "eslint-friendly-formatter": "4.0.1",
  "eslint-loader": "2.2.1",
  "eslint-plugin-vue": "5.2.3"
 }
}

9. Vue virtual scrollbar should be used when displaying a large data.

When displaying multiple rows in a page or when you need to loop through a large amount of data, you have noticed that the page renders very quickly and slowly. To resolve this issue, you can usevue-virtual-scoller

npm install vue-virtual-scroller

It renders only visible items in the list and reuses components and dom elements to make it as efficient as possible. It's so simple like a magic! ✨

<template>
 <RecycleScroller
  class="scroller"
  :items="list"
  :item-size="32"
  key-field="id"
  v-slot="{ item }"
 >
  <div class="user">
   {{  }}
  </div>
 </RecycleScroller>
</template>

10. Track the size of third-party packages

When multiple people work together for a project, if no one pays attention to the number of dependencies installed, it will quickly become unbelievable. In order to avoid slowing down the program (especially in mobile network environments), I use this VSCimport cost packageThis way you can see in the editor how big the imported package is and find out why it is big.

For example, in a recent project, the entire lodash library was imported (24kB after compression). Any questions? Just use the cloneDeep method. The problem was found through the import cost package, and we solved it by:

npm remove lodash
npm install 

Import in the place where you use:

import cloneDeep from "";

For further optimization, we can also use the Webpack Bundle Analyzer package to visualize the size of the Webpack output file through a dendrogram.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.