
This is a best practice I developed when working on Vue projects with a large code base. These tips will help you develop more efficient code that is easier to maintain and share.
In my freelance career this year, I had the opportunity to work on some large Vue applications. The project I'm talking about has more than 12 Vuex stores, a large number of components (sometimes hundreds) and many views (pages). In fact, it was a very meaningful experience for me because I found many interesting patterns to make the code extensible. I also had to fix some of the mistakes that led to the famous spaghetti code problem. ๐
So today, I'm going to share 10 best practices with you. If you want to deal with a large number of code bases, I suggest you follow these best practices.
1. Use slot s to make components easier to understand and more powerful
I recently wrote an article about some important things you need to know about slots in Vue.js. It highlights how slots make your components more reusable and easier to maintain, and why you use them.
๐ง But what does this have to do with the large Vue.js project? One picture is worth a thousand words, so I will draw a picture for you. This is the first time I regret not using them.
One day, I just need to create a pop-up window. At first glance, there is nothing really complicated, just including title, description and some buttons. So all I have to do is treat everything as an attribute. Finally, I used three properties to customize the component and issue an event when people click the button. Very simple! ๐
However, as the project developed, the team asked us to display many other new contents: form fields, different buttons (depending on which page to display), cards, footers and lists. I found that if I continue to use properties to expand this component, it seems to be OK. But God, ๐ฉ I was wrong! The component quickly became too complex to understand because it contained countless subcomponents, used too many properties, and emitted a large number of events. ๐ I've experienced a terrible situation where when you make a change somewhere, it eventually destroys the rest of the content on another page in some way. I made a Frankenstein monster, not a maintainable component! ๐ค
However, it would have been better if I had relied on slots from the beginning. Finally, I refactor everything to provide this widget. Easy to maintain, faster to understand and more scalable!
<template> <div class="c-base-popup"> <div v-if="$slots.header" class="c-base-popup__header"> <slot name="header"> </div> <div v-if="$slots.subheader" 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="$slots.actions" class="c-base-popup__actions"> <slot name="actions"> </div> <div v-if="$slots.footer" 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>
My view is that, based on experience, projects built by developers who know when to use slots do have a great impact on their future maintainability. This reduces the number of events emitted, makes the code easier to understand, and provides greater flexibility when displaying any required components internally.
โ ๏ธ As a rule of thumb, remember that you should start using slots from this point when you finally copy the properties of a child component in its parent component.
2. Organize your Vuex storage correctly
Usually, new Vue.js developers start learning Vuex because they stumble upon the following two problems:
- They either need to access the data of a given component from another component in the tree structure that is actually too far away, or
- They need the data to survive the destruction of the component.
That's when they create the first Vuex storage, understand the modules, and start organizing in the application. ๐ก
The problem is that the first mock exam module has no single mode to follow. But, ๐๐ผ I strongly recommend that you consider how to organize them. As far as I know, most developers like to organize them by function. For example:
- Verification Code
- Blog
- Inbox
- set up
As far as I am concerned, I find it easier to understand when they are organized according to the data model they extract from the API. For example:
- Number of users
- ranks
- Message content
- Widget
- article
Which one you choose is up to you. The only thing to remember is that well-organized Vuex storage will make the team more productive in the long run. It will also make it easier for newcomers to focus your ideas around your code base when they join your team.
3. Use Vuex Actions to call API and submit data
Most, if not all, of my API calls take place in my vuex actions. You might wonder: why is it better to call here? ๐คจ
Just because most of them extract the data I need to submit in the vuex store. In addition, they provide encapsulation and reusability that I really like. There are other reasons why I do this:
- If I need to get the front page of the article in two different places (such as blog and front page), I can call the appropriate scheduler with the correct parameters. The data will be extracted, submitted and returned without duplicate code except for the scheduler call.
- If I need to create some logic to avoid extracting it when extracting the first page, I can do it in one place. In addition to reducing the load on the server, I am confident that it can be used anywhere.
- I can track most of my Mixpanel events in these vuex actions, making the analysis code base really easy to maintain. I do have some applications where all Mixpanel calls are made separately in the operation. When I don't have to know what to track, what not to track, and when to send, ๐ How much happiness this way of working will bring to me.
Mixpanel is a data tracking and analysis company that allows developers to track various user behaviors, such as the number of pages viewed by users, iPhone application analysis, Facebook application interaction, and Email analysis. A buried point analysis tool similar to Firebase.
4. Use mapState, mapGetters, mapMutations and mapAction to simplify the code base
When you only need to access state / getters or call action/mutation inside a component, you usually do not need to create multiple calculated properties or methods. Using mapState, mapGetters, mapMutations and mapActions can help you shorten your code, simplify it by grouping, and master the whole situation from one place in your storage module.
// 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 => state.object.nested.property }) }, methods: { // Accessing actions ...mapActions("my_module", ["myAction"]), // Accessing mutations ...mapMutations("my_module", ["myMutation"]) } };
All the information you need on these handy helpers is available in the official Vuex documentation. ๐คฉ
5. Use API factory
I usually like to create a helper for this.$api that can be called anywhere to get the API endpoint. At the root of the project, I have a folder containing all the classes (see one below).
api โโโ auth.js โโโ notifications.js โโโ teams.js
Each node groups all endpoints of its category. This is how I use plug-ins to initialize this pattern in my Nuxt application (which is very similar to the process in a standard Vue application).
// PROJECT: API import Auth from "@/api/auth"; import Teams from "@/api/teams"; import Notifications from "@/api/notifications"; export default (context, inject) => { if (process.client) { const token = localStorage.getItem("token"); // Set token when defined if (token) { context.$axios.setToken(token, "Bearer"); } } // Initialize API repositories const repositories = { auth: Auth(context.$axios), teams: Teams(context.$axios), notifications: Notifications(context.$axios) }; inject("api", repositories); };
JavaScript for
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); } });
JavaScript for
Now, I can simply call them in my component or Vuex operation, as shown below:
export default { methods: { onSubmit() { try { this.$api.auth.login(this.email, this.password); } catch (error) { console.error(error); } } } };
JavaScript for
6. Use $config to access your environment variables (especially useful in templates)
Your project may have some global configuration variables defined in some files:
config โโโ development.json โโโ production.json
I like to access them quickly through the this.$config assistant, especially when I'm in a template. As usual, extending Vue objects is easy:
// NPM import Vue from "vue"; // PROJECT: COMMONS import development from "@/config/development.json"; import production from "@/config/production.json"; if (process.env.NODE_ENV === "production") { Vue.prototype.$config = Object.freeze(production); } else { Vue.prototype.$config = Object.freeze(development); }
7. Follow a convention to write submission notes
As the project evolves, you will need to periodically browse the submission history of components. If your team does not follow the same Convention to write their submission instructions, it will be difficult to understand the behavior of each team member.
I always use and recommend the Angular commit message guidelines. In every project I work on, I follow it, and in many cases, other team members will soon find it better to follow it.
Following these guidelines leads to more readable messages, making it easier to track submissions when viewing project history. In short, this is how it works:
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 zone.js"
Check out their README file for more conventions.
8. Always freeze the version of the software package when producing the project
I know... All software packages should follow semantic version control rules. But the reality is that some of them are not. ๐
In order to avoid damaging the whole project because one of your dependencies wakes up in the middle of the night, locking the versions of all software packages will reduce your morning work pressure. ๐
Its meaning is simple: avoid using 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. Use the Vue virtual scroll bar when displaying large amounts of data
When you need to display many rows in a given page or need to cycle through a large amount of data, you may have noticed that the page is rendered quickly. To solve this problem, you can use Vue virtual scoller.
npm install vue-virtual-scroller
It renders only the visible items in the list and reuses components and dom elements to make them as efficient as possible. It's really easy to use and smooth! โจ
<template> <RecycleScroller class="scroller" :items="list" :item-size="32" key-field="id" v-slot="{ item }" > <div class="user"> {{ item.name }} </div> </RecycleScroller> </template>
HTML for
10. Track the size of third-party packages
When many people work on the same project, if no one pays attention to them, the number of installed packages will increase rapidly, which is incredible. To prevent your application from slowing down (especially when the mobile network slows down), I used the import fee package in Visual Studio Code. In this way, I can directly see the size of the imported module library from the editor, and see what happens when the imported module library is too large.
For example, in a recent project, the entire lodash library was imported (about 24kB after compression). The problem is that only one method, cloneDeep, is used in the project. After identifying this problem in the imported fee package, we solved the problem in the following ways:
npm remove lodash npm install lodash.clonedeep
Then you can import the clonedeep function where needed:
import cloneDeep from "lodash.clonedeep";
JavaScript for
For further optimization, you can also use the Webpack Bundle Analyzer package to visualize the size of the Webpack output file through an interactive scalable tree view.
Do you have any other best practices when dealing with large Vue code bases? Please let me know in the comments below or contact me on twitter @ rifki Nada. ๐ค
About the author
Nada Rifki

Nada is a JavaScript developer who likes to use UI components to create interfaces with excellent UX. She specializes in Vue.js and likes to share anything that can help her front-end Web developers. Nada is also involved in digital marketing, dance and Chinese.
Article: Yujiaao
come from: https://segmentfault.com/a/1190000040712187
Translated from: https://www.telerik.com/blogs/all-you-need-to-know-about-slots-in-vuejs