## Vue 3 migration notes --- ### Stores file structure All stores are now placed in /stores instead of in each separate app. For example `/src/apps/Search/store.ts` is now `/src/stores/search/index.ts` --- ### Vue-file Converson Flow: * Install `eslint-plugin-vuetify`!! it will give hints on deprecated vuetify attributes 1. Use `vue-declassify Component.Vue` to convert the file * if it fails, try: 1. Cut any vuex Store/State decourators at the top of the component. Such as: `@RoutesStore.Action getRoutes: any` `@OnlineOrderStore.Action fetchCustomerInfo: any` 2. if there is a `created()` function, try cutting it and then putting it in manually inside <script setup>...</script> 3. Remove wrapping `Vue.Extends(...);` from default export 4. Remove any `@Emit ...` decorators since they can't be automatically converted 5. Remove access modifiers (so far only `private` before functions) 6. Remove return-types from functions (data, computed, watch) 7. Use https://tjk.github.io/vue-o2c/ 8. Fix remaining bugs.. :cry: ### vue-facing-decorator Lingering 'vue-facing-decorator' can safely be removed: ~~```import Component from 'vue-facing-decorator'```~~ --- ### v-slot:activator and v-on Before: <v-tooltip right> <template v-slot:activator="{ on, attrs }"> <v-btn v-on="on" :attrs="attrs" ... After: <v-tooltip right> <template v-slot:activator="{ props }"> <v-btn v-bind="props" ... --- ### Dependency changes * Before we used `vue-notification`, which only supports Vue 2.x For now I use `@kyvg/vue3-notification` instead which is *almost* a drop-in replacement. * Instead of `vue-clipboard2` we now use `@soerenmartius/vue3-clipboard. I have tried multiple alternatives, such as `vue-clipboard3` but typescript support is lacking. --- ### Path-aliases such as '@Search' Previously defined in `vue.config.ts`, now defined in `vite.config.ts`: export default defineConfig({ ... resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), '@Search': fileURLToPath(new URL('./src/apps/Search', import.meta.url)), }, ... also in tsconfig.app.json "compilerOptions": { "composite": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@Search/*": ["src/apps/Search/*"], ... --- ### Props * Wrap props with defineProps * no need to create a variable unless it's used in <script>...</script>, (any use in the <template /> is fine anyway and inferred from defineProps) * If a variable is needed we call it just 'props' for consistency * Vue.extend() is no longer used * object is flattened and `props: { ...` can be removed: Before: const SecondaryButtonProps = Vue.extend({ props: { disabled: Boolean, small: Boolean, icon: Boolean, ... }, }) After: defineProps({ disabled: Boolean, small: Boolean, icon: Boolean, ... }) --- ### Emits * `@Emit` decorators are not converted automatically. * Best guess is to defineEmits and then later use that emit. * I'm guessing the return isn't needed anymore, (but it doesn't hurt either) Before: @Emit() click(e: any) { return e } After: const emit = defineEmits(['click']) function click(e: any) { emit('click', e) } --- ### Watch and props * `$this` is no longer used. Instead use a props-variable for defineProps * callbacks are no longer looked up by name, just reference directly Before: watch(() => $this.value, 'onValueChanged') After: const props = defineProps({value: { ... }}); watch(() => props.value, onValueChanged) --- ### Vuetify themes: After conversion you might end up with: const $vuetify = inject('vuetify') ... return $vuetify.theme.dark Instead we use available hooks (theme.current seems to be correct?): import { useTheme } from 'vuetify'; const theme = useTheme(); ... return theme.current.value.dark