# Migration to Vue 3 In order to prepare for the eventual migration to Vue 3.x, we should be wary about adding the following features to the codebase: ## Vue filters **Why?** Filters [are removed](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md) from the Vue 3 API completely. **What to use instead** Component's computed properties / methods or external helpers. ## Event hub **Why?** `$on`, `$once`, and `$off` methods [are removed](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md) from the Vue instance, so in Vue 3 it can't be used to create an event hub. **What to use instead** Vue docs recommend using [mitt](https://github.com/developit/mitt) library. It's relatively small (200 bytes gzipped) and has a simple API: ```javascript import mitt from 'mitt' const emitter = mitt() // listen to an event emitter.on('foo', e => console.log('foo', e) ) // listen to all events emitter.on('*', (type, e) => console.log(type, e) ) // fire an event emitter.emit('foo', { a: 'b' }) // working with handler references: function onFoo() {} emitter.on('foo', onFoo) // listen emitter.off('foo', onFoo) // unlisten ``` **Event hub factory** To make it easier for you to migrate existing event hubs to the new recommended approach, or simply to create new ones, we have created a factory that you can use to instantiate a new mitt-based event hub. ```javascript import createEventHub from '~/helpers/event_hub_factory'; export default createEventHub(); ``` Event hubs created with the factory expose the same methods as Vue 2 event hubs (`$on`, `$once`, `$off` and `$emit`), making them backward compatible with our previous approach. ## \<template functional> **Why?** In Vue 3, `{ functional: true }` option [is removed](https://github.com/vuejs/rfcs/blob/functional-async-api-change/active-rfcs/0007-functional-async-api-change.md) and `<template functional>` is no longer supported. **What to use instead** Functional components must be written as plain functions: ```javascript import { h } from 'vue' const FunctionalComp = (props, slots) => { return h('div', `Hello! ${props.name}`) } ``` ## Old slots syntax with `slot` attribute **Why?** In Vue 2.6 `slot` attribute was already deprecated in favor of `v-slot` directive but its usage is still allowed and sometimes we prefer using them because it simplifies unit tests (with old syntax, slots are rendered on `shallowMount`). However, in Vue 3 we can't use old syntax anymore. **What to use instead** The syntax with `v-slot` directive. To fix rendering slots in `shallowMount`, we need to stub a child component with slots explicitly. ```html <!-- MyAwesomeComponent.vue --> <script> import SomeChildComponent from './some_child_component.vue' export default { components: { SomeChildComponent } } </script> <template> <div> <h1>Hello GitLab!</h1> <some-child-component> <template #header> Header content </template> </some-child-component> </div> </template> ``` ```javascript // MyAwesomeComponent.spec.js import SomeChildComponent from '~/some_child_component.vue' shallowMount(MyAwesomeComponent, { stubs: { SomeChildComponent } }) ```