avatarEmil Hein

Summary

The article details the experiences and considerations of migrating a medium-sized Vue 2 application to Vue 3, including updates to UI frameworks, authentication, store management, charting libraries, and the adoption of the Composition API.

Abstract

The author shares insights into the decision-making process and execution of upgrading a Vue 2 application with 10-15 routes to Vue 3. The migration involved updating the UI library Vuetify, switching to the Vue 3 version of Auth0 for authentication, upgrading Vuex while minimizing global state, and transitioning charting libraries ECharts and Chartjs. A significant part of the migration was the rewrite of all components to utilize Vue 3's Composition API, which resulted in leaner code and reduced reliance on this. The article emphasizes the benefits of the migration, such as improved performance and APIs, and the streamlining of the application through refactoring and updating dependencies. The entire process took approximately 2-3 weeks.

Opinions

  • The author believes that migrating to Vue 3 is beneficial for applications expected to undergo frequent updates over a long period, as it future-proofs the application against outdated libraries.
  • The migration to Vue 3's Composition API was seen as an opportunity to reduce boilerplate code and make components more readable and maintainable.
  • The use of an ESLint plugin for Vuetify was considered helpful in the migration process.
  • The author suggests that a strategic approach to state management, favoring less global state, can be advantageous when migrating to Vue 3.
  • The decision to migrate to Vue 3 was made with the intention of leveraging Vue 3's performance improvements and better APIs.
  • The author recommends considering the size and complexity of the application when deciding whether to migrate, as well as the potential benefits of Vue 3's features.
  • The migration to Vue 3 was also an opportunity to refactor and improve the overall condition of the application.

The Vue 2 → Vue 3 migration story!

From 2 to 3

More and more people are facing the choice, between staying with their Vue 2 application or migrating to Vue 3. Both are fine for the moment, but many considerations have to be weighed when deciding.

I assume most newly started projects will be using Vue 3. But this is the story and learnings from the situation where a migration from Vue 2 to 3 was decided.

Preface

Our application was (is) a medium size application with 10/15 routes. We are using external libraries to do charting, authorization, UI elements, etc… Below are my thoughts on migrating each element.

I won’t dive too much into why we decided to migrate (since you’re properly here because you already decided), so let’s just dive into how the migration of the different parts was planned and executed and what benefits that offered us.

UI framework — Vuetify

Vuetify

By far the most time-consuming task in our project was to migrate the UI library from a Vue 2 version to the corresponding Vue 3 version. In our case, we had to migrate Vuetify. As the Vuetify components were spread all across the application, we more or less had to migrate all the non-compatible components (some components, didn’t need any change). Luckily for us, an ESlint plugin has been created to help the migration process when using Vuetify.

Key takeaway In the Vue 3 version of our application, we decided to have a smaller set of base components (button, card, selector, etc), that we reuse all over the application. We should arguably have done that, to begin with, but now it would be possible to switch to another UI library much much easier.

Authentication — Auth0

Auth0

For authentication, our application is using Auth0. This required us to do an update of the auth0 library. This is a crucial part of the application, even though it code-wise is not the biggest task. The logic was contained in one file, which made the migration relatively easy.

Key takeaway Authentication (and authorization) is a key element in many applications. Migrationwise, not much changed for this component and therefore it’s not so interesting migration-wise.

Store — Vuex

Vuex

Using Vuex as the store in our Vue 2 application, left us with a choice. Should we switch to Pinia (as recommended by Vue) or stick with Vuex and just upgrade the version? Having some experience with Vue 3 and the composition API, we could see that changing state (and relying on component models) would be quite a bit easier and less code-heavy than in Vue 2.

For these reasons, we chose to only upgrade Vuex (less work) and at the same time minimize the use of global state whenever possible.

In time Vuex will be outfaced, but in reality, it turns out we didn’t need as much global state management as initially used in the Vue 2 application.

