Vue Options to Composition API Online Converter

kalimahapps

Kalimah Apps

Posted on May 24, 2023

Vue Options to Composition API Online Converter

If you are reading this, chances are you have old projects using Vue2 options API and you want to migrate it to Vue3.

One of the main features that were introduced in vue3 is composition API. It helps writing a code that resembles "regular" JavaScript functions.

While Vue team has provided backward compatibility for options API, it is still a good idea to migrate the code to get the benefit of the new features in Vue3 and have a more maintainable code.

However, many developers choose not to migrate for a multitude of reasons.

  • Migration might introduce new bugs to a rather working code (if the code is not broke don't fix it).
  • There is a learning curve required when rewrite the code with the new features.
  • Busy schedule. Most developers work on few projects simultaneously and do not have enough time for improving old code.

This is why I developed this online tool. It converts options API to composition API without much effort from the developers.

Click to see example
The tool can convert this code:
// https://github.com/gitlabhq/gitlabhq/blob/e6d048d769240760008f0dbb6b811e1ebc675292/app/assets/javascripts/ide/components/repo_tab.vue#L3

import { GlIcon, GlTab } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex';
import { __, sprintf } from '~/locale';

import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import FileStatusIcon from './repo_file_status_icon.vue';

export default {
  components: {
    FileStatusIcon,
    FileIcon,
    GlIcon,
    ChangedFileIcon,
    GlTab,
  },
  props: {
    tab: {
      type: Object,
      required: true,
    },
  },
  data() {
    return {
      tabMouseOver: false,
    };
  },
  computed: {
    ...mapGetters(['getUrlForPath']),
    closeLabel() {
      if (this.fileHasChanged) {
        return sprintf(__('%{tabname} changed'), { tabname: this.tab.name });
      }
      return sprintf(__('Close %{tabname}'), { tabname: this.tab.name });
    },
    showChangedIcon() {
      if (this.tab.pending) return true;

      return this.fileHasChanged ? !this.tabMouseOver : false;
    },
    fileHasChanged() {
      return this.tab.changed || this.tab.tempFile || this.tab.staged || this.tab.deleted;
    },
  },

  methods: {
    ...mapActions(['closeFile', 'updateDelayViewerUpdated', 'openPendingTab']),
    clickFile(tab) {
      if (tab.active) return;

      this.updateDelayViewerUpdated(true);

      if (tab.pending) {
        this.openPendingTab({ file: tab, keyPrefix: tab.staged ? 'staged' : 'unstaged' });
      } else {
        this.$router.push(this.getUrlForPath(tab.path));
      }
    },
    mouseOverTab() {
      if (this.fileHasChanged) {
        this.tabMouseOver = true;
      }
    },
    mouseOutTab() {
      if (this.fileHasChanged) {
        this.tabMouseOver = false;
      }
    },
  },
};

To this

import { GlIcon, GlTab } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex';
import { __, sprintf } from '~/locale';
import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import FileStatusIcon from './repo_file_status_icon.vue';
import { ref, computed } from 'vue';


// Data
const tabMouseOver = ref('false');

// Props
const props = defineProps({
    tab: {
        type: Object,
        required: true,
    },
});

// Computed
const closeLabel = computed(() => {
    if (fileHasChanged.value) {
        return sprintf(__('%{tabname} changed'), { tabname: props.tab.name });
    }
    return sprintf(__('Close %{tabname}'), { tabname: props.tab.name });
})

const showChangedIcon = computed(() => {
    if (props.tab.pending) return true;

    return fileHasChanged.value ? !tabMouseOver.value : false;
})

const fileHasChanged = computed(() => {
    return props.tab.changed || props.tab.tempFile || props.tab.staged || props.tab.deleted;
})


// Methods
const clickFile = function(tab) {
    if (tab.active) return;

    this.updateDelayViewerUpdated(true);

    if (tab.pending) {
        this.openPendingTab({ file: tab,
            keyPrefix: tab.staged ? 'staged' : 'unstaged' });
    } else {
        this.$router.push(this.getUrlForPath(tab.path));
    }
}

const mouseOverTab = function() {
    if (this.fileHasChanged) {
        tabMouseOver.value = true;
    }
}

const mouseOutTab = function() {
    if (this.fileHasChanged) {
        tabMouseOver.value = false;
    }
}


You can see the tool here: https://kalimah-apps.com/vue-options-to-composition

When you use this tool please remember that it does not cover all cases. It is useful to get you a step head and remove one hurdle from the code migrating process.

If you would like to contribute, report a bug or request a feature you can check the repo at GitHub:

GitHub logo kalimahapps / vue-options-to-composition

Online tool to convert vue2 options to vue3 composition API

Vue Options to Composition API Converter

Introduction

This is an online tool to convert Vue 2 options API code to Vue 3 composition API code.

Example

Input Vue 2 options API code:

export default {
    data:{
      items: [],
      list: {},
    },
  props: ['loading', 'lazy', 'disabled'],
  methods:{
    isLazy(){
      return this.lazy;
    },
    isLoading: function(){
      return this.loading;
    },
    isDisabled: () => {
      return this.disabled;
    }
  },
  watch:{
    loading(newValue){
      console.log("Value", newValue);
    },
    disabled:{
      immediate: true,
    handler(value) {
      this.bar = value;
    }
    }

  }
}
Enter fullscreen mode Exit fullscreen mode

Output Vue 3 composition API code:

import {
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
kalimahapps
Kalimah Apps

Posted on May 24, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related