TB 1200x303 Blog Cover

In this blog post we will explore some tricky migration tips that will help you smoothly embrace Vue 3.

“I love the process of migrating to a newer version of our software” —said no developer ever.

In my career so far, I’ve performed several dozen migrations, despite knowing that migration often feels like this:

coyote

Vue.js 3.0.0 "One Piece" is marvelous, but a lot of developers still have yet to migrate to it. The Vue Core Team did a great job with the migration guide and are currently working on the migration build but one more resource is always helpful, so I decided to outline several not-well-known changes that I stumbled upon while migrating Kendo UI for Vue components.

I have chosen the trickiest cases for me—emitting events with native names, using render functions and mixins merges. Each one of these rare cases could help you catch a bug that could be easily missed during the migration process. In my next blog I will also share all the steps that need to be done for a common ‘Getting Started app’ while upgrading our actual “Kendo Vue - Getting Started” app from the Kendo UI Template Wizard.

Event Emitting with Native Names

I often use a folder with thin layer components around a button, input or even a div and have it ready to use in my app—I call these ones my little weapons. The tiny trap here is that I tend to emit events that have the same names as the native component, so that I can easily switch between them. Like in the code below:

<button @click="onClick" >One click</button>
<MyButton @click="onClick">Two Clicks</MyButton>

 In Vue 3, having this configuration will trigger the event twice as you can see in this editable example.

One possible way to fix this is by using the great brand new Vue 3 ‘emits’ option, as it is described in the documentation here, or just prevent the native event by declaring it as ‘null‘ that will only trigger the custom event. 

emits: {
  click: null
},
...

Using Render Functions

Remember my little weapons? Well, render functions, on the other hands, are like bazookas. They provide huge flexibility and need to be handled with care. Vue 3 brings on a huge change in the syntax, and the entire VNode props structure is flattened. Any change in such scenarios should be handled with special care because they could easily smash us with a rock:

// 2.x
{
  staticClass: 'button',
  class: {
      'is-outlined': isOutlined
  },
  staticStyle: {
       color: '#34495E'
  },
  style: {
       backgroundColor:
          buttonColor
  },
  attrs: { id: 'submit' },
  domProps: { innerHTML: '' },
  on: { click: submitForm },
  key: 'submit-button'
}
// 3.x Syntax
{
  class: [
    'button', {
  'is-outlined': isOutlined
  }
],
  style: [
    { color: '#34495E' },
    {
backgroundColor: buttonColor
}
  ],
  id: 'submit',
  innerHTML: '',
  onClick: submitForm,
  key: 'submit-button'
}

Another tricky thing here is the part when we use a render function with yet another component. In this case we need to define the children as function, this brings more performance because the props will be registered only as a dependency of the child components:

// slow
h(Comp,
{
// props/attributes
},
// array of children
this.$slots.default()
// fast
h(Comp,
{
// props/attributes
},
() => [
  this.$slots.default()
])
 

Example code - https://stackblitz.com/edit/yyyupr-pzu5ny

Mixins Merges

In the very beginning of Vue 2, mixins were really trendy and could be easily used for all kinds of application structure purposes. Vue 3 is a game changer for them because of the introduction of the Composition API. Even though some of mixins features are still supported, I would really recommend reconsidering their usage and migrating away from using them.

One scenario where things may break is mixing data merges. This can lead us to another ‘rock’ when, in the resulting component, the merged data options could be expected—but will no longer exist.

// mixin code
const Mixin = {
  data() {
    return {
      user: {
        name: "Jack",
        id: 1,
      },
    };
  },
};
export default {
  name: "HelloWorld",
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2,
      },
    };
  },
};
 

In such cases, the official Vue documentation recommends either:

  • Extracting the shared data into an external object and using it as a property within data, or
  • Rewriting the references to the shared data to point to a new shared object (as it is described here).

I really like how the setup function declares all the settings, so here is my first option for solving this with code:

// baseuser code
export default {
  user: {
    name: "Jack",
    id: 1
  }
};

setup() {
    const data = reactive({
      user: {
        id: 2,
        ...baseuser.user,
      },
    });
    return data;
 

Example here: https://codesandbox.io/s/immutable-hill-twofr

Lessons Learned

I have spent several weeks migrating all the Kendo UI for Vue components to Vue 3, and even more to migrate around 1000 examples! Even though I read all the change and migration guides carefully, I still often felt like this:

 theupgradeishere

That’s exactly why I decided to share these tips with you. If you know of other tricky parts, or if any of these tips were helpful for you, please share your case in the comments below or reach out via twitter @pa4oZdravkov.

Happy coding and happy migration!


Plamen Zdravkov
About the Author

Plamen Zdravkov

Plamen Zdravkov (@pa4oZdravkov) is a Principle Software Engineer for Kendo UI at Progress and is into the art of web development for over a decade now. He loves working with JavaScript and .NET web technologies and through the years took active part in the evolution of the Telerik ASP.NET AJAX, Kendo UI for jQuery and ASP.NET MVC component libraries—first as a Support Officer and later as a developer. Nowadays he leads the development of Kendo UI for Vue and Telerik UI for ASP.NET Core component libraries.

Related Posts

Comments

Comments are disabled in preview mode.