For the most part, you should be able to keep writing components just like before. There are a few changes to be aware of. Most of these are covered by eslint.
General workflow
npm ci
to make sure you have the correct version of all of the packagesRun eslint (
npm run tui-style-check
), fix the issues.Run build tui, fix any issues the compiler complains about.
Test everything works in the browser, while keeping the console open to see any runtime warnings.
Breaking changes
You can see the full list of breaking changes in the Vue documentation, but some of the most impactful are summarised below.
Event handling (eslinted)
All component must now declare what events they emit, in an emits
array on the component. This is enforced by eslint.
The .native modifier no longer exists, instead any event listener that is not declared in the emits
will now also be attached as a native event handler to the root element of the component.
false
attribute values
In Vue 2, false
would remove the attribute. In Vue 3, false
sets the attribute to the string "false"
If you want to remove the attribute, use null
instead.
Whitespace
Handling of whitespace inside templates has changed a little compared to Vue 2. The changes are:
Whitespace characters between elements that contain newlines are removed.
Consecutive whitespace characters in text nodes are condensed into a single space.
Render functions, vnodes, and h()
This has changed a lot between versions. If you’re using render functions, vnodes, or h(), expect to rework your code.
:key (eslinted)
loops, if/else
v-bind object order
When using v-bind="someObject"
, individual props will now only take precedence if they come before the v-bind. More info
v-model and the input event (eslinted)
Plain v-model is no longer allowed, except on native HTML elements. Use v-model:value
instead.
Avoid using the input
event on components, prefer update:value
(or update:something
).
Slots (eslinted)
$scopedSlots no longer exists. Use $slots instead for all cases, it now behaves like $scopedSlots used to.
this.$el
If your component has multiple root elements, or only renders a slot as its sole content (i.e. a renderless component), this.$el
will point to an HTML comment instead of an actual element.
A workaround is to call extractSingleChild
from tui/vue/vnode
on the slot in the render function.
watch
Watchers on arrays no longer fire if an item is added or removed from the array. You must pass deep: true as a watch option.
Jest tests
Some things that may catch you out in Jest tests:
propsData
is now justprops
scopedSlots
is now justslots
mocks
andstubs
have now moved under theglobal
field onmount
/render
mockQueries
works on both, but it is preferrable to put it under theglobal
field to align withmocks
wrapper.emitted()
now includes native events. It is recommended to just ask for the event you are looking for with e.g.wrapper.emitted('submit')
Lifecycle methods
The
destroyed
lifecycle option has been renamed tounmounted
The
beforeDestroy
lifecycle option has been renamed tobeforeUnmount
Mutating props (eslinted)
This was deprecated in Vue 2 too, but is riskier in Vue 3. This will be automatically flagged by an eslint rule.
Instead of mutating the prop, copy it and change the copy. produce()
from tui/immutable
can help with this.
$children
Accessing child components via $children is no longer possible.
Vue namespaced methods
Vue.set
and Vue.delete
no longer exist -- they are no longer necessary with the proxy-based reactivity approach in Vue 3.
Other methods such as Vue.nextTick
are now just import { nextTick } from 'vue';
Mixins
Mixins should be avoided where possible, but there is a breaking change in Vue 3: data() on mixins is no longer merged with the component’s data().