Migrate to VueJS 3, Composition API, and TypeScript?
For various reasons, many people are still using Vue 2 and have some doubts about migrating to Vue 3. Others are only thinking of trying Vue for the first time, and they don’t know which version to start with. In this article, we’ll try to explain how to start using VueJS 3 and the Composition API.
Another question that often raises concerns is whether you should use TypeScript at the same time. Or will it make it harder to master Vue 3?
Why Vue?
This is the main question for those experienced programmers who are just going to study front-end development, for beginners, as well as for skilled front-end developers from other frameworks. The key answer to this question is reactivity. Reactivity is a breath of fresh air, a revolutionary concept that has made the process of web development truly convenient. And Vue is a reactive framework. Why Vue? After all, there is also Angular and React? The thing is that Vue was released last, and it benefited from Angular and React’s mistakes and achievements. Well, it’s obvious that if you enter a project already written in React, then React is what you need. But if you start a new project, Vue is the best option. It is speedy, it is optimally written, it is easy to learn, and finally, it is quite harmonious. Previously, before the release of Vue 3, React was a rival to Vue in terms of technological effectiveness. But with the release of the Composition API and the new concept of Vue’s reactivity, this isn’t relevant anymore.
Is Vue 3 Ready for Real Projects?
The answer is yes. You don’t have to wait for the official announcement of the final release. The current, at the time of this writing, version 3.1.5, is quite sustainable and works great in many already running projects.
But there is one problem – not all accompanying developer tools are ready to use, and not all third-party libraries and plugins can support the Composition API and TypeScript.
The good news is that there is an efficient Vue Devtools Plugin that supports Vue 3 and is available for Chrome, although the Vue team may continue to finalize it.
Do I Need TypeScript?
The answer is yes. Just as reactivity has once become the best assistant for web developers, TS has become the best (of course, there are alternatives) JavaScript programming assistant. TypeScript makes your code more stable, predictable, and higher-quality. Some people even argue that using TypeScript reduces the number of tests or even makes them unnecessary. Yes, it will take some effort to move to TypeScript, but it’ll be worth it. Some people say that using TypeScript is the key to healthy and restful sleep. I agree with that.
How to Start?
A great Vue CLI tool solves any problems. The installation process for Vue 3 and TypeScript:
npm install -g @vue/cli
vue create dzone
cd dzone
npm run serve
Then move to the project directory and run npm run serve (built-in Dev server).
Open http://localhost:8080/ in your browser, and you’ll see an empty project with the Vue logo – that’s what you need.
Vue’s built-in Dev server is very easy to work with, as it displays all changes in your code on the fly. But when publishing, we will copy our ready-made scripts into a real server. Well, let’s talk about this in another article.
If you have a new project, start from scratch. And if you already have a project written in Vue 2, please copy its components into the project. Maybe you’ll have to change something, but your project written in pure JS and Vue 2 should also work in this configuration. You don’t have to change the old components that use the Options API – they will still work. Start writing new ones in Vue 3 and TypeScript.
Migrate to the Composition API
That’s quite simple, and there are a lot of articles dedicated to this subject. It is important to understand that the Composition API allows you to put some of the logic into separate modules. Your components won’t get bloated, and it will be easier to follow the principle according to which each component has a single functional responsibility. Your code will become drier. And it won’t take you much effort to migrate.
If you start Vue from scratch, there is no need to write in the old Options API, although you need to know it if you want to be able to read the old code.
The best source of information is https://v3.vuejs.org/guide/introduction.html. Vue is known for its clear and straightforward documentation, so there shouldn’t be any difficulties. By the way, there is also a Guide on how to migrate from version 2 to 3.
For studying, I would recommend https://vueuse.org. You can study its examples and learn something new, especially since it has a lot of TS code.
A new <script setup> syntactic sugar was recently introduced. It reduces boilerplate, i.e. you need to write fewer constructs. But in my opinion, beginners shouldn’t use it as this would make things even more complicated. As for me, I haven’t touched it yet. I believe this may cause certain difficulties. I think I’ll try it later.
What About Requests to the Backend?
That’s not difficult if you already have a running back-end server. I hope you remember that we were going to store configurations in separate files (in dedicated config files). Here is this kind of separate file – vue.config.js.
module.exports = {
pages: {
index: {
entry: 'src/main.ts',
template: 'public/index.html'
}
},
publicPath: '/',
configureWebpack: {
devtool: 'source-map'
},
devServer: {
proxy: {
'/api/*': {
target: 'http://my_backend.loc/',
changeOrigin: true
}
}
}
}
The devServer/proxy section is just needed to describe how to fetch data from the back end.
Thus, we see a web page at the Dev server URL, but we use a proxy to send requests to the back-end server.
Formatting With TS Support Enabled
The Vue CLI has already created two files for us:
.eslintrc.js:
module.exports = {
root: true,
env: {
node: true
},
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'@typescript-eslint/no-this-alias': ['off']
},
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/prettier',
'@vue/typescript',
'@vue/typescript/recommended',
'@vue/prettier/@typescript-eslint'
]
}
Pay attention to the rule – vue3-essential, eslint:recommended, typescript/recommended.
When you save a file, it will be automatically formatted. And if everything is written correctly, your IDE will please you with a green checkmark, which means that your file is free of errors.
As for me, I try to follow the manufacturer’s recommended settings and reduce the number of exceptions which, in turn, can be created both in these files and in code files. I trust Vue and TS developers and their recommendations.
Now your IDE will help you write in TypeScript.
Some individual preferences can be written in a prettier configuration file:
.prettierrc:
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid"
}
This way is more convenient for me, but it’s up to you. However, the main thing is that the whole team adheres to the same settings.
What About VUEX?
As for Vuex, you don’t need it. Create your modules and include them in the necessary components. Any application state data can be perfectly stored in modules.
The Vue Devtools Plugin can conveniently display state, so we are deprived of some benefits in terms of working with actions, but the state can still be seen in the component information. So, we don’t lose anything because we won’t have any actions.
TypeScript Is Not a Big Deal
To start writing in TS, you just need to include lang=“ts” in the component’s script tag, like this:
<script lang=“ts">
Then write as usual, in ECMAScript 2015+. Our linter and prettier will sometimes catch bugs. Read them carefully. Then read the TS documentation or advice from Stack Overflow to modify your code and fix bugs.
Also, you will often be advised to set the any type. Never do this. First of all, if you use any, you acknowledge your weakness, and secondly, you lose the advantages provided by TS. In my experience of working on a fairly large project, I never had to use the any type, and I could always find some other solution.
Sometimes it may happen that linter and prettier work great, but your browser and Dev server are fighting one another. So, you need to carefully study this. This is a different type of error. I don’t know for sure if these are compilation or transpilation errors. Gradually, you will understand how to avoid them.
What if you need to use JS code? No problem. To do this, specify “allowJs”: true in the tsconfig.json file.
If a component regularly uses a JS library, then it is possible to leave this component in JS. This component, along with TS components, won’t do any harm to your project.
Gradually, you will get a set of your own complex types, and you will be able to collect them into separate files and directories. Using a type usually causes no problems.
Declare:
export interface MyComplexType {
typeKey1: number
typeKey2: string
}
And apply:
const myFunction = (arg: MyComplexType) => { …. }
But when it comes to component properties, the following construction will be needed:
props: {
myComplexData: {
type: Object as PropType<MyComplexType>,
required: true
}
},
Of course, you will have to use PropType at the top:
import { defineComponent, PropType} from 'vue'
It is also very important to understand that TS cannot be used at runtime. Therefore, type checking becomes quite a challenge:
For example:
• we cannot refer to a function argument without confirming that it is an array.
export const phonesRule = (phoneList: Array<string> | unknown): boolean => {
if (!Array.isArray(phoneList)) return false
const goodList = phoneList.filter(item => checkPhone(item))
return goodList.length === phoneList.length
}
• we must check that an argument is an object, and it is also worth checking whether the object has the required key, but we know for sure that an object will certainly have it.
export const estateTypeIsZero = (estate: Estate | unknown): boolean => {
if (estate && typeof estate=== 'object') {
const estateType = (estate as Estate).type
if (estateType === 0) return false
}
return true
}
In both examples, the argument is either of that type we need or it is unknown, as this is required by a third-party library. If not for the unknown, the check would take less effort.
Another important aspect is that you can find ready-made types.
For example, the method code:
const fileChanged = (e) => { ... }
will raise an error because the event type is undefined. You need to either create a suitable type or find the one already described. In my case, the EventData type from the xstate library I used was fine:
import { EventData } from 'xstate'
and
const fileChanged = (e: EventData) => { ... }
started working without error.
Another very important concept is enum. Please study it and use it whenever required.
In general, you shouldn’t be afraid of TS. I’m sure anyone can learn it. What’s more, it is interesting and quite helpful. Of course, everything you can read in this article is written by a newcomer to TypeScript. I began studying it this year, so I apologize for any inaccuracies.
Work Stack Example
Below, I will provide a set of plugins/libraries which I use. They support the Composition API and TypeScript, as well as the latest version of Vue. So:
package.json
"dependencies": {
"@vuelidate/core": "^2.0.0-alpha.16",
"@vuelidate/validators": "^2.0.0-alpha.13",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-i18n": "^9.1.6",
"vue-router": "^4.0.8",
"xstate": "^4.19.1"
}
In general, the following third-party libraries are enough for me: axios, vue-i18n, vuelidate, and xstate.
Well, we know that axios is used to communicate with servers. It is an old and proven library. Although it is not written in TS, this does not prevent it from being used in a TypeScript project.
vue-i18n is a library for localization, and since we’re not in England, we really need it – https://github.com/intlify/vue-i18n-next
vuelidate is a form validation library, it is quite sophisticated and well-structured – https://github.com/vuelidate/vuelidate
xstate is a library for working with state machines. If you figure out how to work with it, you will significantly simplify your work – https://xstate.js.org.
All three of these libraries – vue-i18n, vuelidate and xstate support the Composition API and TypeScript. They are constantly updated and supplemented. I actively use all of them, and I can assure you that they are almost free from glitches. In short, they work great and don’t throw any curves.
So, that’s my final word on the subject. I hope this information helps someone.