Migrating a big old codebase to Vue 3: what I'm excited about
How big?
1289 .vue files
~230k rows of Vue code
502 Vue applications
How old?
Codebase is almost 8 years old
Vue first time used in 2016
Natalia Tepluhina
Staff Frontend Engineer
Core Team Member
Google Dev Expert
@N_Tepluhina
Performance
@N_Tepluhina
Functional components
return h('div', { class: 'js-line log-line' }, [
h(LineNumber, {
props: {
lineNumber: line.lineNumber,
path,
},
}),
...chars,
]
@N_Tepluhina
Functional components
functional: true
<template functional>
render functions
@N_Tepluhina
Functional components
"Performance gains from 2.x for functional components are now negligible in 3.x, so we recommend just using stateful components"
🎉
@N_Tepluhina
Mixins
@N_Tepluhina
Mixins
👎 Not really reusable
👎 Conflict-prone
👎 Unclear source
@N_Tepluhina
Mixins
import { formatDate, getTimeago } from '../../lib/utils/datetime_utility';
export default {
methods: {
timeFormatted(time) {
const timeago = getTimeago();
return timeago.format(time);
},
tooltipTitle(time) {
return formatDate(time);
},
},
};
@N_Tepluhina
Composition API
import { formatDate, getTimeago } from '../../lib/utils/datetime_utility';
export default function useTimeAgo() {
const timeFormatted = (time) => getTimeago.format(time)
const tooltipTitle = (time) => formatDate(time)
return { timeFormatted, tooltipTitle }
}
@N_Tepluhina
VueApollo
Options API
Apollo Components
Mixins for reuse
Composables
@N_Tepluhina
VueApollo - Options API
apollo: {
permissions: {
query: permissionsQuery,
variables() {
return {
fullPath: this.projectPath,
iid: this.issueIid,
};
},
update: data => data.project.issue.userPermissions,
},
},
@N_Tepluhina
VueApollo - Options API
import { useQuery, useResult } from '@vue/apollo-composable'
const { result, loading } = useQuery(permissionsQuery,
{
fullPath: this.projectPath,
iid: this.issueIid,
})
const permissions = useResult(result, null, data => data.project.issue.userPermissions)
@N_Tepluhina
VueApollo - Components
<apollo-mutation
#default="{ mutate, loading, error }"
:mutation="$options.destroyDesignMutation"
:variables="{
filenames,
projectPath,
iid,
}"
:update="updateStoreAfterDelete"
v-on="$listeners"
>
<slot v-bind="{ mutate, loading, error }"></slot>
</apollo-mutation>
@N_Tepluhina
VueApollo - Components
import { useMutation } from '@vue/apollo-composable'
const { mutate: deleteDesign } = useMutation(
destroyDesignMutation,
{
variables: {
filenames: this.filenames,
projectPath: this.projectPath,
iid: this.iid,
},
update: this.updateStoreAfterDelete
}
)
@N_Tepluhina
Multiple v-model
<gl-table
class="alert-management-table"
:items="alerts ? alerts.list : []"
:fields="$options.fields"
:sort-direction="sortDirection"
:sort-desc.sync="sortDesc"
:sort-by.sync="sortBy"
sort-icon-left
fixed
@row-clicked="navigateToAlertDetails"
@sort-changed="fetchSortedData"
>
@N_Tepluhina
Multiple v-model
<gl-table
class="alert-management-table"
:items="alerts ? alerts.list : []"
:fields="$options.fields"
:sort-direction="sortDirection"
v-model:sort-desc="sortDesc"
v-model:sort-by="sortBy"
sort-icon-left
fixed
@row-clicked="navigateToAlertDetails"
@sort-changed="fetchSortedData"
>
@N_Tepluhina
Multiple v-model
model: {
prop: 'entities',
},
v-model:entities="smth"
@N_Tepluhina
TypeScript
@N_Tepluhina
TypeScript
2 years
321 comment
No clear decision
@N_Tepluhina
TypeScript
import { defineComponent } from 'vue'
const Component = defineComponent({
// type inference enabled
})
@N_Tepluhina
TypeScript
const Component = defineComponent({
data() {
return {
count: 0
}
},
mounted() {
const result = this.count.split('')
// => Property 'split' does not exist on type 'number'
}
})
@N_Tepluhina
DevTools!
Thank you!
Migrating a big old codebase to Vue 3
By Natalia Tepluhina
Migrating a big old codebase to Vue 3
- 834