I'm migrating an old codebase from Vue 2.6 with @vue/composition-api
to Vue 3.5.12.
I will provide my Vue 2 single file component below. Please respond with the
updated code. Your response will be saved to replace the old file (so do not include
comments or markdown formatting).
The codebase is written in Vue, Typescript 5, and Less CSS. If you have concerns during your conversion then include a comment like this:
// TODO: (reason for concern)
The Vue2 code returned a default export with a setup function that takes in props and returns the variables for the template:
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup(props) {
const count = ref(0);
return { count };
},
});
</script>
<script lang="ts" setup>
import { ref } from 'vue';
const count = ref(0);
</script>
Now props are defined using defineProps
with the typescript generic param...
<script lang="ts">
export default defineComponent({
props: {
message: String,
config: Object,
manager: Object as () => ISomethingManager,
},
setup(props) {
},
});
</script>
<script lang="ts" setup>
import { ref } from 'vue';
const props = defineProps<{
message: string,
config: any,
manager: ISomethingManager,
}>();
</script>
Now slot contents are accessed via useSlots
.
<script lang="ts">
export default defineComponent({
setup() {
const elContent = getCurrentInstance()?.slots.default?.()?.[0]?.el;
},
});
</script>
<script lang="ts" setup>
import { useSlots } from 'vue';
const slots = useSlots();
const elContent = slots.default?.()?.[0]?.el;
</script>
Technically, Vue 3 does not allow exports within the setup
script. I will
fix these issues later, so do not move exports into a separate script tag.
In Vue 2 reactive(...)
mutates the original object.
In Vue 3 reactive(...)
returns a new object (so the original object must no longer be used).
If the target object for reactive
comes from the same scope then simply call reactive
on the initial declaration.
Important: If the target is from a different scope (such as a prop, function param, etc)
then I need to review it SO ADD A // TODO: ...
comment!
<script lang="ts">
import { reactive } from 'vue';
export default defineComponent({
props: { manager: Object },
setup(props) {
const obj = { foo: 'bar' };
reactive(obj);
const settings = reactive(manager.settings);
return { obj, settings };
},
});
</script>
<script lang="ts" setup>
import { reactive } from 'vue';
const props = defineProps<{ manager: any }>();
// TODO: review `props.settings`
const settings = reactive(props.settings);
const obj = reactive({ foo: 'bar' });
</script>
In Vue2 we sometimes used a special version of defineComponent
which
received a page
parameter. In Vue3 we no longer use defineComponent
and the page
parameter should be removed.
<script lang="ts">
import { defineComponent } from 'src/router/app-page';
import { wwwPublicSchoolsPage } from "./page.routes";
export default defineComponent({
page: wwwPublicSchoolsPage,
setup(props){
return { count: ref(0) };
},
});
</script>
<script lang="ts" setup>
const count = ref(0);
</script>
Vue 2:
Vue.prototype.dayjs = dayjs;
Vue 3:
app.config.globalProperties.dayjs = dayjs;
Vue 2 usages of an instance's $children
, proxy
, etc need
a review from me, so just add a "CONCERN" comment.
As you know, there are some other considerations when migrating vue 2 to vue 3.
- Anytime an
ILayoutSettings
orIFaReportParams
object is declared, please wrap it with Vue'sreactive(...)
- Global API changes: Adapt to the new global mounting and configuration syntax, as Vue.createApp() replaces Vue.use() and Vue.component().
- Lifecycle hooks: Update component lifecycle hooks, as some have been renamed (e.g., beforeDestroy to beforeUnmount).
- v-model changes: Modify v-model usage, as it now uses modelValue prop and update:modelValue event by default.
- Render function API: Update render functions to use the new, more JavaScript-centric syntax without h function arguments.
- Component filters are no longer available. Replace filters with computed properties.
- Emits option: Use the new
defineEmits
option to explicitly declare emitted events. - v-for on a template tag should have the :key on the template tag and not on the child
- Transition classes: Rename transition classes from v- prefix to vue- for consistency.
- Custom directives API: Modify custom directives to use the new directive hooks API.
- Slots syntax unification: Update scoped slots syntax to use v-slot consistently, as the syntax has been unified.
- $listeners removal: Remove usage of $listeners, as it has been merged into $attrs and
useAttrs
. - Global and internal APIs: Adjust usage of Vue.extend, Vue.set, and Vue.delete, as they have been removed or modified.
- Do not modify code unless it is related to the migration. For example, no need to fill in missing Typescript types unless it relates to the migration.