DEV Community

Albert Mulia Shintra
Albert Mulia Shintra

Posted on • Edited on

Be prepared to migrate your Vue app to Vue 3

Heya!

In this post, I would like to share my recent experience of trying out Vue 3 beta version, specifically regarding some caveats you might want to note if you are planning to migrate your existing Vue 2 application to the upgraded version, Vue 3!

The list below are going to help you to move towards Vue 3 best practices, and also to avoid some use-case in Vue 2 that you might going to have trouble with, if you're migrating to Vue 3.

Let's get it on!

lets get it on

Avoid using Vue Event Bus

Short summary: Don't use $on / $once / $off API since it'll be deprecated in Vue 3.

If you have heard of Event Bus, it's a common term used in the Vue development whenever you're facing a situation where you need to make a shortcut to emit event from a child to parent, or vice versa. You can simply search "vue event bus" in your browser, and you'll find a lot of article explaining it.

One thing to note is that, it's not the official method recommended by Vue 🤯. Why I'm saying this, it's because you'll likely never see Event Bus mentioned in the official Vue docs. The closest reference is from the migration guide from Vue 1.x, in which it's called "eventHub" there, and it recommends you to use Vuex instead.

This pattern can serve as a replacement for $dispatch and $broadcast in simple scenarios, but for more complex cases, it’s recommended to use a dedicated state management layer such as Vuex.

You can check the RFC docs as well to see why they don't recommend it.

Since Event Bus concept is practically a Publish-Subscribe pattern which is a common method in programming, you can actually still use the concept, but with different libraries like mitt. 😉

This is the example of Event Bus, and how to refactor it:

// Vue 2 example of event bus
import Vue from 'vue';
const eventBus = new Vue();

// subscribe
eventBus.$on('sandwich-made', () => console.log('sandwich made!'));

// publish
eventBus.$emit('sandwich-made');
Enter fullscreen mode Exit fullscreen mode
// Refactor to use 3rd party library like mitt
import mitt from 'mitt';
const eventBus = mitt();

// subscribe
eventBus.on('sandwich-made', () => console.log('sandwich made!'));

// publish
eventBus.emit('sandwich-made');
Enter fullscreen mode Exit fullscreen mode

Refactor your Filter functions to Method

Based on the RFC docs, filter are going to be removed.

Filter was there to help you "format" your value, for ex: to uppercase, add currency, short url, etc. Perhaps it's also inspired by Angular Filter. It looks nice since you can implement it in your template syntax. For example, here's a filter toCurrency to add currency format to the price integer value:

<div class="currency">{{ price | toCurrency }}</div>
Enter fullscreen mode Exit fullscreen mode

note: price value is 25, then filtered by toCurrency to $25.00

Although it looks nice, keep in mind that it's practically a "syntax sugar" since in the runtime, it will always run toCurrency to format the price whenever it's updated.

If you refactor toCurrency as a method instead, it'll be written like this:

<div class="currency">{{ toCurrency(price) }}</div>
Enter fullscreen mode Exit fullscreen mode

The refactor in your Vue script is simply to move the function from filter to method:

// before
{
  filter: {
    toCurrency (value) {
      return `$${value.toFixed(2)}`
    }
  }
}

