Best Practices for Vue Developers in 2021
Vue JS is famous for its innovative JavaScript framework that enables us to build responsive, high-performing, feature-rich, and beautiful frontends. Additionally, Vue equips developers with the power to create a wide range of powerful web applications with its single-page apps (SPA) and server-side rendering (SSR) capabilities.
In this article, we’ll explore some of the best practices every Vue developer should adopt to help us write quality code, become better developers, and build better applications.
Audit Packages Regularly
It's not new knowledge that third-party packages can introduce security vulnerabilities into our applications. Auditing these packages regularly to find and fix any vulnerabilities ensures that our applications remain secure.
- Every Vue developer should have a dependency audit process (DAP) checklist deployed in their projects.
-
To audit dependency packages:
- Check for vulnerabilities with npm audit. This command will produce a report of dependency vulnerabilities and, if available, suggested patches.
- Review the audit report and run recommended commands like npm audit fix, or investigate further and manually fix vulnerabilities if needed.
- Check for outdated packages with npm obsolete and try to update them with the npm update command.
Organize HTTP Requests Using the API Module Pattern
Let’s imagine we’re building a shopping cart app. We’d have to make a lot of HTTP requests to get data from API endpoints. While it's not wrong to bundle all that code inside a component, it’s better to abstract HTTP requests by modularizing them with the API module pattern.
Abstracting HTTP requests ensures that the UI component focuses on the UI rather than business logic. Eventually, as the lines of codes expand, the codebase does not get too complex.
The API module is a JavaScript module that has all HTTP logic categorized by resource. In our app, our resources are Product, Cart, Orders, and so on. For example, say we wanted to display all the products in the cart. We’ll begin by creating an API directory and add a product.js file. Here’s how the API module looks:
//api/product.js
export const async fetchProducts = () => {
const response = await axios.get("/api/products");
return response;
}
//api/product.js
export const async addToCart = (itemId, qty) {
const payload = JSON.stringify({ itemId, qty });
const response = await axios.post("/api/cart", {
body: payload
});
const body = await response.json();
return body;
}
Next, we import the modules both modules into components:
//~/components/AllProducts.vue
import {fetchProducts, addToCart} from '~/api/product.js'
const getAllProducts = () => {
try {
const response = fetchProducts()
....
}
catch {}
}
const createNewProduct = () => {
try {
const response = addToCart()
}
catch {}
}
Use JSDoc to Document API Endpoints
JSDoc is an open-source API documentation generator that allows us to document our code using comments.
Documenting API endpoints is crucial as it makes everybody's lives easier. It decreases the amount of time (and confusion) spent on understanding how the API works and deciphering unexpected errors when old and new team members alike use it.
While JSDoc isn’t the only documentation tool out there, it's open-source, deeply integrated, and supported by popular code editors like VS Code. To add JSDoc to our project, install JSDoc as follows:
//bash
npm install --save-dev jsdoc
Next, create a jsdoc.json file and add these lines of code:
//jsdoc.json
{
"source": {
"include": [ "src/", "api/" ],
"exclude": [ "src/router" ]
},
"opts": {
"template": "node_modules/docdash",
"encoding": "utf8",
"destination": "./docs/",
"recurse": true,
"verbose": true
}
}
Then, modify package.json to look like this:
//package.json
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"generate:doc": "jsdoc -c ./jsdoc.json",
},
Use comments to document the JavaScript.
// api/product.js
/*
*Add product to cart
* @param itemID {String} is the id of the product
* @param qty {Number} is an integer depicting the quantity of products
* @returns {object}
*/
export const async addToCart = (itemId, qty) {
const payload = JSON.stringify({ itemId, qty });
const response = await axios.post("/api/cart", {
body: payload
});
const body = await response.json();
return body;
}
Finally, generate a documentation page by running this command:
npm run generate:doc
This practice not only saves you a lot of time but also ultimately boosts your workflow.
Use Refs for DOM Manipulation
Performing DOM manipulation is not a good idea because Vue abstracts most of those things. However, if we must manipulate the DOM, then refs are the solution.
In Vue, refs is a special attribute used to register a reference to an element or a child component. One popular case is trying to add focus to an input element. Instead of targeting the element using vanilla JavaScript, use $refs
with this .$refs.input.focus()
.
//vuejs
const app = Vue.createApp({})
app.component('base-input', {
template: `
<input ref="input" />
`,
methods: {
focusInput() {
this.$refs.input.focus()
}
},
mounted() {
this.focusInput()
}
})
Refactor Big Components into Smaller Reusable Components
Reusable components are components that you can use anywhere in your application. As a result, they must be generic enough so that they are free from business logic. When planning component organization, you should consider reusable components.
When we repeat code too much in JavaScript, we refactor it to become a function so it becomes reusable, right? In Vue, when a component becomes too big, we should refactor it into smaller reusable components. Doing this saves time, makes the project more readable and maintainable.
Steer Clear of Cross-site Scripting Mistakes
Cross-site Scripting attacks the data integrity of trusted websites and applications by injecting malicious code into the webpage. If we allow HTML, JavaScript, or CSS code to execute impure, user-provided content, we might be opening our projects up to attacks.
Some common mistakes that Vue developers make that make our applications prone to XSS attacks include:
- Using v-HTML for rendering text. Instead, use as many interpolated expressions {{}} as you can. The browser can’t execute anything in {{}} because they are ordinary strings. But, if you ever must use v-HTML, ensure to parse the string and escape characters.
- Using third-party UI libraries that use v-HTML to render data passed through props. To ensure you sanitize your HTML, use vue-sanitize — a whitelist-based HTML sanitizer (sanitize-HTML) for Vue.js apps.
Don’t Rely Heavily on Third-Party Libraries
When it comes to personal security, we're wary of inviting a stranger into our homes because we don't know their backgrounds, who they are, or what they’re capable of doing. It should be the same with our codebase. For example, we shouldn't install a library to parse strings when we can write our own custom directive or plugin or instance property (try not to pollute the global scope).
This practice works in tandem with the previous one because most of these packages contain malicious code that can mess up our project. Reducing dependence on third-party UI libraries also boosts the performance of our frontend.
The point here isn't to avoid using third-party libraries. It’s to make sure the functionality provided by the library is something that we do need and can’t write on our own — for example, date and time parsers.
Before adding a third-party library to our project, we should write a pros and cons list. If the pros are more significant than the cons, we must confirm that the package does not open our application to security or technical risks.
To confirm that the package doesn’t open our application to security or technical risks, begin by checking the last published date, weekly downloads, and collaborators' profile of the library to ensure they indicate active maintenance. Then, test the package for security vulnerabilities with the Synk open-source security testing tool. After that, check the performance cost of adding that library to our project using the bundlephobia tool. If all these checks yield negative results, then we should consider alternative tools.
Use Kebab Case for Custom Event Names
This is probably the most overlooked practice when writing Vue. Even though event names are not case sensitive, it’s best practice to use the kebab case. This is because the listener event name’s casing must match the emitter event name casing.
Smashed-up lower-case names work fine, but they are less readable than kebab case. Also, do not use camel case for event naming because an emitted event named this <.$emit(myAge)> is not going to work if your listener event name is in kebab case like this <component> v-on:my-age="tell my age"> <component>.
The thing about following best practices is that they are easy to forget or overlook. That's why eslint is very important in any Vue project. We can use the vue/custom-event-name-casing eslint plugin to enact a style for custom event name casing for consistency purposes.
Include Keys in v-for Components
By default, if you use VS Code and Vetur (the official tooling extension for VS Code), you get error messages when you don't include a unique key in a v-for element. This is a priority rule with Vue.
The <:key> attribute helps Vue's virtual DOM better identify each element on the list or the difference between an older node list and a newer one. The most common use case is with list rendering, especially when mapping an array to elements with v-for.
//vue
<ul id="football-example">
<li v-for="footballer in footballers" :key="footballer.id">
\{{ footballer.name }}
</li>
</ul>
If you don't use VS Code and Vetur, the eslint plugin vue/require-v-for-key will assist in reporting the elements which have v-for and do not have <v-bind:key> except for custom components.
Validate Props with Custom Validators
A common rule in programming is to write predictable code. Predictable code means that our code is easy to understand by just reading it. Writing a custom props validator is one of the ways of achieving code predictability in Vue. It’s essential that when there's data communication between components or any two entities, they should validate that data to gain expected behavior.
Vue natively implements prop data security by providing type checking, validation, default values, and constraints to props. So why all this fuss about prop validation if they are type checks and default values? User behavior isn't predictable. That's why validating props, writing type checks, constraints, and default values ensure that we have a robust defense against malicious attacks and unpredictable edge cases. One typical case is when an object finds a way to bypass our type checks.
A custom prop validator is a function that accepts the value as input and returns a Boolean as validity status. Let's go through an example where we use a validator to check if a user isn’t from Nigeria.
//childComponent.vue
<template>
<div>\{{ userInfo }}</div>
</template>
<script>
export default {
data: () => ({}),
props: {
userInfo: {
type: String,
required: true,
validator: val => val.location != "Nigeria"
}
}
};
</script>
//parentComponent.vue
<!-- Caller -->
<template>
<div>
<PropReceiverComponent :userInfo="user"></PropReceiverComponent>
</div>
</template>
<script>
import PropReceiverComponent from "~/components/PropReceiverComponent";
export default {
data: () => ({
user: {
location: "Nigeria"
}
}),
components: {
PropReceiverComponent
}
};
</script>
Conclusion
Newbie Vue developers should be pragmatic — just make things work and refactor in the future. But, as time goes on, the responsibilities start growing, and then developers must be concerned with design patterns, performance, test automation, accessibility, and so on. Maintaining best practices improves our code quality.
Rules like using a unique key in v-for components are mandatory because it's an essential Vue code practice. Other rules such as auditing packages regularly, reducing the use of third-party libraries, and avoiding XSS mistakes are vital to your project's security. You can learn more about these rules using the Vuejs Style guide.
Also, if you're ever working on an enterprise Vue project that requires you to implement robust reports, spreadsheets, charts, and tables, you don't have to build from scratch anymore. GrapeCity (with over 40 years of experience and expertise in this field) has the Vuejs tools you need to implement those features:
- Wijmo, which provides a collection of UI components and responsive data grids for Vuejs projects. You can learn how to use Wijmo's Vue components with your project here.
- SpreadJS, which is the world-leading UI library for building spreadsheets with over 500 Excel functions for your enterprise applications. You can learn how to integrate and use Spreadjs with your project here.
- DataViewsJS, which is a JavaScript data visualization tool that helps customize data presentation using different layouts, row templates, data fields, calculations, and editing modes, that are completely and easily customizable. You can learn how to integrate and use dataviewjs with your project here.
- ActiveReportsJS, which is a data visualization solution that offers developers the ability to customize report layouts and integrate the reports designer and components to your JavaScript project. You can learn how to integrate and use ActiveReports with your project here.
Be sure to check out GrapeCity’s Vue-compatible products, and drop any questions or suggestions on more best practices in the comments section below!