Vue Best Practices and Security
Last Updated on
Nov 21, 2024
Vue.js is a popular JavaScript open-source front-end building platform that is entirely capable of designing single-page applications. Using this language, Vue.js developers can use a single file component instance to build rich applications. For better performance, you can combine the codes with Vue.js. Vue.js framework offers advantages over architectures like Angular and React because of its lightweight nature and unique framework design principles.
Using our technical expertise and experience, we have curated some of the evolving best practices in this blog. Since Vue.js is becoming more and more favorable for developers in 2022, these quick tricks will help you to develop an effortless web application.
1. Vue.JS Best Practices
Here are the best practices for vue.js.
1.1 Always Use Key V-for With “: Key” Inside
- While we use the “key” attribute in the “v-for” directive section, it will always help the Vue app to be constant and the data can be manipulated whenever we want. It can also be used to identify the elements in a list that can be easily updated. An example of this “Keys” is the most used for HTML lists, animations, and Vue transitions.As an example, we can say without the use of the “:key”, DOM will not update the UI properly. It will get confused about which record to update when duplicate records exist in the list. So, if we want to update the last item from the list, the code will always update the first item if we don’t use the “:key”.
Let’s check it practically:
Example: Render List Without the Key
For the demonstration we made one list of computer parts with no IDs assigned. In the code, we have added one functionality where if you click on any part, it will delete it from the list.
<ul v-if="itemList && itemList.length > 0"> <li v-for="item in itemList" @click="deleteItem(item)">{{ item }} </li> </ul> |
- {{ item }}
Once we run the above code, we will see a list printed on the browser as shown below. Now let’s try to delete the last item (highlighted one from the below image) of the list.
When we click on that item, instead of deleting the last item from the list, it will delete the third item from the list. As both are duplicate records. So, it will delete the records that come first in the list. So, the output will be like the below.
Example: Render list with the key
<ul v-if="itemList && itemList.length > 0"> <li> v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ item }} </li> </ul> |
- v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ item }}
Once we click on the last item to delete, it will actually delete the last item with the key.
1.2 Always Use Kebab Casing for Events
- It is advisable to use a kebab case where you need to emit custom events. This takes place at the time of using shared components where the same syntax is used for broadcast as well as to listen to the event.
- when you use kebab casing for the custom events, it will be easy to identify which is a parent component.
Let see an example of kebab-case for event names which comes with component names:
Item Child Component:
// handle data and give it back to parent this.$emit('value-update', this.localValue) |
APP Parent Component:
<template> <div class="container"> <item :value="value" @value-update="handleData"></item> </div> </template> |
1.3 Use Pascal Case or Use Kebab Case for Components
- The best practices is to name a conventional component is by using a Pascal case or use kebab case. The most consistent attribute is the “Import attribute” which is irrespective of whichever project one chooses to work on.
# Avoid itemcomponent.vue || itemComponent.vue || Itemcomponenrt.vue # Good Practice ItemComponent.vue |
1.4 Keep npm Packages Updated
- As per Vue Style guide base components can only contain HTML elements, 3rd party UI components and other additional based components.
- Try to regularly update npm packages to avoid any dependency errors and to use the latest/updated features provided by individual packages.
- As an example, if you have configured vuetify the design patterns in the VueJS project, vuetify regularly updates its packages to provide the best UI including some breaking changes sometimes. So, it’s better to update NPM packages regularly to avoid bulky or breaking changes at a time of need. We also know about visual studio code- an inbuilt feature that supports base components.
npm outdated // run to check outdated npm packages npx npm-check-updates -u // run to check updates outdated npm packages npm install // run to update npm packages |
1.5 Manage Global File for Shared Variable
- To make the system more generic and easier to update anytime, manage global configurations (i.e. API URLs. Third-party URLs if any, keys can be used in any integrated tool, theme settings) or in a separate file (i.e environment.json). It will be helpful once your website is live to update any global configurations without any re-deployments.
1.6 Used Suitable Data Type Assign for Variable
- Continuously use proper data types instead of “any” to minimize the casting time and other casting errors.
- Avoid any casting inside the loops.
- In a case of two data types assigned to the same property, implement type casting using both the types and using conditions.
Example:
// Wrong const age: any = 0; [hard to identify response type at the places this variable used and also hard to track errors on assignments] // Right const age: number = 0; [easy to track and identify response type] |
1.7 Data Property Initialization
- It is recommended to initialize all the data properties that need to be reactive in advance in the data option.
- Vue.js constantly observes the change in data by recursively running through data parts.
- Use the Watch prop to get the latest values depending on another instead of creating multiple getters and setters. (Avoid the use of a watch inside the array of objects).
- Avoid memory leaks – remove custom events, instances, intervals when base components are destroyed.
1.8 Used a $refs
- Always used $refs to get results from DOM and try to minimize the use of JavaScript.
- Avoid the use of jQuery, instead, use typescript because typescript allows code rendering faster and to catch and rectify multiple problems at development time.of projects.
1.9 Do Not Mix v-if and v-for
- In Vue, You don’t use v-if on the same element as v-for. While Vue.js compiles the template, it checks all time v-if conditions. It is time-consuming. Instead, we can apply the V-if condition to the parent tag or template to achieve the same.
Let see one example,
<ul> <li v-if="itemList && itemList.length > 0"> v-for="(item, index) in itemList" :key="item.id" @click="deleteItem(index)"> { item }} </li> </ul> |
- v-for="(item, index) in itemList" :key="item.id" @click="deleteItem(index)"> { item }}
In the above code, we will be able to check if the condition resides in v-if all time while rendering the list or not.
<ul v-if="itemList && itemList.length > 0"> <li v-if="itemList && itemList.length > 0" v-for="(item, index) in itemList" :key="item.id" @click="deleteItem(index)"> {{ item }} </li> </ul> |
- {{ item }}
Here, v-if applied to ul tag, so the v-if condition will be checked only once before rendering v-for items.
Some of the undiscovered advantages of Vue.js rendering are
- Rendering is an efficient process because there is no looping for each item repeatedly.
- Every time you change the dependency, the filtered list gets re-evaluated.
- Rendering helps you differentiate the component logic from the template, which makes the component more readable in the user interface.
1.10 Vue Component Reusability & Communication
- From the Vuex store, you have access to all the reusable components and reusable code of Vue.js. Vue’s reusable component is very flexible to use. Try to make a common component with maximum required props and reuse it in all other pages. As an example, you can create common components for the confirmation messages. (You can pass dynamic confirmation text, button text, icons name, etc.). Same way confirmation you can create one component for add/edit functionality with the same model and bindings using the Vue component library.
- Data communication between parent and child components in Vue using “props” and “event emitter” is explained below. Once created, we can reuse the object across the single page application by adding required props and code in the component.
Example:
In parent component (App.vue):
<template> <div class="container"> <item :value="value" @onvaluechange="handleData"></item> <h3>Value(emitted from child-component): {{value}}</h3> </div> </template> <style scoped=""> .container{text-align: center;} </style> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import Item from "@/components/ItemComponent.vue"; @Component({ components: { Item }, }) export default class App extends Vue { private value: string = "Vue.js Application"; private handleData(data: string) { // get the data after child dealing this.value = data; } } </script> |
In Child Component (Item.vue):
<template> <div> <label>Enter Value: </label><input v-model="localValue" type="text"> <button class="save-btn" @click="submitValue">Save</button> </div> </template> <style scoped=""> .save-btn{margin: 10px;} </style> <script lang="ts"> import { Component, Vue, Prop } from "vue-property-decorator"; @Component export default class ChildComponent extends Vue { @Prop({default: ""}) private value: string; private localValue: string = ""; private mounted() { this.localValue = this.value // save props data to itself's data and deal with it } private submitValue() { this.$emit('onValueChange', this.localValue) // handle data and give it back to parent } } </script> |
For the custom components, we can use “v-model” to create two-way data binding without using props and event emitters.
Use “eventBus” in unrelated components for data communication.
1.11 Data Should Always Return Function
When you declare a Vue component data, that aspect of it should return a value. In other cases when it does not return an output, that information of data will be shared at all instances of the component value.
Example:
In the below Vue example, the functional data is not returning any output. So, you cannot access properties outside the data function. It will generate a runtime error.
data: { value: "Vue.js Application", itemList: [], counter: 0 }, |
Right Way:
data: function () { return { value: "Vue.js Application", itemList: [], counter: 0 }; }, |
1.12 Template Expressions Should Only have Basic JavaScript Expressions
In the Vue template, you applied more complex logic and some formatting variables like (date formatting). Let’s see the first example, we can see more complex logic in the template. What kind of issue we will face in the future.
<ul v-if="itemList && itemList.length > 0"> <li> v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ item.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }} </li> </ul> |
- v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ item.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }}
In the above example, some formatting is applied to the item value. As you can see in the list tag, it will increase the LOC (line of code). At a time of some complex formatting or functionality, these LOC will increase in the template which will be difficult to manage and will be more confusing. So, it’s better to separate the bindings by keeping formatting or extra login in some function in code.
Creating a separate function for formatting.
<ul v-if="itemList && itemList.length > 0"> <li> v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ normalizedItemValue(item) }} </li> </ul> |
- v-for="(item, index) in itemList" :key="index" @click="deleteItem(index)"> {{ normalizedItemValue(item) }}
private normalizedItemValue(value: string) { return value .split(" ") .map(word => { return word[0].toUpperCase() + word.slice(1); }) .join(" "); } |
In this “update” function example, we have added a new Vue function (normalizedItemValue) to manage UI formatting to make UI clean, easy to understand for developers, and easy to update.
The image shown below is an output of the entered item name that is displayed as the first character in the upper case.
1.13 Clean Code and Refactoring
- Use a shared/separate file for the static functions/properties for re-usability. It will be helpful to keep a shared/static code at the same file in the entire solution.
- Use eslint or tslint analysis tools to maintain code quality.
- In Vue, you can reduce the line of code by narrowing down the UI into smaller components.
- Use keywords (Const/Let) provided by typescript smartly instead of the var keyword of javascript.
Example:
Bad: var test: number = 0; “Identifier 'test' is never reassigned; use 'const' instead of 'var'” You will get the above error if tslint is configured properly when you run the project Good: const test: number = 0; // if static, use const let test: number = 0; // if updateable, use let |
Let’s see now common security best practices for Vue.js Application for pro developers
1.14 Define and Validate the Props
Undoubtedly, the most crucial best practices to follow are for Vuejs. If you ask me what its significance is then the answer is there are many reasons for this. It essentially protects the future you from the current you. It’s easy to lose track of the exact format, type, and other conventions you used for a prop when working on a huge project.
If you’re part of a larger development team, then you must communicate well, so as to make sure they understand how to use your components. So, please just provide prop validations. You need to avoid challenges and meticulously track all your components to ascertain a prop’s formatting. Check out this example from the Vue documentation.
props: { status: { type: String, required: true, validator: function (value) { return [ 'syncing', 'synced', 'version-conflict', 'error' ].indexOf(value) !== -1 } } } |
1.15 Components Declared and Used ONCE Should Have The Prefix “The”
If you don’t know what Single instance components are then let’s understand it as those used only once per page and do not accept props. These types of components have their own name scheme, similar to base components. These are components that are unique to your programme, such as a header, sidebar, or footer. For every component, there should only be one active instance.
TheHeader.vue TheFooter.vue TheSidebar.vue ThePopup.vue |
1.16 Consistency Using Directive shorthand
The usage of shorthand for directives is a predominant method among Vue developers.
For example, @ stands for v-on; : colon- stands for v-bind; and similar other definitions
Using these shorthands in your Vue project is a wonderful idea.
However, if you want to establish a project-wide standard, you should either use them all the time or never at all. Your project will be more unified and readable as a result of this.
1.17 Don’t Call a Method on Created AND Watch
For no reason, if you call a method that is created and then monitored is a common mistake Vue developers make (or maybe it was just me). The idea is that the watch hook should be called as soon as a component is initialised.
BAD!
created: () { this.handlePropertyChange() }, methods: { handlePropertyChange() { // stuff happens } }, watch () { property() { this.handlePropertyChange() } } |
Vue, on the other hand, offers a predefined in-built solution for this. It’s a feature of Vue viewers that we often overlook.
All we need to do now is reorganize our watcher and declare two properties:
- handler (newVal, oldVal) – here is the actual observer method:
- true – when our instance is created, our handler is called.
GOOD!
methods: {0 handlePropertyChange() { // stuff happens } }, watch () { property { immediate: true handler() { this.handlePropertyChange() } } } |
1.18 Use Actions: Commit the Data and Make API Call
Use Vuex actions to make the majority of my API calls because they make it so much easier to get data and provide a level of reusability and encapsulation. If I need to fetch the same web page from two separate locations, I can use the dispatcher and the appropriate parameters to fetch, commit, and return with no additional code than the dispatcher.
If we apply the same logic after the page has already been fetched, you’ll have to do it in one place to reduce server traffic. It will work best at all places. The ability to track activities in Mixpanel events is quite convenient, and the code base is simple to maintain.
1.19 Name Commits Using Single Convention Method
As the program reaches stability and matures, we’ll all be forced to look over the component’s history. If you or any of your team members do not use the same naming convention for their commits, it will be difficult to distinguish between them and comprehend what they do.
To make commits easier when browsing through the project history, follow the criteria stated below as one of the Vue js best practices.
Commit Message Format
< type >( < scope > ): < subject > < BLANK LINE > < body > < BLANK LINE > < footer > |
1.20 Multiple V-Condition
Using numerous v-if conditions to render multiple elements from a Vue component’s render method is not recommended. Wrap the elements with <div > and the extra ones with <template >.
< template v-if=“true” > < p >Paragraph 1 < / p > < p >Paragraph 2 < / p > < p >Paragraph 3 < / p > < / template > |
1.21 Code Splitting
Everyone knows that performance is of utmost importance. As it turns out to be more and more important, you must find efficient ways of code splitting. Async components like
Vue.component('async-component', (resolve) => { resolve({ template: '< div >Async Component< / div >', props: [ 'mypropVariable' ] }); }); |
Single file components
< template > < div >A sync Component < / div > < / template > < script > export default { props: [ 'mypropVariable' ] } < / script > This syntax for importing is even neater: new Vue({ el: '#app', components: { AsyncComponent: () => import('./AsyncComponent.vue') } }); Dynamic Module Loading export default { template: '< div >Async Component< /div >', props: [ 'mypropVariable' ] } You may try something like this; import AsyncComponent from './AsyncComponent.js'`; Vue.component('async-component', AsyncComponent); |
1.22 Routing
Client-side routing is the most prevalent method for creating SPAs.Vue does not come with built-in routing because it has an official plugin called VueRouter that is extremely straightforward to use and includes all of the features you’ll need to create a sophisticated application.If you’re using the VueCLI, you can add it to your app without using the npm-install Vue-router command.
1.23 Eliminate the DOM Access Directly
Avoid attempting to access the DOM directly, when programming on the Vue application at all costs. Instead, you should use $refs, I find it an ideal way to access the DOM, and it’s more maintainable and you are no more required to depend on specific class names.
1.24 Add Multiple Classes To an Element
One of the best things about Vue is it makes so convenient to add dynamic class to an element
//Add class red if isValidationError is true < div :class=”{'red': isValidationError}” >< / div > |
The common yet a unique approach
// Add to classes if two properties return true < div :class="{'red': isValidationError, 'text-bold': isSuccess }” >< / div > |
1.25 Use Selectors
The codes will better explain the concept
// We have this selector export const language = (state) => state.userConfig.language;// In one of our actions, we need language: // Bad [GET_LANGUAGE]({ commit, rootState }) { const languageSelector = rootState.userConfig.language; // Do stuff... } // Good [GET_LANGUAGE]({ commit, rootState }) { const languageSelector = language(rootState); // Do stuff... } |
2. Vue Application Security Best Practices
While developing an application using Vue.js, we’re mostly concerned about performance, SEO, API calls, and UI/UX, so the security of the existing application is often overlooked by the developers. There are thousands of malicious attacks that can happen from the frontend side, some of which are mentioned below:
- Unrestricted File Upload
- Clickjacking
- XSS Attack
- SQL injection
- A denial-of-service attack (DoS attack)
- Session hijacking
So to overcome this the best practices is to have collection of Vue.js best practices while developing web applications.
2.1 Enable XSS Protection Mode
In the case where an attacker hacks and inserts a malicious code in the user input, we can enable the “X-XSS-Protection”: “1; mode=block” header by preventing the response. The advanced browsers are well equipped with XSS protection mode were adding an X-XSS-Protection header is highly recommended. This gives an assurance to the old browsers on higher security concerns that do not support CSP headers.
2.2 Avoid Typical XSS Mistakes
An XSS attack is typically monitored in DOM API’s inner HTML section. Say for an example.
document.querySelector('.application').innerHTML = value; |
It is possible that the attacker can unknowingly insert a malicious code using the above line. So it is advisable not to set the inner HTML value-based on the user input. Instead of that, you can use textContent.
2.3 Use Captcha
You should always promote using captcha at the end-points where there is a larger audience to address for large-scale projects. Examples are login, registration or contact id. If you ask what is Captcha then A captcha is a computerized program or system that is designed to differentiate between humans and robots. It also prevents DoS (Denial Of Service) attacks.
2.4 Audit Dependencies Regularly
Auditing dependencies packages means checking if installed NPM packages are upgraded to the latest version or not.
Run npm audit commands regularly to audit packages. This command shows all outdated versions of packages and vulnerable packages and suggests upgrading packages to the latest version.
2.5 Use of Third-party Packages
The more you use third-party packages in your project, there can be security issues rising as vulnerabilities in open-source libraries. This will instigate hackers to do more fraud. While selecting Vue.js components from the package to integrate with the application, the expert Vue.js developer needs to check if the library is open source or not as lack of transparency poses a security risk, security best practices is where the library is well-documented, recommended, meets specific requirements, and is actively supported by the author.
2.6 Disable Our App to Load in an iframe
We should disable loading our app into the iframe. To restrict the rendering of a website in an iframe, you can enable the DENY option in X-Frame.
2.6 Displaying Generic Error Message for Authentication
While you are developing a user authentication form you must keep in mind certain factors. In your form, if the user enters the wrong password then a message is displayed saying “Your Password is incorrect”. This is not a good way because it helps an attacker to identify your email address or user id as valid and the password is wrong. Then the attacker starts a brute-force attack or dictionary attack to find the password for that user. That is no good for us. The solution is, you just display a message like ‘Incorrect login detail entered’.
3. Conclusion
With this, we have reached the end of the blog. We hope you found this insightful and will help you in maintaining best practices while developing apps using Vue.js. With our experience, we have curated these tricks and tactics that will help Vue.js developers to make code easily maintainable and accessible. Hopefully, these tips were useful to you because that is what we intended for your development project to be seamless and hassle-free. Cheers!
Share this Image On Your Site
Please include attribution to TatvaSoft.com with this graphic. <a href="https://www.tatvasoft.com/blog/vue-js-best-practices/"><img src="https://www.tatvasoft.com/blog/wp-content/uploads/2021/03/VueJS-Infographic.jpg" alt="VueJs Best Practices" width="952" height="3948"></a> |
View Comments
One of the major benefits of using vue is the reusability of code. By reusing the component developers are able to improve the code structure and can simplify maintenance and testing.
One best practice is to refactor big code into smaller reusable code in order to make it reusable, saving your time, and making the project more reliable and maintainable.
Using third party packages in your development project is a common practice but it can cause security issues or there may be bugs that can cause error or slow down your development process. So try to audit these packages on a regular interval to ensure the best code quality.
Many developers face the issues of not being able to keep the base component together. To solve this issue the best practices of naming base component can be adopted where by developers use a affix a like App, Base. It is completely up to you until you keep it constant in your project code.
Is Vue.js SEO friendly? And can it be used for Mobile app development
Vue.JS by default is not SEO friendly but, as a developer you must be knowing about the modules of Vue.JS that are SEO friendly and make use of them during your development process. Talking about mobile support since Vue.js is a web framework, it cannot support Mobile app development at its core or on its own.
Who founded Vue and for what purpose? Was there really a need for Vue?
Evan You is the person who founded Vue who is a former employee of Google. Evan liked Angular but the thing that he didn’t like was Angular being a heavy framework. So he created Vue that had all the good of Angular but he built Vue to be extremely lightweight.
What is Vue Good for?
Vue is good for startups as well as for building large-scale applications. Vue is simple and easy to learn, offers high-grade production-ready apps for Android and IOS. It can also be used for building Single Page Applications.
I was not sure if I wanted to implement any of the best practices but today as Vue has grown and become widespread, these best practices have become a standard. You have to implement them in your project to improve your chances of getting an effective app.
I was relying a lot on third-party packages for my development project and I was not sure if I was doing the right thing. But after reading the security best practices I came to know that it is not recommended. Really appreciate your work.
The Code splitting best practice is something I came across while I was reading the blog and it has helped me a lot in improving my site's overall performance. Thank you for this blog.