Intro
At CodersRank we build our front-end with Vue.js. And with the recent release of Vue.js version 3 we decided to upgrade. Here, weβll cover what needs to be changed to migrate to the all new Vue.js based on our experience.
We have 2 main projects. One project is the large developers profile website and the other one is a smaller admin section. To start, we decided to migrate the smaller admin section to see how hard it is to migrate (spoiler: not hard).
So, let's start.
Init Vue App
Letβs start at the main app entrypoint script. Vue.js version 3 uses new Global API and requires a different approach to initialize the app:
In Vue 2 we had:
// Import Vue
import Vue from "vue";
// Import main App component
import App from "./App.vue";
// Init Vue app
const app = new Vue({
// element where to mount the app
el: "#app",
// render main component
render: (h) => h(App),
});
And in Vue 3 it is now:
// Import createApp function
import { createApp } from 'vue';
// Import main App component
import App from './App.vue';
// Init Vue app and pass main app component
const app = createApp(App);
// Mount app
app.mount('#app');
Vuex Store
If you use Vuex state management library, then it also needs to be updated to the latest version for Vue 3. And Vuex v4 also has new global API changes.
Let's look at how we use that and the init Vuex store in Vue 2:
import Vue from "vue";
// Import Vuex
import Vuex from "vuex";
import App from "./App.vue";
// Tell Vue.js to use Vuex plugin
Vue.use(Vuex);
// Create store instance
const store = new Vuex.Store({
state: {
/* ... */
},
getters: {
/* ... */
},
mutations: {
/* ... */
},
actions: {
/* ... */
},
});
const app = new Vue({
el: "#app",
render: (h) => h(App),
// pass store instance
store: store,
});
The same but in Vue 3 should be the following:
import { createApp } from 'vue';
// Import createStore function
import { createStore } from 'vuex';
import App from './App.vue';
const app = createApp(App);
// Create store instance
const store = createStore({
state: { /* ... */ },
getters: { /* ... */ },
mutations: { /* ... */ },
actions: { /* ... */ },
})
// Tell app to use store
app.use(store);
// Mount app
app.mount('#app');
Slots
In our Vue 2 app we were still using legacy slots API:
<some-component>
<h1 slot="header">Title</h1>
<p slot="content">Content</p>
</some-component>
It is required to be changed to a new one using <template>
tags:
<some-component>
<template #header>
<h1>Title</h1>
</template>
<template #content>
<p>Content</p>
</template>
</some-component>
v-model
v-model also has new syntax in Vue 3. For example, if in Vue 2 we had the following component:
<custom-input v-model="inputValue" />
<template>
<input :value="value" @input="onInput" />
</template>
<script>
export default {
model: {
// specify prop that will be modified by v-model
props: 'value',
// specify event that should be received by v-model with the new value
event: 'input',
},
props: {
value: String,
},
methods: {
onInput(e) {
this.$emit('input', e.target.value),
},
},
}
</script>
In Vue 3, by default, it expects that v-model should be bound to modelValue prop of the component and emit update:modelValue
event in order to update model value. So we have to change the component to the following:
<script>
export default {
props: {
// change "value" prop to "modelValue"
modelValue: String,
},
methods: {
onInput(e) {
// emit "update:modelValue" prop with new value
this.$emit('update:modelValue', e.target.value),
},
},
}
</script>
But also Vue 3 provides more control over it and we still keep the prop named value
. In this case we need to emit update:value event
:
<script>
export default {
props: {
// keep name as value
value: String,
},
methods: {
onInput(e) {
// emit "update:value" prop with new value
this.$emit('update:value', e.target.value),
},
},
}
</script>
And to let Vue know that we need model to be bound to the value
prop instead of the default modelValue
, we should use v-model
like this:
<custom-input v-model:value="inputValue" />
The best thing about it is that now components can have multiple v-model
s:
<some-component v-model:title="titleValue" v-model:content="contentValue" />
Composition API
Vue 3 comes with a new Composition API.
It is not necessary to change all your components to the new Composition API as Vue 3 still works perfectly with the current Options API. That is why we decided to keep it at the moment.
Custom Elements (Web Components)
At CodersRank we have a nice set of web components for developers to integrate on their personal websites. We also use them on our website:
It was not so straightforward to make Vue 3 understand them properly and not to think these are not Vue components.
In Vue 2 to specify custom elements, we used Vue.config.ignoredElements
import Vue from "vue";
Vue.config.ignoredElements = ["codersrank-activity", "codersrank-skills-chart"];
import Vue from "vue";
Vue.config.ignoredElements = ["codersrank-activity", "codersrank-skills-chart"];
In Vue 3 it is decided whether it is a custom element or not during template compilation phase, so it should be specified in webpack config Vue loader options:
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
options: {
compilerOptions: {
// ignore elements that starts with codersrank-
isCustomElement: (tag) => tag.indexOf('codersrank-') === 0,
},
},
},
},
TypeScript
Vue 3 has much better TypeScript support. And during the migration to Vue 3 all we needed to change was the component declaration in single-file components:
In Vue 2 we used `Vue.extend` to define the Vue component:
<template>
<!-- ... -->
</template>
<script>
import Vue from "vue";
export default Vue.extend({
props: {
// ...
},
data() {
// ...
},
// ...
});
</script>
And in Vue 3 we need to use the new defineComponent
function:
<template>
<!-- ... -->
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
props: {
// ...
},
data() {
// ...
},
// ...
});
</script>
Post Scriptum
In this article we have covered just the basics that we faced ourselves in our own project during migration from Vue.js 2 to Vue.js 3. Of course there are many things to pay attention to if you use other APIs, Vue features and plugins. Worth to mention:
- Official Vue.js 3 migration guide
- Official Vue Router migration guide for Vue.js 3 (in case you use Vue Router)
- New built-in Teleport functionality (if you used `portal-vue` plugin which is not yet supported for Vue.js 3)
- Composition API Reference
- Render function API changes
About CodersRank
Interested in learning more about how we help developers? Check out our website here & create your own profile!
Top comments (0)