DEV Community

Cover image for Vue Options to Composition API Online Converter
Kalimah Apps
Kalimah Apps

Posted on • Originally published at kalimah-apps.com

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

Top comments (0)