Key takeaway The main point here is that we now keep less global state, due to the ease of sharing data in Vue 3. Migration to Pinia will be in the pipeline, but for now, this specific element remains more or less unchanged, to avoid more migration than necessary.

Charts — ECharts / Chartjs

Chart.js

Unfortunately for our migration adventure, we had included two charting libraries in our application. This means we had to migrate two libraries. Luckily for us, the use of charting in the application was relatively limited, so for the first migration, we chose just to migrate the few components more or less 1-to-1.

Key takeaway

We found a system (Embeddable), that in the future will allow us to integrate charts as a native component (but built in another system), that will allow us to fully detach the charting code with the application code, which will allow us to migrate the two separately in the future.

Composition API

Not only do all the 3rd party libraries need to be updated, but we might as well update all our components to use the newest Composition API. If your application is sufficiently large, it might be wiser NOT to update to the newer composition API, and do that in a subsequent step.

Our application contains about 100 “components” (.vue files). This was a number that made us decide that we could rewrite all of them. Once you start, it becomes easier and easier, since a lot of it, is simply syntax change.

<template>
  <div>
    <v-chip class="mx-2 mb-2" dark variant="outlined" label color="info" size="small"
      v-for="key in Object.keys(targeting)" :key="key">
      {{ key }} = {{ targeting[key] }}
    </v-chip>


    <v-row class="mx-4 my-4 mb-2" :key="index" v-for="(adunit, index) in Object.keys(unitTargeting)">
      {{ adunit }}:
      <v-chip v-for="key in Object.keys(unitTargeting[adunit])" :key="key" class="mx-2 mb-2" dark variant="outlined"
        label color="green" size="small">
        {{ key }} = {{ unitTargeting[adunit][key] }}
      </v-chip>
    </v-row>

    <v-row class="mx-2 mb-2" :key="index" v-for="(unit, index) in prebidTargeting">
      {{ unit.unit }}
      <v-chip class="mx-2 mb-2" dark variant="outlined" label color="orange" size="small"
        v-for="key in Object.keys(unit.targeting)" :key="key">
        {{ key }} = {{ unit.targeting[key] }}
      </v-chip>
    </v-row>
  </div>
</template>

<script>
export default {
  name: "targetingRow",
  props: {
    targeting: {},
    unitTargeting: {
      type: Object,
    },
    prebidTargeting: {
      type: Array,
    },
    loading: {
      type: Boolean,
    },
  },
  async mounted() { },
  data() {
    return {};
  },
  methods: {},
  computed: {},
};
</script>
<style lang="scss" scoped>
@import "@/styles.scss";
</style>

With the composition API, the above script part ends up looking like this

<script setup>
defineProps({
  targeting: {},
  unitTargeting: {
    type: Object,
  },
  prebidTargeting: {
    type: Array,
  },
  loading: {
    type: Boolean,
  },
})

</script>

In general, the Composition API seems more lean, with less code. You will find yourself using this a lot less, which I think will feel nice for many people. Ref and reactive are concepts one needs to get used to, but this is like any other new syntax (takes some time).

Key takeaway The rewrite to the composition API has mainly gone without too many bumps and the result is much “better” components, with less clutter and boilerplate code. The main reason for the whole migration was not only to get the updated version of some 3rd party library but also to get all the benefits that Vue 3 offers (performance, better APIs, etc.)

Conclusion

Whether you should do a migration or stay with Vue 2 depends a lot on your application and your future development plan. In the long run, most libraries will be outdated and it will be extremely hard to make any changes to the application. So if the application is meant to be updated frequently over a longer period of time, I would say it's a reasonable safe bet to start the migration now.

After migration, the application is arguably in way better condition, due to refactoring and updating/deletion of old dependencies.

Overall the full migration took about 2–3 weeks!

You might also like

Vuejs
Vue 3
Migration
UI
Software Development
Recommended from ReadMedium