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


Filters are removed from the Vue 3 API completely.

What to use instead

Component’s computed properties / methods or external helpers.

Event hub


$on, $once, and $off methods are removed 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 library. It’s relatively small (200 bytes gzipped) and has a simple API:

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.

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>


In Vue 3, { functional: true } option is removed and <template functional> is no longer supported.

What to use instead

Functional components must be written as plain functions:

import { h } from 'vue'

const FunctionalComp = (props, slots) => {
  return h('div', `Hello! ${props.name}`)

Old slots syntax with slot attribute


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.

<!-- MyAwesomeComponent.vue -->
import SomeChildComponent from './some_child_component.vue'

export default {
  components: {


    <h1>Hello GitLab!</h1>
      <template #header>
        Header content
// MyAwesomeComponent.spec.js

import SomeChildComponent from '~/some_child_component.vue'

shallowMount(MyAwesomeComponent, {
  stubs: {