// after
{
  methods: {
    toCurrency (value) {
      return `$${value.toFixed(2)}`
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cool! But, what if the filter is registered as a global filter?

Vue.filter('toCurrency', function (value) {
  return `$${value.toFixed(2)}`
})
Enter fullscreen mode Exit fullscreen mode

In this case, I will recommend you to delete the global filter code above, and move your filter function to become a pure helper function first that can be shared. For example:

// helper/filter.js

export function toCurrency (value) {
  return `$${value.toFixed(2)}`
}
Enter fullscreen mode Exit fullscreen mode

And then, you can import the helper function to whenever component that needs to use it. For example:

// price-component.vue
import { toCurrency } from './helper/filter'

// your vue object
{
  methods: {
    toCurrency 
  }
}
Enter fullscreen mode Exit fullscreen mode

note: just toCurrency will work ;) thanks to ES6 object property shorthand

Refactor your component model into .sync

Based on the RFC docs, Vue 3 will deprecate the model option in the Vue component, and it will replace sync to become multiple model.

If you have used model option in your component to set two-way data binding, you can refactor it to become .sync instead. Here's the example:

// BEFORE

// parent component
<child-component v-model="visible"/>

// the model option in the child component's Vue object
<script>
{
  model: {
    prop: 'visible',
    event: 'change'
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Refactor it to use .sync:

// AFTER

// parent component
<child-component v-bind:visible.sync="visible"/>

// delete the model option in the child component's Vue object
Enter fullscreen mode Exit fullscreen mode

When the time comes for you to upgrade to Vue 3, you can simply rename the .sync to v-model instead:

// Vue 3

// parent component
<child-component v-model:visible="visible"/>
Enter fullscreen mode Exit fullscreen mode

Easy peasy lemon squeezy! 😋

Be wary of using 3rd party plugins

The beauty of Vue framework like other framework is, it provides API for community to create their own plugin.

But in Vue 3, there will be a breaking changes that will make some plugins not compatible anymore. One major change is, the Plugin installation and app initialization will be immutable from the original Vue instance. For example:

// BEFORE, in Vue 2
Vue.use(myPlugin);
new Vue({/* your vue initialization */});

// AFTER, in Vue 3
const app = createApp(); // new method to initialize Vue
app.use(myPlugin); 
Enter fullscreen mode Exit fullscreen mode

It's most likely that you will not able to refactor your code to use the plugins in the Vue 3, until the author of the plugin upgrades it. So this means, you should be considerate of using the 3rd party plugins if you're planning to migrate, as this will be the blocker.

Check the issue or roadmap of the plugins you're using, to see if they're planning to upgrade to support Vue 3. This is the example of the plugins that'll support Vue 3:

If your used plugins doesn't have the plan yet to upgrade to Vue 3, you can help to contribute by asking the author in the issue to support Vue 3, or even take part to help them upgrade. 🤗

Use @vue/composition-api to write your component

I really appreciate the Vue community for providing the @vue/composition-api 🥰. Not only it can be used for the developer to hands-on using the Composition API, but it also provide API that'll become the core method in Vue 3.

Take for example, defineComponent. It will become the new standard of writing a Vue component in Vue 3, and you can already use it in your Vue 2 app!

To use it, install @vue/composition-api and replace your Vue object component initiation. For example:

// BEFORE
import Vue from 'vue';

export default Vue.extend({
  name: 'my-component',
  /* your component props, data, methods, etc. */
});
Enter fullscreen mode Exit fullscreen mode

Simply replace it to use defineComponent:

// AFTER
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  name: 'my-component',
  /* your component props, data, methods, etc. */
});
Enter fullscreen mode Exit fullscreen mode

What's the difference, you ask? Practically no difference, and that's the beauty of it! Your component shall work the same as usual, and added with "bonus" that now you can already refactor your component to use Composition API if you want to:

// Refactor to use setup()
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
  name: 'my-component',
  setup (props) {
    /* your component props, data, methods, etc. */
  }
});
Enter fullscreen mode Exit fullscreen mode

note: if you love Typescript, I'm pretty sure you will love the composition API because it'll help to improve your component typing. ;)

What's More

There will be another breaking changes such as:

But if you're not using it much, and you believe it can be refactored easily, then it's up to you to decide if it shall be changed soon or later.

Summary

phew

Phew! I hope this article helps you to be prepared when the time comes to upgrade to the Vue 3. As a Vue developer, I know that I am excited to see it coming, since it uses better API to handle reactivity, more Typescript support, and better practices in the development.

If I missed any API or notes to be defined, please let me know and I appreciate your feedback. Thank you and have a great day!

Top comments (20)

Collapse
 
artofintel profile image
ArtOfIntel

Simple and useful, thx.
Where's the link to this "if you love Typescript,.... I'll write a separated article about it ;)" ?

Collapse
 
chenxeed profile image
Albert Mulia Shintra

Thanks for checking!

I'll post a new article in a few days, will share it here once I do!

Collapse
 
sonicoder profile image
Gábor Soós

Here is some Typescript love until the article :)

Just code examples, but it's more than nothing

Collapse
 
artofintel profile image
ArtOfIntel

Thanks

Collapse
 
chenxeed profile image
Albert Mulia Shintra

Fresh from the oven, thanks for asking!

dev.to/chenxeed/consider-vue-compo...

Collapse
 
nonary profile image
Nonary • Edited

Using composition API will break Vetur if you’re using the template interpolation feature (where it type checks the html and verifies bound properties exists)

In addition the Vue dev tools will crash significantly more often as it does not officially support the plugin.

So if you rely on that I’d recommend not installing the plugin.

Collapse
 
dotaitch profile image
Heena Kwag

Thank you for the great article! It was very useful for me 👍

I would like to ask you for permission to translate this article into Korean and publish it on a company run blog (ui.toast.com/). I will quote the source and in no way use it to gain any monetary value.

Please let me know what you think, and hope you have a great day :)

Collapse
 
chenxeed profile image
Albert Mulia Shintra

Hi, feel free to use this article! It's my honour 👍

Collapse
 
wormss profile image
WORMSS

And if you are using vue-property-decorator?

Collapse
 
chenxeed profile image
Albert Mulia Shintra • Edited

Ah, good concern! I missed to mention it in the article above, that the Vue Class Component is also in the discussion to be available in Vue 3. I think the issue below mentioned some breaking changes to be noted:

github.com/vuejs/vue-class-compone...

Collapse
 
wormss profile image
WORMSS

Wow, the example given looks really weird with watchers being external. We use vue-property-decorator which would do things like

import { Component, Ref, Watcher, Vue } from 'vue-property-decorator';
import NestedComponent from './NestedComponent';
@Component({ components: { NestedComponent }})
export default class MyClass extends Vue {
  @Ref()
  private someRef?: HTMLInputElement;
  private someData: string;
  private someComputed(): string { return window.localStorage.getItem('foobar') ?? '' }
  @Watcher('someData', { immediate: true })
  private onSomeDataChanged(newValue: string, oldValue?: string) {
    if(this.someRef) { this.someRef.focus(); }
  }
}

Just hope there are no super significant changes. We have over 925 *.vue files, all of them using vue-property-decorator

Thread Thread
 
chenxeed profile image
Albert Mulia Shintra

Yeah it'll be a hassle to migrate each of your vue files. Hopefully they don't deprecate the common interfaces in the new version for Vue 3.

Collapse
 
sonicoder profile image
Gábor Soós

Great writeup!

It's important that the v-model props and events are also changing along with the removal of the global Vue instance.

Collapse
 
sovai profile image
Sovai Kean

Very useful, thanks for the post!

Collapse
 
danielkun profile image
Daniel Albuschat

Thanks! I'll come back to this article when Vue 3 is out and it's time for us to upgrade. But it's good to know what to avoid in the meantime. 💯

Collapse
 
chenxeed profile image
Albert Mulia Shintra

Thank you for your feedback!

Collapse
 
klukiyan profile image
Kiril Lukiyan

I'll rather not do anything until Vue3 finally officially comes out. It seems to take forever.

Collapse
 
sonicoder profile image
Gábor Soós

It's just around the corner

Collapse
 
mzaini30 profile image
Zen

Thanks! I'll rewatch my code.

Collapse
 
chenxeed profile image
Albert Mulia Shintra

You're welcome! Hope it helps!